# HG changeset patch # User unc0rr # Date 1241122424 0 # Node ID 7845c77c8d31c1994056f4f6d5a1cd25fa0f9b83 # Parent 73b0bcc4396da8c4b3ae7450e59df1c56d8d297f nemo's great patch: - Speech bubbles - Vampirism + karma diff -r 73b0bcc4396d -r 7845c77c8d31 QTfrontend/ammoSchemeModel.cpp --- a/QTfrontend/ammoSchemeModel.cpp Sun Apr 26 15:47:03 2009 +0000 +++ b/QTfrontend/ammoSchemeModel.cpp Thu Apr 30 20:13:44 2009 +0000 @@ -32,11 +32,13 @@ << QVariant(false) // laser sight 6 << QVariant(false) // invulnerable 7 << QVariant(true) // add mines 8 - << QVariant(100) // damage modfier 9 - << QVariant(45) // turn time 10 - << QVariant(100) // init health 11 - << QVariant(15) // sudden death 12 - << QVariant(5) // case prob 13 + << QVariant(false) // vampiric 9 + << QVariant(false) // karma 10 + << QVariant(100) // damage modfier 11 + << QVariant(45) // turn time 12 + << QVariant(100) // init health 13 + << QVariant(15) // sudden death 14 + << QVariant(5) // case prob 15 ; AmmoSchemeModel::AmmoSchemeModel(QObject* parent, const QString & fileName) : @@ -61,11 +63,13 @@ << "laser" // 6 << "invulnerability" // 7 << "mines" // 8 - << "damagefactor" // 9 - << "turntime" // 10 - << "health" // 11 - << "suddendeath" // 12 - << "caseprobability" // 13 + << "vampiric" // 9 + << "karma" // 10 + << "damagefactor" // 11 + << "turntime" // 12 + << "health" // 13 + << "suddendeath" // 14 + << "caseprobability" // 15 ; QList proMode; @@ -79,11 +83,13 @@ << QVariant(false) // laser sight 6 << QVariant(false) // invulnerable 7 << QVariant(false) // add mines 8 - << QVariant(100) // damage modfier 9 - << QVariant(15) // turn time 10 - << QVariant(100) // init health 11 - << QVariant(15) // sudden death 12 - << QVariant(0) // case prob 13 + << QVariant(false) // vampiric 9 + << QVariant(false) // karma 10 + << QVariant(100) // damage modfier 11 + << QVariant(15) // turn time 12 + << QVariant(100) // init health 13 + << QVariant(15) // sudden death 14 + << QVariant(0) // case prob 15 ; QList shoppa; @@ -97,11 +103,13 @@ << QVariant(false) // laser sight 6 << QVariant(false) // invulnerable 7 << QVariant(false) // add mines 8 - << QVariant(100) // damage modfier 9 - << QVariant(30) // turn time 10 - << QVariant(100) // init health 11 - << QVariant(50) // sudden death 12 - << QVariant(1) // case prob 13 + << QVariant(false) // vampiric 9 + << QVariant(false) // karma 10 + << QVariant(100) // damage modfier 11 + << QVariant(30) // turn time 12 + << QVariant(100) // init health 13 + << QVariant(50) // sudden death 14 + << QVariant(1) // case prob 15 ; QList basketball; @@ -115,11 +123,13 @@ << QVariant(false) // laser sight 6 << QVariant(true) // invulnerable 7 << QVariant(false) // add mines 8 - << QVariant(100) // damage modfier 9 - << QVariant(30) // turn time 10 - << QVariant(100) // init health 11 - << QVariant(15) // sudden death 12 - << QVariant(0) // case prob 13 + << QVariant(false) // vampiric 9 + << QVariant(false) // karma 10 + << QVariant(100) // damage modfier 11 + << QVariant(30) // turn time 12 + << QVariant(100) // init health 13 + << QVariant(15) // sudden death 14 + << QVariant(0) // case prob 15 ; schemes.append(defaultScheme); diff -r 73b0bcc4396d -r 7845c77c8d31 QTfrontend/gamecfgwidget.cpp --- a/QTfrontend/gamecfgwidget.cpp Sun Apr 26 15:47:03 2009 +0000 +++ b/QTfrontend/gamecfgwidget.cpp Thu Apr 30 20:13:44 2009 +0000 @@ -107,13 +107,17 @@ result |= 0x80; if (schemeData(8).toBool()) result |= 0x100; + if (schemeData(9).toBool()) + result |= 0x200; + if (schemeData(10).toBool()) + result |= 0x400; return result; } quint32 GameCFGWidget::getInitHealth() const { - return schemeData(11).toInt(); + return schemeData(13).toInt(); } QStringList GameCFGWidget::getFullConfig() const @@ -121,10 +125,10 @@ QStringList sl; sl.append("eseed " + pMapContainer->getCurrentSeed()); sl.append(QString("e$gmflags %1").arg(getGameFlags())); - sl.append(QString("e$damagepct %1").arg(schemeData(9).toInt())); - sl.append(QString("e$turntime %1").arg(schemeData(10).toInt() * 1000)); - sl.append(QString("e$sd_turns %1").arg(schemeData(12).toInt())); - sl.append(QString("e$casefreq %1").arg(schemeData(13).toInt())); + sl.append(QString("e$damagepct %1").arg(schemeData(11).toInt())); + sl.append(QString("e$turntime %1").arg(schemeData(12).toInt() * 1000)); + sl.append(QString("e$sd_turns %1").arg(schemeData(14).toInt())); + sl.append(QString("e$casefreq %1").arg(schemeData(15).toInt())); sl.append(QString("e$template_filter %1").arg(pMapContainer->getTemplateFilter())); QString currentMap = pMapContainer->getCurrentMap(); diff -r 73b0bcc4396d -r 7845c77c8d31 QTfrontend/hedgewars.qrc --- a/QTfrontend/hedgewars.qrc Sun Apr 26 15:47:03 2009 +0000 +++ b/QTfrontend/hedgewars.qrc Thu Apr 30 20:13:44 2009 +0000 @@ -53,6 +53,8 @@ res/btnMines.png res/btnTeamsDivide.png res/btnSolid.png + res/btnVampiric.png + res/btnKarma.png res/iconBox.png res/iconHealth.png res/iconSuddenDeath.png diff -r 73b0bcc4396d -r 7845c77c8d31 QTfrontend/hwconsts.cpp.in --- a/QTfrontend/hwconsts.cpp.in Sun Apr 26 15:47:03 2009 +0000 +++ b/QTfrontend/hwconsts.cpp.in Thu Apr 30 20:13:44 2009 +0000 @@ -29,14 +29,14 @@ QStringList * Themes; QStringList * mapList; -QString * cDefaultAmmoStore = new QString("939192942219912103223511100120100000"); +QString * cDefaultAmmoStore = new QString("9391929422199121032235111001201000001"); QList< QPair > cDefaultAmmos = QList< QPair >() << qMakePair(QString("Default"), *cDefaultAmmoStore) - << qMakePair(QString("Crazy"), QString("999999999999999999299999999999999929")) - << qMakePair(QString("Pro mode"), QString("909000900000000000000900000000000000")) - << qMakePair(QString("Shoppa"), QString("000000990000000000000000000000000000")) - << qMakePair(QString("Basketball"),QString("000000900000090000000000000000000000")) + << qMakePair(QString("Crazy"), QString("9999999999999999992999999999999999299")) + << qMakePair(QString("Pro mode"), QString("9090009000000000000009000000000000000")) + << qMakePair(QString("Shoppa"), QString("0000009900000000000000000000000000000")) + << qMakePair(QString("Basketball"),QString("0000009000000900000000000000000000000")) ; QColor * color1 = new QColor(221, 0, 0); diff -r 73b0bcc4396d -r 7845c77c8d31 QTfrontend/pages.cpp --- a/QTfrontend/pages.cpp Sun Apr 26 15:47:03 2009 +0000 +++ b/QTfrontend/pages.cpp Thu Apr 30 20:13:44 2009 +0000 @@ -916,6 +916,14 @@ TBW_mines->setText(ToggleButtonWidget::tr("Add Mines")); glGMLayout->addWidget(TBW_mines,1,3,1,1); + TBW_vampiric = new ToggleButtonWidget(gbGameModes, ":/res/btnVampiric.png"); + TBW_vampiric->setText(ToggleButtonWidget::tr("Vampirism")); + glGMLayout->addWidget(TBW_vampiric,2,0,1,1); + + TBW_karma = new ToggleButtonWidget(gbGameModes, ":/res/btnKarma.png"); + TBW_karma->setText(ToggleButtonWidget::tr("Karma")); + glGMLayout->addWidget(TBW_karma,2,1,1,1); + // Right QLabel * l; @@ -1031,11 +1039,13 @@ mapper->addMapping(TBW_laserSight->button(), 6); mapper->addMapping(TBW_invulnerable->button(), 7); mapper->addMapping(TBW_mines->button(), 8); - mapper->addMapping(SB_DamageModifier, 9); - mapper->addMapping(SB_TurnTime, 10); - mapper->addMapping(SB_InitHealth, 11); - mapper->addMapping(SB_SuddenDeath, 12); - mapper->addMapping(SB_CaseProb, 13); + mapper->addMapping(TBW_vampiric->button(), 9); + mapper->addMapping(TBW_karma->button(), 10); + mapper->addMapping(SB_DamageModifier, 11); + mapper->addMapping(SB_TurnTime, 12); + mapper->addMapping(SB_InitHealth, 13); + mapper->addMapping(SB_SuddenDeath, 14); + mapper->addMapping(SB_CaseProb, 15); mapper->toFirst(); } diff -r 73b0bcc4396d -r 7845c77c8d31 QTfrontend/pages.h --- a/QTfrontend/pages.h Sun Apr 26 15:47:03 2009 +0000 +++ b/QTfrontend/pages.h Thu Apr 30 20:13:44 2009 +0000 @@ -424,6 +424,8 @@ ToggleButtonWidget * TBW_laserSight; ToggleButtonWidget * TBW_invulnerable; ToggleButtonWidget * TBW_mines; + ToggleButtonWidget * TBW_vampiric; + ToggleButtonWidget * TBW_karma; QSpinBox * SB_DamageModifier; QSpinBox * SB_TurnTime; diff -r 73b0bcc4396d -r 7845c77c8d31 hedgewars/CCHandlers.inc --- a/hedgewars/CCHandlers.inc Sun Apr 26 15:47:03 2009 +0000 +++ b/hedgewars/CCHandlers.inc Thu Apr 30 20:13:44 2009 +0000 @@ -390,6 +390,35 @@ end end; +procedure chHogSay(var s: shortstring); +var Gear: PGear; + text: shortstring; +begin +text:= copy(s, 2, Length(s)-1); +if CheckNoTeamOrHH or ((CurrentHedgehog^.Gear^.State and gstHHDriven) = 0) then + begin + chSay(text); + exit + end; + +if not CurrentTeam^.ExtDriven then SendIPC('h' + s); +if byte(s[1]) < 4 then + begin + Gear:= AddGear(0, 0, gtSpeechBubble, 0, _0, _0, 0); + Gear^.Text:= text; + Gear^.Hedgehog:= CurrentHedgehog; + Gear^.State:= byte(s[1]); + end +else + begin + // If I knew how to add a gear without it becoming immediately active, I'd + // just create/attach the hedgehog SpeechGear here, then activate it where + // SpeechType/SpeechText are activated + SpeechType:= byte(s[1]); + SpeechText:= text + end; +end; + procedure chNewGrave; begin if CheckNoTeamOrHH then exit; diff -r 73b0bcc4396d -r 7845c77c8d31 hedgewars/GSHandlers.inc --- a/hedgewars/GSHandlers.inc Sun Apr 26 15:47:03 2009 +0000 +++ b/hedgewars/GSHandlers.inc Thu Apr 30 20:13:44 2009 +0000 @@ -67,8 +67,7 @@ PlaySound(sndOw1, false, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack); dmg:= modifyDamage(1 + hwRound((hwAbs(Gear^.dY) - _0_4) * 70)); - inc(Gear^.Damage, dmg); - AddDamageTag(hwRound(Gear^.X), hwRound(Gear^.Y) + cHHRadius, dmg, PHedgehog(Gear^.Hedgehog)^.Team^.Clan^.Color); + ApplyDamage(Gear, dmg); end end; @@ -255,7 +254,7 @@ if Gear^.Timer = 0 then begin - if Gear^.Kind = gtHealthTag then + if (Gear^.Kind = gtHealthTag) and (PHedgehog(Gear^.Hedgehog)^.Gear <> nil) then PHedgehog(Gear^.Hedgehog)^.Gear^.Active:= true; // to let current hh die DeleteGear(Gear) end @@ -288,6 +287,44 @@ Gear^.Y:= Gear^.Y - int2hwFloat(Gear^.Tex^.h) end; +procedure doStepSpeechBubbleWork(Gear: PGear); +begin +dec(Gear^.Timer); + +if (PHedgehog(Gear^.Hedgehog)^.Gear <> nil) then + begin + Gear^.X:= PHedgehog(Gear^.Hedgehog)^.Gear^.X+int2hwFloat(Gear^.Tex^.w div 2 - Gear^.State); + Gear^.Y:= PHedgehog(Gear^.Hedgehog)^.Gear^.Y-int2hwFloat(16+Gear^.Tex^.h); + end; + +if Gear^.Timer = 0 then + begin + CurrentHedgehog^.SpeechGear:= nil; + DeleteGear(Gear) + end; +end; + +procedure doStepSpeechBubble(Gear: PGear); +begin +if (CurrentHedgehog^.SpeechGear <> nil) then DeleteGear(CurrentHedgehog^.SpeechGear); +CurrentHedgehog^.SpeechGear:= Gear; + +Gear^.Timer:= max(Length(Gear^.Text)*150,3000); + +Gear^.Tex:= RenderSpeechBubbleTex(Gear^.Text, Gear^.State, fnt16); + +// Arbitrary offsets added to the widths based on shape of current tails +case Gear^.State of + 1: Gear^.State:= SpritesData[sprSpeechTail].Width-28; + 2: Gear^.State:= SpritesData[sprThoughtTail].Width-20; + 3: Gear^.State:= SpritesData[sprShoutTail].Width-10; + end; + +Gear^.doStep:= @doStepSpeechBubbleWork; + +Gear^.Y:= Gear^.Y - int2hwFloat(Gear^.Tex^.h) +end; + //////////////////////////////////////////////////////////////////////////////// procedure doStepGrave(Gear: PGear); begin diff -r 73b0bcc4396d -r 7845c77c8d31 hedgewars/HHHandlers.inc --- a/hedgewars/HHHandlers.inc Sun Apr 26 15:47:03 2009 +0000 +++ b/hedgewars/HHHandlers.inc Thu Apr 30 20:13:44 2009 +0000 @@ -100,6 +100,7 @@ procedure Attack(Gear: PGear); var xx, yy: hwFloat; + tmpGear: PGear; begin with Gear^, PHedgehog(Gear^.Hedgehog)^ do @@ -189,10 +190,20 @@ amInvulnerable: Invulnerable:= true; amExtraTime: TurnTimeLeft:= TurnTimeLeft + 30000; amLaserSight: cLaserSighting:= true; + amVampiric: cVampiric:= true; end; uStats.AmmoUsed(Ammo^[CurSlot, CurAmmo].AmmoType); + if not (SpeechText = '') then + begin + tmpGear:= AddGear(0, 0, gtSpeechBubble, 0, _0, _0, 0); + tmpGear^.Text:= SpeechText; + tmpGear^.Hedgehog:= CurrentHedgehog; + tmpGear^.State:= SpeechType; + SpeechText:= '' + end; + Power:= 0; if (CurAmmoGear <> nil) and (((Ammo^[CurSlot, CurAmmo].Propz) and ammoprop_AltUse) = 0){check for dropping ammo from rope} then @@ -386,6 +397,7 @@ or TestCollisionYwithGear(Gear, -1)) then Gear^.Y:= Gear^.Y - _1; end; + // ARTILLERY HERE if not TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then Gear^.X:= Gear^.X + SignAs(_1, Gear^.dX); SetAllHHToActive; @@ -504,6 +516,7 @@ if (Gear^.State and gstMoving) <> 0 then begin Gear^.State:= Gear^.State and not gstAnimation; +// ARTILLERY but not being moved by explosions Gear^.X:= Gear^.X + Gear^.dX; Gear^.Y:= Gear^.Y + Gear^.dY; if (not Gear^.dY.isNegative) and diff -r 73b0bcc4396d -r 7845c77c8d31 hedgewars/SDLh.pas --- a/hedgewars/SDLh.pas Sun Apr 26 15:47:03 2009 +0000 +++ b/hedgewars/SDLh.pas Thu Apr 30 20:13:44 2009 +0000 @@ -73,6 +73,7 @@ SDL_HWACCEL = $00000100; SDL_SRCCOLORKEY = $00001000; SDL_RLEACCEL = $00004000; + SDL_SRCALPHA = $00010000; SDL_NOEVENT = 0; SDL_ACTIVEEVENT = 1; @@ -247,6 +248,7 @@ function SDL_CreateRGBSurfaceFrom(pixels: Pointer; width, height, depth, pitch: LongInt; RMask, GMask, BMask, AMask: Longword): PSDL_Surface; cdecl; external SDLLibName; procedure SDL_FreeSurface(Surface: PSDL_Surface); cdecl; external SDLLibName; function SDL_SetColorKey(surface: PSDL_Surface; flag, key: Longword): LongInt; cdecl; external SDLLibName; +function SDL_SetAlpha(surface: PSDL_Surface; flag, key: Longword): LongInt; cdecl; external SDLLibName; function SDL_UpperBlit(src: PSDL_Surface; srcrect: PSDL_Rect; dst: PSDL_Surface; dstrect: PSDL_Rect): LongInt; cdecl; external SDLLibName; function SDL_FillRect(dst: PSDL_Surface; dstrect: PSDL_Rect; color: Longword): LongInt; cdecl; external SDLLibName; diff -r 73b0bcc4396d -r 7845c77c8d31 hedgewars/uAIAmmoTests.pas --- a/hedgewars/uAIAmmoTests.pas Sun Apr 26 15:47:03 2009 +0000 +++ b/hedgewars/uAIAmmoTests.pas Thu Apr 30 20:13:44 2009 +0000 @@ -73,14 +73,15 @@ (proc: nil; flags: 0), // amBanana (proc: nil; flags: 0), // amHellishBomb (proc: nil; flags: 0), // amNapalm - (proc: nil; flags: 0), // amDrill - (proc: nil; flags: 0), // amBallgun + (proc: nil; flags: 0), // amDrill + (proc: nil; flags: 0), // amBallgun (proc: nil; flags: 0), // amRCPlane (proc: nil; flags: 0), // amLowGravity (proc: nil; flags: 0), // amExtraDamage (proc: nil; flags: 0), // amInvulnerable (proc: nil; flags: 0), // amExtraTime - (proc: nil; flags: 0) // amLaserSight + (proc: nil; flags: 0), // amLaserSight + (proc: nil; flags: 0) // amVampiric ); const BadTurn = Low(LongInt) div 4; diff -r 73b0bcc4396d -r 7845c77c8d31 hedgewars/uAmmos.pas --- a/hedgewars/uAmmos.pas Sun Apr 26 15:47:03 2009 +0000 +++ b/hedgewars/uAmmos.pas Thu Apr 30 20:13:44 2009 +0000 @@ -61,12 +61,17 @@ var cnt: Longword; a: TAmmoType; ammos: TAmmoCounts; + substr: shortstring; // TEMPORARY begin TryDo(byte(s[0]) = byte(ord(High(TAmmoType)) + 1), 'Invalid ammo scheme (incompatible frontend)', true); // TEMPORARY hardcoded check on shoppa pending creation of probability editor -if (s = '000000990000009000000000000000000000') or (s = '000000990000000000000000000000000000') then +substr:= Copy(s,1,15); +if (substr = '000000990000009') or + (substr = '000000990000000') then shoppa:= true; +for a:= Low(TAmmoType) to High(TAmmoType) do + if (ord(a) > 14) and (s[ord(a)+1] <> '0') then shoppa:= false; // TEMPORARY etc - this just avoids updating every time new wep is added inc(StoreCnt); TryDo(StoreCnt <= cMaxHHs, 'Ammo stores overflow', true); @@ -82,7 +87,8 @@ end; if ((a = amLowGravity) and ((GameFlags and gfLowGravity) <> 0)) or ((a = amInvulnerable) and ((GameFlags and gfInvulnerable) <> 0)) or - ((a = amLaserSight) and ((GameFlags and gfLaserSight) <> 0)) then + ((a = amLaserSight) and ((GameFlags and gfLaserSight) <> 0)) or + ((a = amVampiric) and ((GameFlags and gfVampiric) <> 0)) then begin cnt:= 0; Ammoz[a].Probability:= 0 diff -r 73b0bcc4396d -r 7845c77c8d31 hedgewars/uChat.pas --- a/hedgewars/uChat.pas Sun Apr 26 15:47:03 2009 +0000 +++ b/hedgewars/uChat.pas Thu Apr 30 20:13:44 2009 +0000 @@ -132,6 +132,40 @@ procedure AcceptChatString(s: shortstring); var i: TWave; begin +// "Make hedgehog say something" +if (s[1] = '"') and (s[Length(s)] = '"') then + begin + ParseCommand('/hogsay '+#1+copy(s, 2, Length(s)-2), true); + exit + end; +// 'Make hedgehog think something' +if (s[1] = '''') and (s[Length(s)] = '''') then + begin + ParseCommand('/hogsay '+#2+copy(s, 2, Length(s)-2), true); + exit + end; +// -Make hedgehog yell something- +if (s[1] = '-') and (s[Length(s)] = '-') then + begin + ParseCommand('/hogsay '+#3+copy(s, 2, Length(s)-2), true); + exit + end; +// These 3 are same as above, only are to make the hedgehog say it on next attack +if (s[1] = '/') and (copy(s, 1, 5) = '/hsa ') then + begin + ParseCommand('/hogsay '+#4+copy(s, 6, Length(s)-5), true); + exit + end; +if (s[1] = '/') and (copy(s, 1, 5) = '/hta ') then + begin + ParseCommand('/hogsay '+#5+copy(s, 6, Length(s)-5), true); + exit + end; +if (s[1] = '/') and (copy(s, 1, 5) = '/hya ') then + begin + ParseCommand('/hogsay '+#6+copy(s, 6, Length(s)-5), true); + exit + end; if (s[1] = '/') and (copy(s, 1, 4) <> '/me ') then begin if CurrentTeam^.ExtDriven then exit; @@ -143,8 +177,11 @@ exit end; if (s = '/newgrave') then + begin ParseCommand('/newgrave', true); - end + exit + end; + end else ParseCommand('/say ' + s, true); end; diff -r 73b0bcc4396d -r 7845c77c8d31 hedgewars/uConsole.pas --- a/hedgewars/uConsole.pas Sun Apr 26 15:47:03 2009 +0000 +++ b/hedgewars/uConsole.pas Thu Apr 30 20:13:44 2009 +0000 @@ -262,6 +262,7 @@ RegisterVariable('chat' , vtCommand, @chChat , true ); RegisterVariable('newgrave', vtCommand, @chNewGrave , false); RegisterVariable('say' , vtCommand, @chSay , true ); +RegisterVariable('hogsay' , vtCommand, @chHogSay , true ); RegisterVariable('ammomenu', vtCommand, @chAmmoMenu , false); RegisterVariable('+precise', vtCommand, @chPrecise_p , false); RegisterVariable('-precise', vtCommand, @chPrecise_m , false); diff -r 73b0bcc4396d -r 7845c77c8d31 hedgewars/uConsts.pas --- a/hedgewars/uConsts.pas Sun Apr 26 15:47:03 2009 +0000 +++ b/hedgewars/uConsts.pas Thu Apr 30 20:13:44 2009 +0000 @@ -59,7 +59,10 @@ sprCakeWalk, sprCakeDown, sprAMAmmosBW, sprWatermelon, sprEvilTrace, sprHellishBomb, sprSeduction, sprDress, sprCensored, sprDrill, sprHandDrill, sprHandBallgun, sprBalls, - sprPlane, sprHandPlane, sprUtility, sprInvulnerable, sprGirder); + sprPlane, sprHandPlane, sprUtility, sprInvulnerable, sprVampiric, sprGirder, + sprSpeechCorner, sprSpeechEdge, sprSpeechTail, + sprThoughtCorner, sprThoughtEdge, sprThoughtTail, + sprShoutCorner, sprShoutEdge, sprShoutTail); TGearType = (gtAmmo_Bomb, gtHedgehog, gtAmmo_Grenade, gtHealthTag, // 3 gtGrave, gtUFO, gtShotgunShot, gtPickHammer, gtRope, // 8 @@ -69,7 +72,7 @@ gtParachute, gtAirAttack, gtAirBomb, gtBlowTorch, gtGirder, // 27 gtTeleport, gtSwitcher, gtTarget, gtMortar, // 31 gtWhip, gtKamikaze, gtCake, gtSeduction, gtWatermelon, gtMelonPiece, // 37 - gtHellishBomb, gtEvilTrace, gtWaterUp, gtDrill, gtBallGun, gtBall,gtRCPlane); + gtHellishBomb, gtEvilTrace, gtWaterUp, gtDrill, gtBallGun, gtBall,gtRCPlane, gtSpeechBubble); TVisualGearType = (vgtFlake, vgtCloud, vgtExplPart, vgtExplPart2, vgtFire, vgtSmallDamageTag, vgtTeamHealthSorter); @@ -93,7 +96,7 @@ amBaseballBat, amParachute, amAirAttack, amMineStrike, amBlowTorch, amGirder, amTeleport, amSwitch, amMortar, amKamikaze, amCake, amSeduction, amWatermelon, amHellishBomb, amNapalm, amDrill, amBallgun, - amRCPlane, amLowGravity, amExtraDamage, amInvulnerable, amExtraTime, amLaserSight); + amRCPlane, amLowGravity, amExtraDamage, amInvulnerable, amExtraTime, amLaserSight, amVampiric); THWFont = (fnt16, fntBig, fntSmall); @@ -203,6 +206,8 @@ gfLaserSight = $00000040; gfInvulnerable = $00000080; gfMines = $00000100; + gfVampiric = $00000200; + gfKarma = $00000400; gfOneClanMode = $10000000; gstDrowning = $00000001; @@ -497,8 +502,28 @@ Width: 48; Height: 48; saveSurf: false), // sprUtility (FileName:'Invulnerable';Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; Width: 48; Height: 48; saveSurf: false), // sprInvulnerable + (FileName:'Vampiric';Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; + Width: 48; Height: 48; saveSurf: false), // sprVampiric (FileName: 'amGirder'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 512; Height:512; saveSurf: false) // sprGirder + Width: 512; Height:512; saveSurf: false), // sprGirder + (FileName:'SpeechCorner';Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; + Width: 12; Height: 9; saveSurf: true), // sprSpeechCorner + (FileName:'SpeechEdge';Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; + Width: 25; Height: 9; saveSurf: true), // sprSpeechEdge + (FileName:'SpeechTail';Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; + Width: 25; Height: 26; saveSurf: true), // sprSpeechTail + (FileName:'ThoughtCorner';Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; + Width: 49; Height: 37; saveSurf: true), // sprThoughtCorner + (FileName:'ThoughtEdge';Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; + Width: 23; Height: 16; saveSurf: true), // sprThoughtEdge + (FileName:'ThoughtTail';Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; + Width: 45; Height: 65; saveSurf: true), // sprThoughtTail + (FileName:'ShoutCorner';Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; + Width: 34; Height: 23; saveSurf: true), // sprShoutCorner + (FileName:'ShoutEdge';Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; + Width: 30; Height: 20; saveSurf: true), // sprShoutEdge + (FileName:'ShoutTail';Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; + Width: 30; Height: 37; saveSurf: true) // sprShoutTail ); Wavez: array [TWave] of record @@ -1300,6 +1325,27 @@ isDamaging: false; SkipTurns: 0; PosCount: 1; + PosSprite: sprWater), + (NameId: sidVampiric; + NameTex: nil; + Probability: 15; + NumberInCase: 1; + Ammo: (Propz: ammoprop_NoCrosshair or + ammoprop_DontHold or + ammoprop_AltUse or + ammoprop_Utility; + Count: 1; + NumPerTurn: 0; + Timer: 0; + Pos: 0; + AmmoType: amVampiric); + Slot: 6; + TimeAfterTurn: 0; + minAngle: 0; + maxAngle: 0; + isDamaging: false; + SkipTurns: 0; + PosCount: 1; PosSprite: sprWater) ); diff -r 73b0bcc4396d -r 7845c77c8d31 hedgewars/uGears.pas --- a/hedgewars/uGears.pas Sun Apr 26 15:47:03 2009 +0000 +++ b/hedgewars/uGears.pas Thu Apr 30 20:13:44 2009 +0000 @@ -54,11 +54,13 @@ IntersectGear: PGear; TriggerId: Longword; uid: Longword; + Text: shortstring; end; function AddGear(X, Y: LongInt; Kind: TGearType; State: Longword; dX, dY: hwFloat; Timer: LongWord): PGear; procedure ProcessGears; procedure ResetUtilities; +procedure ApplyDamage(Gear: PGear; Damage: Longword); procedure SetAllToActive; procedure SetAllHHToActive; procedure DrawGears; @@ -71,6 +73,9 @@ var CurAmmoGear: PGear = nil; GearsList: PGear = nil; KilledHHs: Longword = 0; + SuddenDeathDmg: Boolean = false; + SpeechType: Longword = 1; + SpeechText: shortstring; implementation uses uWorld, uMisc, uStore, uConsole, uSound, uTeams, uRandom, uCollisions, @@ -157,7 +162,8 @@ @doStepDrill, @doStepBallgun, @doStepBomb, - @doStepRCPlane + @doStepRCPlane, + @doStepSpeechBubble ); procedure InsertGearToList(Gear: PGear); @@ -248,7 +254,10 @@ end; gtHealthTag: begin Result^.Timer:= 1500; - Result^.Z:= 2001; + Result^.Z:= 2002; + end; + gtSpeechBubble: begin + Result^.Z:= 2003; end; gtGrave: begin Result^.Radius:= 10; @@ -440,9 +449,6 @@ if (Gear^.Damage <> 0) and (not Gear^.Invulnerable) then begin - if (PHedgehog(Gear^.Hedgehog)^.Team = CurrentTeam) and - (Gear^.Damage <> int(cHealthDecrease)) then - Gear^.State:= Gear^.State or gstLoser; CheckNoDamage:= false; uStats.HedgehogDamaged(Gear); dmg:= Gear^.Damage; @@ -451,6 +457,10 @@ else dec(Gear^.Health, dmg); + if (PHedgehog(Gear^.Hedgehog)^.Team = CurrentTeam) and + not SuddenDeathDmg then + Gear^.State:= Gear^.State or gstLoser; + AddGear(hwRound(Gear^.X), hwRound(Gear^.Y) - cHHRadius - 12, gtHealthTag, dmg, _0, _0, 0)^.Hedgehog:= Gear^.Hedgehog; @@ -462,6 +472,7 @@ end; Gear:= Gear^.NextGear end; +SuddenDeathDmg:= false; end; procedure HealthMachine; @@ -562,6 +573,7 @@ else begin bBetweenTurns:= true; HealthMachine; + SuddenDeathDmg:= true; step:= stChDmg end end; @@ -612,9 +624,14 @@ procedure ResetUtilities; var i: LongInt; begin + SpeechText:= ''; // in case it hasn't been consumed + if (GameFlags and gfLowGravity) = 0 then cGravity:= cMaxWindSpeed; + if (GameFlags and gfVampiric) = 0 then + cVampiric:= false; + cDamageModifier:= _1; if (GameFlags and gfLaserSight) = 0 then @@ -629,6 +646,50 @@ if (Gear <> nil) then Gear^.Invulnerable:= false; end; +procedure ApplyDamage(Gear: PGear; Damage: Longword); +var s: shortstring; + vampDmg: Longword; +begin + inc(Gear^.Damage, Damage); + if Gear^.Kind = gtHedgehog then + begin + AddDamageTag(hwRound(Gear^.X), hwRound(Gear^.Y), Damage, PHedgehog(Gear^.Hedgehog)^.Team^.Clan^.Color); + Damage:= min(Damage, Gear^.Health); + if (Gear <> CurrentHedgehog^.Gear) and (CurrentHedgehog^.Gear <> nil) and (Damage >= 1) then + begin + if cVampiric then + begin + vampDmg:= hwRound(int2hwFloat(Damage)*_0_8); + // was considering pulsing on attack, Tiy thinks it should be permanent while in play + //CurrentHedgehog^.Gear^.State:= CurrentHedgehog^.Gear^.State or gstVampiric; + inc(CurrentHedgehog^.Gear^.Health,vampDmg); + str(vampDmg, s); + s:= '+' + s; + AddCaption(s, CurrentHedgehog^.Team^.Clan^.Color, capgrpAmmoinfo); + RenderHealth(CurrentHedgehog^); + RecountTeamHealth(CurrentHedgehog^.Team); + end; + if ((GameFlags and gfKarma) <> 0) and + ((GameFlags and gfInvulnerable) = 0) and + not CurrentHedgehog^.Gear^.Invulnerable then + begin // this cannot just use Damage or it interrupts shotgun and gets you called stupid + if CurrentHedgehog^.Gear^.Health < int(Damage) then + begin + // Add damage to trigger normal resolution + CurrentHedgehog^.Gear^.Health := 0; + inc(CurrentHedgehog^.Gear^.Damage); + end + else + dec(CurrentHedgehog^.Gear^.Health, Damage); + AddGear(hwRound(Gear^.X), + hwRound(Gear^.Y), + gtHealthTag, Damage, _0, _0, 0)^.Hedgehog:= CurrentHedgehog; + RenderHealth(CurrentHedgehog^); + RecountTeamHealth(CurrentHedgehog^.Team); + end; + end; + end; +end; procedure SetAllToActive; var t: PGear; @@ -841,6 +902,7 @@ 1, 1, 0); + HatVisible:= true; defaultPos:= false end else @@ -950,7 +1012,10 @@ end else // not gstHHDriven begin if (Gear^.Damage > 0) - and (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > _0_003) then + and (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > _0_003) +// ARTILLERY +//and (1=0) +then begin DrawHedgehog(sx, sy, hwSign(Gear^.dX), @@ -1123,9 +1188,15 @@ end; if Gear^.Invulnerable then - begin - DrawSprite(sprInvulnerable, sx - 24, sy - 24, 0); - end; + begin + DrawSprite(sprInvulnerable, sx - 24, sy - 24, 0); + end; +if cVampiric and + (CurrentHedgehog^.Gear <> nil) and + (CurrentHedgehog^.Gear = Gear) then + begin + DrawSprite(sprVampiric, sx - 24, sy - 24, 0); + end; end; procedure DrawGears; @@ -1216,6 +1287,8 @@ gtAmmo_Grenade: DrawRotated(sprGrenade, hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, 0, DxDy2Angle(Gear^.dY, Gear^.dX)); gtHealthTag: if Gear^.Tex <> nil then DrawCentered(hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, Gear^.Tex); + + gtSpeechBubble: if Gear^.Tex <> nil then DrawCentered(hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, Gear^.Tex); gtGrave: DrawSurfSprite(hwRound(Gear^.X) + WorldDx - 16, hwRound(Gear^.Y) + WorldDy - 16, 32, (GameTicks shr 7) and 7, PHedgehog(Gear^.Hedgehog)^.Team^.GraveTex); @@ -1328,6 +1401,9 @@ if (GameFlags and gfLowGravity) <> 0 then cGravity:= cMaxWindSpeed / 2; +if (GameFlags and gfVampiric) <> 0 then + cVampiric:= true; + Gear:= GearsList; if (GameFlags and gfInvulnerable) <> 0 then while Gear <> nil do @@ -1372,11 +1448,7 @@ if (Mask and EXPLNoDamage) = 0 then begin if not Gear^.Invulnerable then - begin - inc(Gear^.Damage, dmg); - if Gear^.Kind = gtHedgehog then - AddDamageTag(hwRound(Gear^.X), hwRound(Gear^.Y), dmg, PHedgehog(Gear^.Hedgehog)^.Team^.Clan^.Color); - end + ApplyDamage(Gear, dmg) else Gear^.State:= Gear^.State or gstWinner; end; @@ -1423,11 +1495,7 @@ gtCase, gtTarget: begin if (not t^.Invulnerable) then - begin - inc(t^.Damage, dmg); - if t^.Kind = gtHedgehog then - AddDamageTag(hwRound(Gear^.X), hwRound(Gear^.Y), dmg, PHedgehog(t^.Hedgehog)^.Team^.Clan^.Color); - end + ApplyDamage(t, dmg) else Gear^.State:= Gear^.State or gstWinner; @@ -1468,12 +1536,7 @@ gtCase: begin if (Ammo^.Kind = gtDrill) then begin Ammo^.Timer:= 0; exit; end; if (not t^.ar[i]^.Invulnerable) then - begin - inc(t^.ar[i]^.Damage, Damage); - - if (t^.ar[i]^.Kind = gtHedgehog) and (Damage > 0) then - AddDamageTag(hwRound(t^.ar[i]^.X), hwRound(t^.ar[i]^.Y), Damage, PHedgehog(t^.ar[i]^.Hedgehog)^.Team^.Clan^.Color); - end + ApplyDamage(t^.ar[i], Damage) else t^.ar[i]^.State:= t^.ar[i]^.State or gstWinner; @@ -1587,7 +1650,7 @@ if (t^.Kind = gtHedgehog) and (t^.Y < Ammo^.Y) then if not (hwSqr(Ammo^.X - t^.X) + hwSqr(Ammo^.Y - t^.Y - int2hwFloat(cHHRadius)) * 2 > _2) then begin - inc(t^.Damage, 5); + ApplyDamage(t, 5); t^.dX:= t^.dX + (t^.X - Ammo^.X) * _0_02; t^.dY:= - _0_25; t^.Active:= true; @@ -1638,8 +1701,7 @@ FollowGear:= nil; -t:= getrandom(20); // TEMPORARY REMOVE WHEN CRATE PROBABILITY IS ADDED -if shoppa then +if shoppa then // TEMPORARY REMOVE WHEN CRATE PROBABILITY IS ADDED t:= 7 else t:= getrandom(20); diff -r 73b0bcc4396d -r 7845c77c8d31 hedgewars/uIO.pas --- a/hedgewars/uIO.pas Sun Apr 26 15:47:03 2009 +0000 +++ b/hedgewars/uIO.pas Thu Apr 30 20:13:44 2009 +0000 @@ -293,6 +293,7 @@ 'w': ParseCommand('setweap ' + headcmd^.str[2], true); 't': ParseCommand('taunt ' + headcmd^.str[2], true); 'g': ParseCommand('newgrave', true); + 'h': ParseCommand('hogsay ' + copy(headcmd^.str, 2, Pred(headcmd^.len)), true); '1'..'5': ParseCommand('timer ' + headcmd^.cmd, true); #128..char(128 + cMaxSlotIndex): ParseCommand('slot ' + char(byte(headcmd^.cmd) - 79), true) else diff -r 73b0bcc4396d -r 7845c77c8d31 hedgewars/uLocale.pas --- a/hedgewars/uLocale.pas Sun Apr 26 15:47:03 2009 +0000 +++ b/hedgewars/uLocale.pas Thu Apr 30 20:13:44 2009 +0000 @@ -25,7 +25,7 @@ sidGirder, sidTeleport, sidSwitch, sidMortar, sidWhip, sidKamikaze, sidCake, sidSeduction, sidWatermelon, sidHellishBomb, sidDrill, sidBallgun, sidNapalm, sidRCPlane, - sidLowGravity, sidExtraDamage, sidInvulnerable, sidExtraTime, sidLaserSight); + sidLowGravity, sidExtraDamage, sidInvulnerable, sidExtraTime, sidLaserSight, sidVampiric); TMsgStrId = (sidStartFight, sidDraw, sidWinner, sidVolume, sidPaused, sidConfirm, sidSuddenDeath); diff -r 73b0bcc4396d -r 7845c77c8d31 hedgewars/uMisc.pas --- a/hedgewars/uMisc.pas Sun Apr 26 15:47:03 2009 +0000 +++ b/hedgewars/uMisc.pas Thu Apr 30 20:13:44 2009 +0000 @@ -105,6 +105,7 @@ cGravity: hwFloat; cDamageModifier: hwFloat; cLaserSighting: boolean; + cVampiric: boolean; flagMakeCapture: boolean = false; @@ -382,7 +383,7 @@ for x:= Surf^.w to Pred(tw) do toP4^[x]:= 0; toP4:= @(toP4^[tw]); - fromP4:= @(fromP4^[Surf^.w]); + fromP4:= @(fromP4^[Surf^.pitch div 4]); end; for y:= Surf^.h to Pred(th) do @@ -548,6 +549,7 @@ cGravity:= cMaxWindSpeed; cDamageModifier:= _1; cLaserSighting:= false; +cVampiric:= false; {$IFDEF DEBUGFILE} {$I-} diff -r 73b0bcc4396d -r 7845c77c8d31 hedgewars/uStore.pas --- a/hedgewars/uStore.pas Sun Apr 26 15:47:03 2009 +0000 +++ b/hedgewars/uStore.pas Thu Apr 30 20:13:44 2009 +0000 @@ -18,7 +18,7 @@ unit uStore; interface -uses uConsts, uTeams, SDLh, +uses sysutils, uConsts, uTeams, SDLh, {$IFDEF IPHONE} gles11, {$ELSE} @@ -45,6 +45,11 @@ procedure DrawHedgehog(X, Y: LongInt; Dir: LongInt; Pos, Step: LongWord; Angle: real); procedure DrawFillRect(r: TSDL_Rect); function RenderStringTex(s: string; Color: Longword; font: THWFont): PTexture; +function RenderSpeechBubbleTex(s: string; SpeechType: Longword; font: THWFont): PTexture; +procedure flipSurface(Surface: PSDL_Surface; Vertical: Boolean); +//procedure rotateSurface(Surface: PSDL_Surface); +procedure copyRotatedSurface(src, dest: PSDL_Surface); // this is necessary since width/height are read only in SDL +procedure copyToXY(src, dest: PSDL_Surface; destX, destY: Integer); procedure RenderHealth(var Hedgehog: THedgehog); procedure AddProgress; procedure FinishProgress; @@ -672,6 +677,176 @@ SDL_FreeSurface(Result) end; +function RenderSpeechBubbleTex(s: string; SpeechType: Longword; font: THWFont): PTexture; +var textWidth, textHeight, x, y, w, h, i, pos, prevpos, line, numLines, edgeWidth, edgeHeight, cornerWidth, cornerHeight: LongInt; + Result, tmpsurf, rotatedEdge: PSDL_Surface; + rect: TSDL_Rect; + chars: TSysCharSet = [#9,' ','.',';',':','?','!',',']; + substr: shortstring; + edge, corner, tail: TSPrite; +begin + +case SpeechType of + 1: begin; + edge:= sprSpeechEdge; + corner:= sprSpeechCorner; + tail:= sprSpeechTail; + end; + 2: begin; + edge:= sprThoughtEdge; + corner:= sprThoughtCorner; + tail:= sprThoughtTail; + end; + 3: begin; + edge:= sprShoutEdge; + corner:= sprShoutCorner; + tail:= sprShoutTail; + end; + end; +edgeHeight:= SpritesData[edge].Height; +edgeWidth:= SpritesData[edge].Width; +cornerWidth:= SpritesData[corner].Width; +cornerHeight:= SpritesData[corner].Height; +// This one screws it up +s:= 'This is the song that never ends. ''cause it goes on and on my friends. Some people, started singing it not knowing what it was. And they''ll just go on singing it forever just because... This is the song that never ends...'; +// This one doesn't +//s:= 'This is the song that never ends. cause it goes on and on my friends. Some people, started singing it not knowing what it was. And theyll just go on singing it forever just because... This is the song that never ends... '; +// Also screws up, but only action +//s:= 'This is the song that never ends. cause it goes on and on .'; +// ok in all +// s:= 'This is the song that never ends. cause it goes on .'; +numLines:= 1; + +if length(s) = 0 then s:= '...'; + +TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(s), w, h); +textWidth:= w; +textHeight:= h; +if (length(s) > 20) then + begin + i:= round(Sqrt(length(s)) * 2); + s:= WrapText(s, #1, chars, i); + for pos:= 1 to length(s) do + if (s[pos] = #1) or (pos = length(s)) then + inc(numLines); + + // TODO - find out why this calc doesn't do what I expect + if numLines = 2 then textWidth:= w div 2 + else if numlines > 2 then textWidth:= w div (numLines-1); + end; + +textWidth:=((textWidth-(cornerWidth-edgeWidth)*2) div edgeWidth)*edgeWidth+edgeWidth; +textHeight:=(((numlines * h)-((cornerHeight-edgeWidth)*2)) div edgeWidth)*edgeWidth+edgeWidth; +addfilelog(inttostr(textHeight)+'=========== '+inttostr(numlines)+' x '+inttostr(h)); +//textWidth:=max(textWidth,SpritesData[tail].Width); +rect.x:= 0; +rect.y:= 0; +rect.w:= textWidth + cornerWidth * 2; +rect.h:= textHeight + cornerHeight * 2 - edgeHeight + SpritesData[tail].Height; +//s:= inttostr(h) + ' ' + inttostr(numlines) + ' ' + inttostr(rect.x) + ' '+inttostr(rect.y) + ' ' + inttostr(rect.w) + ' ' + inttostr(rect.h) + ' ' + s; + +Result:= SDL_CreateRGBSurface(SDL_SWSURFACE, rect.w, rect.h, 32, RMask, GMask, BMask, AMask); + +TryDo(Result <> nil, 'RenderString: fail to create surface', true); + +//////////////////////////////// CORNERS /////////////////////////////// +copyToXY(SpritesData[corner].Surface, Result, 0, 0); /////////////////// NW + +flipSurface(SpritesData[corner].Surface, true); // store all 4 versions in memory to avoid repeated flips? +x:= 0; +y:= textHeight + cornerHeight -1; +copyToXY(SpritesData[corner].Surface, Result, x, y); /////////////////// SW + +flipSurface(SpritesData[corner].Surface, false); +x:= rect.w-cornerWidth-1; +y:= textHeight + cornerHeight -1; +copyToXY(SpritesData[corner].Surface, Result, x, y); /////////////////// SE + +flipSurface(SpritesData[corner].Surface, true); +x:= rect.w-cornerWidth-1; +y:= 0; +copyToXY(SpritesData[corner].Surface, Result, x, y); /////////////////// NE +flipSurface(SpritesData[corner].Surface, false); // restore original position +//////////////////////////////// END CORNERS /////////////////////////////// + +//////////////////////////////// EDGES ////////////////////////////////////// +x:= cornerWidth; +y:= 0; +while x < rect.w-cornerWidth-1 do + begin + copyToXY(SpritesData[edge].Surface, Result, x, y); ///////////////// top edge + inc(x,edgeWidth); + end; +flipSurface(SpritesData[edge].Surface, true); +x:= cornerWidth; +y:= textHeight + cornerHeight*2 - edgeHeight-1; +while x < rect.w-cornerWidth-1 do + begin + copyToXY(SpritesData[edge].Surface, Result, x, y); ///////////////// bottom edge + inc(x,edgeWidth); + end; +flipSurface(SpritesData[edge].Surface, true); // restore original position + +rotatedEdge:= SDL_CreateRGBSurface(SDL_SWSURFACE, edgeHeight, edgeWidth, 32, RMask, GMask, BMask, AMask); +x:= rect.w - edgeHeight - 1; +y:= cornerHeight; +//// initially was going to rotate in place, but the SDL spec claims width/height are read only +copyRotatedSurface(SpritesData[edge].Surface,rotatedEdge); +while y < textHeight + cornerHeight do + begin + copyToXY(rotatedEdge, Result, x, y); + inc(y,edgeWidth); + end; +flipSurface(rotatedEdge, false); // restore original position +x:= 0; +y:= cornerHeight; +while y < textHeight + cornerHeight do + begin + copyToXY(rotatedEdge, Result, x, y); + inc(y,edgeWidth); + end; +//////////////////////////////// END EDGES ////////////////////////////////////// + +x:= cornerWidth; +y:= textHeight + cornerHeight * 2 - edgeHeight - 1; +copyToXY(SpritesData[tail].Surface, Result, x, y); + +rect.x:= edgeHeight; +rect.y:= edgeHeight; +rect.w:= rect.w - edgeHeight * 2; +rect.h:= textHeight + cornerHeight * 2 - edgeHeight * 2; +SDL_FillRect(Result, @rect, cWhiteColor); + +pos:= 1; prevpos:= 0; line:= 0; +while pos <= length(s) do + begin + if (s[pos] = #1) or (pos = length(s)) then + begin + if s[pos] <> #1 then inc(pos); + while s[prevpos+1] = ' 'do inc(prevpos); + substr:= copy(s, prevpos+1, pos-prevpos-1); + if Length(substr) <> 0 then + begin + tmpsurf:= TTF_RenderUTF8_Blended(Fontz[Font].Handle, Str2PChar(substr), cColorNearBlack); + rect.x:= edgeHeight; + rect.y:= edgeHeight + line * h; + SDLTry(tmpsurf <> nil, true); + SDL_UpperBlit(tmpsurf, nil, Result, @rect); + SDL_FreeSurface(tmpsurf); + inc(line); + prevpos:= pos; + end; + end; + inc(pos); + end; + +//TryDo(SDL_SetColorKey(Result, SDL_SRCCOLORKEY, 0) = 0, errmsgTransparentSet, true); +RenderSpeechBubbleTex:= Surface2Tex(Result); + +SDL_FreeSurface(rotatedEdge); +SDL_FreeSurface(Result) +end; + procedure RenderHealth(var Hedgehog: THedgehog); var s: shortstring; begin @@ -755,4 +930,73 @@ FreeTexture(ProgrTex) end; +procedure flipSurface(Surface: PSDL_Surface; Vertical: Boolean); +var y, x, i, j: LongInt; + tmpPixel: Longword; + pixels: PLongWordArray; +begin +TryDo(Surface^.format^.BytesPerPixel = 4, 'flipSurface failed, expecting 32 bit surface', true); +pixels:= Surface^.pixels; +if Vertical then + for y := 0 to (Surface^.h div 2) - 1 do + for x := 0 to Surface^.w - 1 do + begin + i:= y * Surface^.w + x; + j:= (Surface^.h - y - 1) * Surface^.w + x; + tmpPixel:= pixels^[i]; + pixels^[i]:= pixels^[j]; + pixels^[j]:= tmpPixel; + end +else + for x := 0 to (Surface^.w div 2) - 1 do + for y := 0 to Surface^.h -1 do + begin + i:= y*Surface^.w + x; + j:= y*Surface^.w + (Surface^.w - x - 1); + tmpPixel:= pixels^[i]; + pixels^[i]:= pixels^[j]; + pixels^[j]:= tmpPixel; + end; +end; + +procedure copyToXY(src, dest: PSDL_Surface; destX, destY: Integer); +var srcX, srcY, i, j, maxDest: LongInt; + srcPixels, destPixels: PLongWordArray; +begin +addfilelog('copyToXY: src surf (w, h) = ('+inttostr(src^.w)+', '+inttostr(src^.h)+')'); +addfilelog('copyToXY: dest(X, Y) = ('+inttostr(destX)+', '+inttostr(destY)+')'); +maxDest:= (dest^.pitch div 4) * dest^.h; +srcPixels:= src^.pixels; +destPixels:= dest^.pixels; + +for srcX:= 0 to src^.w - 1 do + for srcY:= 0 to src^.h - 1 do + begin + i:= (destY + srcY) * (dest^.pitch div 4) + destX + srcX; + j:= srcY * (src^.pitch div 4) + srcX; + // basic skip of transparent pixels - cleverness would be to do true alpha + if (i < maxDest) and ($FF000000 and srcPixels^[j] <> 0) then destPixels^[i]:= srcPixels^[j]; + end; +end; + +procedure copyRotatedSurface(src, dest: PSDL_Surface); // this is necessary since width/height are read only in SDL, apparently +var y, x, i, j: LongInt; + srcPixels, destPixels: PLongWordArray; +begin +TryDo(src^.format^.BytesPerPixel = 4, 'rotateSurface failed, expecting 32 bit surface', true); +TryDo(dest^.format^.BytesPerPixel = 4, 'rotateSurface failed, expecting 32 bit surface', true); + +srcPixels:= src^.pixels; +destPixels:= dest^.pixels; + +j:= 0; +for x := 0 to src^.w - 1 do + for y := 0 to src^.h - 1 do + begin + i:= (src^.h - 1 - y) * (src^.pitch div 4) + x; + destPixels^[j]:= srcPixels^[i]; + inc(j) + end; +end; + end. diff -r 73b0bcc4396d -r 7845c77c8d31 hedgewars/uTeams.pas --- a/hedgewars/uTeams.pas Sun Apr 26 15:47:03 2009 +0000 +++ b/hedgewars/uTeams.pas Thu Apr 30 20:13:44 2009 +0000 @@ -37,6 +37,7 @@ THedgehog = record Name: string[MAXNAMELEN]; Gear: PGear; + SpeechGear: PGear; NameTagTex, HealthTagTex, HatTex: PTexture; diff -r 73b0bcc4396d -r 7845c77c8d31 share/hedgewars/Data/Locale/bg.txt --- a/share/hedgewars/Data/Locale/bg.txt Sun Apr 26 15:47:03 2009 +0000 +++ b/share/hedgewars/Data/Locale/bg.txt Thu Apr 30 20:13:44 2009 +0000 @@ -37,6 +37,7 @@ 00:34=Invulnerable 00:35=Extra Time 00:36=Laser Sight +00:37=Vampirism 01:00=Бой! 01:01=Равен рунд diff -r 73b0bcc4396d -r 7845c77c8d31 share/hedgewars/Data/Locale/cs.txt --- a/share/hedgewars/Data/Locale/cs.txt Sun Apr 26 15:47:03 2009 +0000 +++ b/share/hedgewars/Data/Locale/cs.txt Thu Apr 30 20:13:44 2009 +0000 @@ -37,6 +37,7 @@ 00:34=Invulnerable 00:35=Extra Time 00:36=Laser Sight +00:37=Vampirism 01:00=Do boje! 01:01=Kolo nerozhodně diff -r 73b0bcc4396d -r 7845c77c8d31 share/hedgewars/Data/Locale/de.txt --- a/share/hedgewars/Data/Locale/de.txt Sun Apr 26 15:47:03 2009 +0000 +++ b/share/hedgewars/Data/Locale/de.txt Thu Apr 30 20:13:44 2009 +0000 @@ -37,6 +37,7 @@ 00:34=Unverwundbarkeit 00:35=Zusatzzeit 00:36=Laservisier +00:37=Vampirism 01:00=Auf in die Schlacht! 01:01=Unentschieden diff -r 73b0bcc4396d -r 7845c77c8d31 share/hedgewars/Data/Locale/en.txt --- a/share/hedgewars/Data/Locale/en.txt Sun Apr 26 15:47:03 2009 +0000 +++ b/share/hedgewars/Data/Locale/en.txt Thu Apr 30 20:13:44 2009 +0000 @@ -37,6 +37,7 @@ 00:34=Invulnerable 00:35=Extra Time 00:36=Laser Sight +00:37=Vampirism 01:00=Let's fight! 01:01=Round draw diff -r 73b0bcc4396d -r 7845c77c8d31 share/hedgewars/Data/Locale/es.txt --- a/share/hedgewars/Data/Locale/es.txt Sun Apr 26 15:47:03 2009 +0000 +++ b/share/hedgewars/Data/Locale/es.txt Thu Apr 30 20:13:44 2009 +0000 @@ -37,6 +37,7 @@ 00:34=Invulnerable 00:35=Tiempo extra 00:36=Mira láser +00:37=Vampirism 01:00=Luchad! 01:01=Empate diff -r 73b0bcc4396d -r 7845c77c8d31 share/hedgewars/Data/Locale/fi.txt --- a/share/hedgewars/Data/Locale/fi.txt Sun Apr 26 15:47:03 2009 +0000 +++ b/share/hedgewars/Data/Locale/fi.txt Thu Apr 30 20:13:44 2009 +0000 @@ -37,6 +37,7 @@ 00:34=Invulnerable 00:35=Extra Time 00:36=Laser Sight +00:37=Vampirism 01:00=Taistelu alkakoon! 01:01=Tasapeli diff -r 73b0bcc4396d -r 7845c77c8d31 share/hedgewars/Data/Locale/fr.txt --- a/share/hedgewars/Data/Locale/fr.txt Sun Apr 26 15:47:03 2009 +0000 +++ b/share/hedgewars/Data/Locale/fr.txt Thu Apr 30 20:13:44 2009 +0000 @@ -37,6 +37,7 @@ 00:34=Invulnérable 00:35=Extra Time 00:36=Laser Sight +00:37=Vampirism 01:00=C'est parti! 01:01=Round ex aequo diff -r 73b0bcc4396d -r 7845c77c8d31 share/hedgewars/Data/Locale/it.txt --- a/share/hedgewars/Data/Locale/it.txt Sun Apr 26 15:47:03 2009 +0000 +++ b/share/hedgewars/Data/Locale/it.txt Thu Apr 30 20:13:44 2009 +0000 @@ -37,6 +37,7 @@ 00:34=Invulnerabilità 00:35=Tempo Extra 00:36=Mirino Laser +00:37=Vampirism 01:00=Combattiamo! 01:01=Round in parità diff -r 73b0bcc4396d -r 7845c77c8d31 share/hedgewars/Data/Locale/pl.txt --- a/share/hedgewars/Data/Locale/pl.txt Sun Apr 26 15:47:03 2009 +0000 +++ b/share/hedgewars/Data/Locale/pl.txt Thu Apr 30 20:13:44 2009 +0000 @@ -37,6 +37,7 @@ 00:34=Niezniszczalność 00:35=Dodatkowy czas 00:36=Celownik laserowy +00:37=Vampirism 01:00=Walczmy! 01:01=Remis diff -r 73b0bcc4396d -r 7845c77c8d31 share/hedgewars/Data/Locale/pt-br.txt --- a/share/hedgewars/Data/Locale/pt-br.txt Sun Apr 26 15:47:03 2009 +0000 +++ b/share/hedgewars/Data/Locale/pt-br.txt Thu Apr 30 20:13:44 2009 +0000 @@ -37,6 +37,7 @@ 00:34=Invulnerable 00:35=Extra Time 00:36=Laser Sight +00:37=Vampirism 01:00=Hora de lutar! 01:01=Partida empatou diff -r 73b0bcc4396d -r 7845c77c8d31 share/hedgewars/Data/Locale/ru.txt --- a/share/hedgewars/Data/Locale/ru.txt Sun Apr 26 15:47:03 2009 +0000 +++ b/share/hedgewars/Data/Locale/ru.txt Thu Apr 30 20:13:44 2009 +0000 @@ -37,6 +37,7 @@ 00:34=Неуязвимость 00:35=30 секунд 00:36=Лазерный прицел +00:37=Vampirism 01:00=Вперёд к победе! 01:01=Ничья diff -r 73b0bcc4396d -r 7845c77c8d31 share/hedgewars/Data/Locale/sk.txt --- a/share/hedgewars/Data/Locale/sk.txt Sun Apr 26 15:47:03 2009 +0000 +++ b/share/hedgewars/Data/Locale/sk.txt Thu Apr 30 20:13:44 2009 +0000 @@ -37,6 +37,7 @@ 00:34=Nesmrteľnosť 00:35=Extra čas 00:36=Laserové zameriavanie +00:37=Vampirism 01:00=Do boja! 01:01=Remíza diff -r 73b0bcc4396d -r 7845c77c8d31 share/hedgewars/Data/Locale/tr.txt --- a/share/hedgewars/Data/Locale/tr.txt Sun Apr 26 15:47:03 2009 +0000 +++ b/share/hedgewars/Data/Locale/tr.txt Thu Apr 30 20:13:44 2009 +0000 @@ -37,6 +37,7 @@ 00:34=Ölümsüzlük 00:35=Arttırılmış Zaman 00:36=Lazer Görüşü +00:37=Vampirism 01:00=Savaş başlasın! 01:01=Beraberlik diff -r 73b0bcc4396d -r 7845c77c8d31 share/hedgewars/Data/Locale/uk.txt --- a/share/hedgewars/Data/Locale/uk.txt Sun Apr 26 15:47:03 2009 +0000 +++ b/share/hedgewars/Data/Locale/uk.txt Thu Apr 30 20:13:44 2009 +0000 @@ -37,6 +37,7 @@ 00:34=Invulnerable 00:35=Extra Time 00:36=Laser Sight +00:37=Vampirism 01:00=Уперед до перемоги! 01:01=Нічия diff -r 73b0bcc4396d -r 7845c77c8d31 share/hedgewars/Data/Locale/zh_CN.txt --- a/share/hedgewars/Data/Locale/zh_CN.txt Sun Apr 26 15:47:03 2009 +0000 +++ b/share/hedgewars/Data/Locale/zh_CN.txt Thu Apr 30 20:13:44 2009 +0000 @@ -37,6 +37,7 @@ 00:34=刀枪不入 00:35=加时 00:36=激光瞄准 +00:37=Vampirism 01:00=战斗啦! 01:01=平手 diff -r 73b0bcc4396d -r 7845c77c8d31 share/hedgewars/Data/Locale/zh_TW.txt --- a/share/hedgewars/Data/Locale/zh_TW.txt Sun Apr 26 15:47:03 2009 +0000 +++ b/share/hedgewars/Data/Locale/zh_TW.txt Thu Apr 30 20:13:44 2009 +0000 @@ -35,6 +35,7 @@ 00:34=刀槍不入 00:35=附加時間 00:36=雷射瞄准 +00:37=Vampirism 01:00=戰鬥開始! 01:01=平手