--- 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<QVariant> 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<QVariant> 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<QVariant> 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);
--- 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();
--- 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 @@
<file>res/btnMines.png</file>
<file>res/btnTeamsDivide.png</file>
<file>res/btnSolid.png</file>
+ <file>res/btnVampiric.png</file>
+ <file>res/btnKarma.png</file>
<file>res/iconBox.png</file>
<file>res/iconHealth.png</file>
<file>res/iconSuddenDeath.png</file>
--- 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<QString, QString> > cDefaultAmmos =
QList< QPair<QString, QString> >()
<< 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);
--- 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();
}
--- 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;
--- 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;
--- 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
--- 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
--- 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;
--- 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;
--- 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
--- 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;
--- 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);
--- 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)
);
--- 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);
--- 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
--- 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);
--- 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-}
--- 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.
--- 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;
--- 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=Равен рунд
--- 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ě
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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à
--- 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
--- 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
--- 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=Ничья
--- 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
--- 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
--- 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=Нічия
--- 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=平手
--- 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=平手