hedgewars/CCHandlers.inc
changeset 2947 803b277e4894
parent 2905 f3c79f7193a9
child 2948 3f21a9dc93d0
equal deleted inserted replaced
2946:1d9e0a541c62 2947:803b277e4894
     1 (*
     1 (*
     2  * Hedgewars, a free turn based strategy game
     2 * Hedgewars, a free turn based strategy game
     3  * Copyright (c) 2004-2009 Andrey Korotaev <unC0Rr@gmail.com>
     3 * Copyright (c) 2004-2009 Andrey Korotaev <unC0Rr@gmail.com>
     4  *
     4 *
     5  * This program is free software; you can redistribute it and/or modify
     5 * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     6 * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation; version 2 of the License
     7 * the Free Software Foundation; version 2 of the License
     8  *
     8 *
     9  * This program is distributed in the hope that it will be useful,
     9 * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    12 * GNU General Public License for more details.
    13  *
    13 *
    14  * You should have received a copy of the GNU General Public License
    14 * You should have received a copy of the GNU General Public License
    15  * along with this program; if not, write to the Free Software
    15 * along with this program; if not, write to the Free Software
    16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
    16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
    17  *)
    17 *)
    18 
    18 
    19 function CheckNoTeamOrHH: boolean;
    19 function CheckNoTeamOrHH: boolean;
    20 var bRes: boolean;
    20 var bRes: boolean;
    21 begin
    21 begin
    22 bRes:= (CurrentTeam = nil) or (CurrentHedgehog^.Gear = nil);
    22 bRes:= (CurrentTeam = nil) or (CurrentHedgehog^.Gear = nil);
    23 {$IFDEF DEBUGFILE}
    23 {$IFDEF DEBUGFILE}
    24 if bRes then
    24 if bRes then
    25    if CurrentTeam = nil then AddFileLog('CONSOLE: CurTeam = nil')
    25 if CurrentTeam = nil then AddFileLog('CONSOLE: CurTeam = nil')
    26                         else AddFileLog('CONSOLE: CurTeam <> nil, Gear = nil');
    26                         else AddFileLog('CONSOLE: CurTeam <> nil, Gear = nil');
    27 {$ENDIF}
    27 {$ENDIF}
    28 CheckNoTeamOrHH:= bRes;
    28 CheckNoTeamOrHH:= bRes;
    29 end;
    29 end;
    30 ////////////////////////////////////////////////////////////////////////////////
    30 ////////////////////////////////////////////////////////////////////////////////
    40 end;
    40 end;
    41 
    41 
    42 procedure chConfirm(var s: shortstring);
    42 procedure chConfirm(var s: shortstring);
    43 begin
    43 begin
    44 if GameState = gsConfirm then
    44 if GameState = gsConfirm then
    45 	begin
    45     begin
    46 	SendIPC('Q');
    46     SendIPC('Q');
    47 	GameState:= gsExit
    47     GameState:= gsExit
    48 	end
    48     end
    49 else
    49 else
    50     begin
    50     begin
    51     GameState:= gsChat;
    51     GameState:= gsChat;
    52     KeyPressChat(27);
    52     KeyPressChat(27);
    53     KeyPressChat(47);
    53     KeyPressChat(47);
    61 
    61 
    62 procedure chCheckProto(var s: shortstring);
    62 procedure chCheckProto(var s: shortstring);
    63 var i, c: LongInt;
    63 var i, c: LongInt;
    64 begin
    64 begin
    65 if isDeveloperMode then
    65 if isDeveloperMode then
    66    begin
    66 begin
    67    val(s, i, c);
    67 val(s, i, c);
    68    if (c <> 0) or (i = 0) then exit;
    68 if (c <> 0) or (i = 0) then exit;
    69    TryDo(i <= cNetProtoVersion, 'Protocol version mismatch: engine is too old', true);
    69 TryDo(i <= cNetProtoVersion, 'Protocol version mismatch: engine is too old', true);
    70    TryDo(i >= cNetProtoVersion, 'Protocol version mismatch: engine is too new', true)
    70 TryDo(i >= cNetProtoVersion, 'Protocol version mismatch: engine is too new', true)
    71    end
    71 end
    72 end;
    72 end;
    73 
    73 
    74 procedure chAddTeam(var s: shortstring);
    74 procedure chAddTeam(var s: shortstring);
    75 var Color: Longword;
    75 var Color: Longword;
    76     ts, cs: shortstring;
    76     ts, cs: shortstring;
    77 begin
    77 begin
    78 if isDeveloperMode then
    78 if isDeveloperMode then
    79    begin
    79 begin
    80    SplitBySpace(s, cs);
    80 SplitBySpace(s, cs);
    81    SplitBySpace(cs, ts);
    81 SplitBySpace(cs, ts);
    82    val(cs, Color);
    82 val(cs, Color);
    83    TryDo(Color <> 0, 'Error: black team color', true);
    83 TryDo(Color <> 0, 'Error: black team color', true);
    84 
    84 
    85    // color is always little endian so the mask must be constant also in big endian archs
    85 // color is always little endian so the mask must be constant also in big endian archs
    86    Color:= Color or $FF000000;
    86 Color:= Color or $FF000000;
    87  	
    87     
    88    AddTeam(Color);
    88 AddTeam(Color);
    89    CurrentTeam^.TeamName:= ts;
    89 CurrentTeam^.TeamName:= ts;
    90    CurrentTeam^.PlayerHash:= s;
    90 CurrentTeam^.PlayerHash:= s;
    91    if GameType in [gmtDemo, gmtSave] then CurrentTeam^.ExtDriven:= true;
    91 if GameType in [gmtDemo, gmtSave] then CurrentTeam^.ExtDriven:= true;
    92 
    92 
    93    CurrentTeam^.voicepack:= AskForVoicepack('Default')
    93 CurrentTeam^.voicepack:= AskForVoicepack('Default')
    94    end
    94 end
    95 end;
    95 end;
    96 
    96 
    97 procedure chTeamLocal(var s: shortstring);
    97 procedure chTeamLocal(var s: shortstring);
    98 begin
    98 begin
    99 if not isDeveloperMode then exit;
    99 if not isDeveloperMode then exit;
   144 var s: shortstring;
   144 var s: shortstring;
   145     Gear: PGear;
   145     Gear: PGear;
   146 begin
   146 begin
   147 if (not isDeveloperMode) or (CurrentTeam = nil) then exit;
   147 if (not isDeveloperMode) or (CurrentTeam = nil) then exit;
   148 with CurrentTeam^ do
   148 with CurrentTeam^ do
   149 	begin
   149     begin
   150 	SplitBySpace(id, s);
   150     SplitBySpace(id, s);
   151 	CurrentHedgehog:= @Hedgehogs[HedgehogsNumber];
   151     CurrentHedgehog:= @Hedgehogs[HedgehogsNumber];
   152 	val(id, CurrentHedgehog^.BotLevel);
   152     val(id, CurrentHedgehog^.BotLevel);
   153 	Gear:= AddGear(0, 0, gtHedgehog, 0, _0, _0, 0);
   153     Gear:= AddGear(0, 0, gtHedgehog, 0, _0, _0, 0);
   154 	SplitBySpace(s, id);
   154     SplitBySpace(s, id);
   155 	val(s, Gear^.Health);
   155     val(s, Gear^.Health);
   156 	TryDo(Gear^.Health > 0, 'Invalid hedgehog health', true);
   156     TryDo(Gear^.Health > 0, 'Invalid hedgehog health', true);
   157 	PHedgehog(Gear^.Hedgehog)^.Team:= CurrentTeam;
   157     PHedgehog(Gear^.Hedgehog)^.Team:= CurrentTeam;
   158     if (GameFlags and gfSharedAmmo) <> 0 then CurrentHedgehog^.AmmoStore:= Clan^.ClanIndex
   158     if (GameFlags and gfSharedAmmo) <> 0 then CurrentHedgehog^.AmmoStore:= Clan^.ClanIndex
   159     else CurrentHedgehog^.AmmoStore:= TeamsCount - 1;
   159     else CurrentHedgehog^.AmmoStore:= TeamsCount - 1;
   160 	CurrentHedgehog^.Gear:= Gear;
   160     CurrentHedgehog^.Gear:= Gear;
   161 	CurrentHedgehog^.Name:= id;
   161     CurrentHedgehog^.Name:= id;
   162     CurrHedgehog:= HedgehogsNumber;
   162     CurrHedgehog:= HedgehogsNumber;
   163 	inc(HedgehogsNumber)
   163     inc(HedgehogsNumber)
   164 	end
   164     end
   165 end;
   165 end;
   166 
   166 
   167 procedure chSetHat(var s: shortstring);
   167 procedure chSetHat(var s: shortstring);
   168 begin
   168 begin
   169 if (not isDeveloperMode) or (CurrentTeam = nil) then exit;
   169 if (not isDeveloperMode) or (CurrentTeam = nil) then exit;
   170 with CurrentTeam^ do
   170 with CurrentTeam^ do
   171     begin
   171     begin
   172     if not CurrentHedgehog^.King then
   172     if not CurrentHedgehog^.King then
   173        if (s = '') or 
   173     if (s = '') or 
   174           (((GameFlags and gfKing) <> 0) and (s = 'crown')) or
   174         (((GameFlags and gfKing) <> 0) and (s = 'crown')) or
   175           ((Length(s) > 39) and (Copy(s,1,8) = 'Reserved') and (Copy(s,9,32) <> PlayerHash)) then
   175         ((Length(s) > 39) and (Copy(s,1,8) = 'Reserved') and (Copy(s,9,32) <> PlayerHash)) then
   176            CurrentHedgehog^.Hat:= 'NoHat'
   176         CurrentHedgehog^.Hat:= 'NoHat'
   177        else
   177     else
   178            CurrentHedgehog^.Hat:= s
   178         CurrentHedgehog^.Hat:= s
   179     end;
   179     end;
   180 end;
   180 end;
   181 
   181 
   182 procedure chSetHHCoords(var x: shortstring);
   182 procedure chSetHHCoords(var x: shortstring);
   183 var y: shortstring;
   183 var y: shortstring;
   204 SplitBySpace(id, s);
   204 SplitBySpace(id, s);
   205 if s[1]='"' then Delete(s, 1, 1);
   205 if s[1]='"' then Delete(s, 1, 1);
   206 if s[byte(s[0])]='"' then Delete(s, byte(s[0]), 1);
   206 if s[byte(s[0])]='"' then Delete(s, byte(s[0]), 1);
   207 b:= KeyNameToCode(id);
   207 b:= KeyNameToCode(id);
   208 if b = 0 then OutError(errmsgUnknownVariable + ' "' + id + '"', false)
   208 if b = 0 then OutError(errmsgUnknownVariable + ' "' + id + '"', false)
   209          else CurrentTeam^.Binds[b]:= s
   209         else CurrentTeam^.Binds[b]:= s
   210 end;
   210 end;
   211 
   211 
   212 procedure chCurU_p(var s: shortstring);
   212 procedure chCurU_p(var s: shortstring);
   213 begin
   213 begin
   214 CursorMovementY:= -1;
   214 CursorMovementY:= -1;
   261 procedure chLeft_m(var s: shortstring);
   261 procedure chLeft_m(var s: shortstring);
   262 begin
   262 begin
   263 if CheckNoTeamOrHH then exit;
   263 if CheckNoTeamOrHH then exit;
   264 if not CurrentTeam^.ExtDriven then SendIPC('l');
   264 if not CurrentTeam^.ExtDriven then SendIPC('l');
   265 with CurrentHedgehog^.Gear^ do
   265 with CurrentHedgehog^.Gear^ do
   266      Message:= Message and not gm_Left
   266     Message:= Message and not gm_Left
   267 end;
   267 end;
   268 
   268 
   269 procedure chRight_p(var s: shortstring);
   269 procedure chRight_p(var s: shortstring);
   270 begin
   270 begin
   271 if CheckNoTeamOrHH then exit;
   271 if CheckNoTeamOrHH then exit;
   278 procedure chRight_m(var s: shortstring);
   278 procedure chRight_m(var s: shortstring);
   279 begin
   279 begin
   280 if CheckNoTeamOrHH then exit;
   280 if CheckNoTeamOrHH then exit;
   281 if not CurrentTeam^.ExtDriven then SendIPC('r');
   281 if not CurrentTeam^.ExtDriven then SendIPC('r');
   282 with CurrentHedgehog^.Gear^ do
   282 with CurrentHedgehog^.Gear^ do
   283      Message:= Message and not gm_Right
   283     Message:= Message and not gm_Right
   284 end;
   284 end;
   285 
   285 
   286 procedure chUp_p(var s: shortstring);
   286 procedure chUp_p(var s: shortstring);
   287 begin
   287 begin
   288 if CheckNoTeamOrHH then exit;
   288 if CheckNoTeamOrHH then exit;
   295 procedure chUp_m(var s: shortstring);
   295 procedure chUp_m(var s: shortstring);
   296 begin
   296 begin
   297 if CheckNoTeamOrHH then exit;
   297 if CheckNoTeamOrHH then exit;
   298 if not CurrentTeam^.ExtDriven then SendIPC('u');
   298 if not CurrentTeam^.ExtDriven then SendIPC('u');
   299 with CurrentHedgehog^.Gear^ do
   299 with CurrentHedgehog^.Gear^ do
   300      Message:= Message and not gm_Up
   300     Message:= Message and not gm_Up
   301 end;
   301 end;
   302 
   302 
   303 procedure chDown_p(var s: shortstring);
   303 procedure chDown_p(var s: shortstring);
   304 begin
   304 begin
   305 if CheckNoTeamOrHH then exit;
   305 if CheckNoTeamOrHH then exit;
   312 procedure chDown_m(var s: shortstring);
   312 procedure chDown_m(var s: shortstring);
   313 begin
   313 begin
   314 if CheckNoTeamOrHH then exit;
   314 if CheckNoTeamOrHH then exit;
   315 if not CurrentTeam^.ExtDriven then SendIPC('d');
   315 if not CurrentTeam^.ExtDriven then SendIPC('d');
   316 with CurrentHedgehog^.Gear^ do
   316 with CurrentHedgehog^.Gear^ do
   317      Message:= Message and not gm_Down
   317     Message:= Message and not gm_Down
   318 end;
   318 end;
   319 
   319 
   320 procedure chPrecise_p(var s: shortstring);
   320 procedure chPrecise_p(var s: shortstring);
   321 begin
   321 begin
   322 if CheckNoTeamOrHH then exit;
   322 if CheckNoTeamOrHH then exit;
   329 procedure chPrecise_m(var s: shortstring);
   329 procedure chPrecise_m(var s: shortstring);
   330 begin
   330 begin
   331 if CheckNoTeamOrHH then exit;
   331 if CheckNoTeamOrHH then exit;
   332 if not CurrentTeam^.ExtDriven then SendIPC('z');
   332 if not CurrentTeam^.ExtDriven then SendIPC('z');
   333 with CurrentHedgehog^.Gear^ do
   333 with CurrentHedgehog^.Gear^ do
   334      Message:= Message and not gm_Precise
   334     Message:= Message and not gm_Precise
   335 end;
   335 end;
   336 
   336 
   337 procedure chLJump(var s: shortstring);
   337 procedure chLJump(var s: shortstring);
   338 begin
   338 begin
   339 if CheckNoTeamOrHH then exit;
   339 if CheckNoTeamOrHH then exit;
   355 procedure chAttack_p(var s: shortstring);
   355 procedure chAttack_p(var s: shortstring);
   356 begin
   356 begin
   357 if CheckNoTeamOrHH then exit;
   357 if CheckNoTeamOrHH then exit;
   358 bShowFinger:= false;
   358 bShowFinger:= false;
   359 with CurrentHedgehog^.Gear^ do
   359 with CurrentHedgehog^.Gear^ do
   360      begin
   360     begin
   361      {$IFDEF DEBUGFILE}AddFileLog('/+attack: hedgehog''s Gear^.State = '+inttostr(State));{$ENDIF}
   361     {$IFDEF DEBUGFILE}AddFileLog('/+attack: hedgehog''s Gear^.State = '+inttostr(State));{$ENDIF}
   362      if ((State and gstHHDriven) <> 0) then
   362     if ((State and gstHHDriven) <> 0) then
   363         begin
   363         begin
   364         FollowGear:= CurrentHedgehog^.Gear;
   364         FollowGear:= CurrentHedgehog^.Gear;
   365         if not CurrentTeam^.ExtDriven then SendIPC('A');
   365         if not CurrentTeam^.ExtDriven then SendIPC('A');
   366         Message:= Message or gm_Attack
   366         Message:= Message or gm_Attack
   367         end
   367         end
   368      end
   368     end
   369 end;
   369 end;
   370 
   370 
   371 procedure chAttack_m(var s: shortstring);
   371 procedure chAttack_m(var s: shortstring);
   372 begin
   372 begin
   373 if CheckNoTeamOrHH then exit;
   373 if CheckNoTeamOrHH then exit;
   374 with CurrentHedgehog^.Gear^ do
   374 with CurrentHedgehog^.Gear^ do
   375      begin
   375     begin
   376      if not CurrentTeam^.ExtDriven and
   376     if not CurrentTeam^.ExtDriven and
   377         ((Message and gm_Attack) <> 0) then SendIPC('a');
   377         ((Message and gm_Attack) <> 0) then SendIPC('a');
   378      Message:= Message and not gm_Attack
   378     Message:= Message and not gm_Attack
   379      end
   379     end
   380 end;
   380 end;
   381 
   381 
   382 procedure chSwitch(var s: shortstring);
   382 procedure chSwitch(var s: shortstring);
   383 begin
   383 begin
   384 if CheckNoTeamOrHH then exit;
   384 if CheckNoTeamOrHH then exit;
   385 if not CurrentTeam^.ExtDriven then SendIPC('S');
   385 if not CurrentTeam^.ExtDriven then SendIPC('S');
   386 with CurrentHedgehog^.Gear^ do
   386 with CurrentHedgehog^.Gear^ do
   387      Message:= Message or gm_Switch
   387     Message:= Message or gm_Switch
   388 end;
   388 end;
   389 
   389 
   390 procedure chNextTurn(var s: shortstring);
   390 procedure chNextTurn(var s: shortstring);
   391 begin
   391 begin
   392 TryDo(AllInactive, '/nextturn called when not all gears are inactive', true);
   392 TryDo(AllInactive, '/nextturn called when not all gears are inactive', true);
   399 procedure chSay(var s: shortstring);
   399 procedure chSay(var s: shortstring);
   400 begin
   400 begin
   401 SendIPC('s' + s);
   401 SendIPC('s' + s);
   402 
   402 
   403 if copy(s, 1, 4) = '/me ' then
   403 if copy(s, 1, 4) = '/me ' then
   404 	s:= #2'* ' + UserNick + ' ' + copy(s, 5, Length(s) - 4)
   404     s:= #2'* ' + UserNick + ' ' + copy(s, 5, Length(s) - 4)
   405 else
   405 else
   406 	s:= #1 + UserNick + ': ' + s;
   406     s:= #1 + UserNick + ': ' + s;
   407 
   407 
   408 AddChatString(s)
   408 AddChatString(s)
   409 end;
   409 end;
   410 
   410 
   411 procedure chTeamSay(var s: shortstring);
   411 procedure chTeamSay(var s: shortstring);
   422 if (s[0] <> #1) or (s[1] < '1') or (s[1] > '5') or CheckNoTeamOrHH then exit;
   422 if (s[0] <> #1) or (s[1] < '1') or (s[1] > '5') or CheckNoTeamOrHH then exit;
   423 bShowFinger:= false;
   423 bShowFinger:= false;
   424 
   424 
   425 if not CurrentTeam^.ExtDriven then SendIPC(s);
   425 if not CurrentTeam^.ExtDriven then SendIPC(s);
   426 with CurrentHedgehog^.Gear^ do
   426 with CurrentHedgehog^.Gear^ do
   427      begin
   427     begin
   428      Message:= Message or gm_Timer;
   428     Message:= Message or gm_Timer;
   429      MsgParam:= byte(s[1]) - ord('0')
   429     MsgParam:= byte(s[1]) - ord('0')
   430      end
   430     end
   431 end;
   431 end;
   432 
   432 
   433 procedure chSlot(var s: shortstring);
   433 procedure chSlot(var s: shortstring);
   434 var slot: LongWord;
   434 var slot: LongWord;
   435 begin
   435 begin
   437 bShowFinger:= false;
   437 bShowFinger:= false;
   438 slot:= byte(s[1]) - 49;
   438 slot:= byte(s[1]) - 49;
   439 if slot > cMaxSlotIndex then exit;
   439 if slot > cMaxSlotIndex then exit;
   440 if not CurrentTeam^.ExtDriven then SendIPC(char(byte(s[1]) + 79));
   440 if not CurrentTeam^.ExtDriven then SendIPC(char(byte(s[1]) + 79));
   441 with CurrentHedgehog^.Gear^ do
   441 with CurrentHedgehog^.Gear^ do
   442      begin
   442     begin
   443      Message:= Message or gm_Slot;
   443     Message:= Message or gm_Slot;
   444      MsgParam:= slot
   444     MsgParam:= slot
   445      end
   445     end
   446 end;
   446 end;
   447 
   447 
   448 procedure chSetWeapon(var s: shortstring);
   448 procedure chSetWeapon(var s: shortstring);
   449 begin
   449 begin
   450 if (s[0] <> #1) or CheckNoTeamOrHH then exit;
   450 if (s[0] <> #1) or CheckNoTeamOrHH then exit;
   452 if TAmmoType(s[1]) > High(TAmmoType) then exit;
   452 if TAmmoType(s[1]) > High(TAmmoType) then exit;
   453 
   453 
   454 if not CurrentTeam^.ExtDriven then SendIPC('w' + s);
   454 if not CurrentTeam^.ExtDriven then SendIPC('w' + s);
   455 
   455 
   456 with CurrentHedgehog^.Gear^ do
   456 with CurrentHedgehog^.Gear^ do
   457      begin
   457     begin
   458      Message:= Message or gm_Weapon;
   458     Message:= Message or gm_Weapon;
   459      MsgParam:= byte(s[1])
   459     MsgParam:= byte(s[1])
   460      end
   460     end
   461 end;
   461 end;
   462 
   462 
   463 procedure chTaunt(var s: shortstring);
   463 procedure chTaunt(var s: shortstring);
   464 begin
   464 begin
   465 if (s[0] <> #1) or CheckNoTeamOrHH then exit;
   465 if (s[0] <> #1) or CheckNoTeamOrHH then exit;
   467 if TWave(s[1]) > High(TWave) then exit;
   467 if TWave(s[1]) > High(TWave) then exit;
   468 
   468 
   469 if not CurrentTeam^.ExtDriven then SendIPC('t' + s);
   469 if not CurrentTeam^.ExtDriven then SendIPC('t' + s);
   470 
   470 
   471 with CurrentHedgehog^.Gear^ do
   471 with CurrentHedgehog^.Gear^ do
   472      begin
   472     begin
   473      Message:= Message or gm_Animate;
   473     Message:= Message or gm_Animate;
   474      MsgParam:= byte(s[1])
   474     MsgParam:= byte(s[1])
   475      end
   475     end
   476 end;
   476 end;
   477 
   477 
   478 procedure chHogSay(var s: shortstring);
   478 procedure chHogSay(var s: shortstring);
   479 var Gear: PVisualGear;
   479 var Gear: PVisualGear;
   480     text: shortstring;
   480     text: shortstring;
   481 begin
   481 begin
   482 text:= copy(s, 2, Length(s)-1);
   482 text:= copy(s, 2, Length(s)-1);
   483 if CheckNoTeamOrHH
   483 if CheckNoTeamOrHH
   484   or ((CurrentHedgehog^.Gear^.State and gstHHDriven) = 0) then
   484 or ((CurrentHedgehog^.Gear^.State and gstHHDriven) = 0) then
   485     begin
   485     begin
   486     chSay(text);
   486     chSay(text);
   487     exit
   487     exit
   488     end;
   488     end;
   489 
   489 
   491 
   491 
   492 if byte(s[1]) < 4 then
   492 if byte(s[1]) < 4 then
   493     begin
   493     begin
   494     Gear:= AddVisualGear(0, 0, vgtSpeechBubble);
   494     Gear:= AddVisualGear(0, 0, vgtSpeechBubble);
   495     if Gear <> nil then
   495     if Gear <> nil then
   496        begin
   496     begin
   497        Gear^.Hedgehog:= CurrentHedgehog;
   497     Gear^.Hedgehog:= CurrentHedgehog;
   498        Gear^.Text:= text;
   498     Gear^.Text:= text;
   499        Gear^.FrameTicks:= byte(s[1])
   499     Gear^.FrameTicks:= byte(s[1])
   500        end
   500     end
   501     end
   501     end
   502 else
   502 else
   503     begin
   503     begin
   504     SpeechType:= byte(s[1])-3;
   504     SpeechType:= byte(s[1])-3;
   505     SpeechText:= text
   505     SpeechText:= text
   518 
   518 
   519 procedure doPut(putX, putY: LongInt; fromAI: boolean);
   519 procedure doPut(putX, putY: LongInt; fromAI: boolean);
   520 begin
   520 begin
   521 if CheckNoTeamOrHH then exit;
   521 if CheckNoTeamOrHH then exit;
   522 if bShowAmmoMenu then
   522 if bShowAmmoMenu then
   523 	begin
   523     begin
   524 	bSelected:= true;
   524     bSelected:= true;
   525 	exit
   525     exit
   526 	end;
   526     end;
   527 
   527 
   528 with CurrentHedgehog^.Gear^,
   528 with CurrentHedgehog^.Gear^,
   529 	CurrentHedgehog^ do
   529     CurrentHedgehog^ do
   530 	if (State and gstHHChooseTarget) <> 0 then
   530     if (State and gstHHChooseTarget) <> 0 then
   531 		begin
   531         begin
   532 		isCursorVisible:= false;
   532         isCursorVisible:= false;
   533 		if not CurrentTeam^.ExtDriven then
   533         if not CurrentTeam^.ExtDriven then
   534 			begin
   534             begin
   535 			if fromAI then
   535             if fromAI then
   536 				begin
   536                 begin
   537 				TargetPoint.X:= putX;
   537                 TargetPoint.X:= putX;
   538 				TargetPoint.Y:= putY
   538                 TargetPoint.Y:= putY
   539 				end else
   539                 end else
   540 				begin
   540                 begin
   541 				TargetPoint.X:= CursorPoint.X - WorldDx;
   541                 TargetPoint.X:= CursorPoint.X - WorldDx;
   542 				TargetPoint.Y:= cScreenHeight - CursorPoint.Y - WorldDy;
   542                 TargetPoint.Y:= cScreenHeight - CursorPoint.Y - WorldDy;
   543 				end;
   543                 end;
   544 			SendIPCXY('p', TargetPoint.X, TargetPoint.Y);
   544             SendIPCXY('p', TargetPoint.X, TargetPoint.Y);
   545 			end
   545             end
   546 		else
   546         else
   547 			begin
   547             begin
   548 			TargetPoint.X:= putX;
   548             TargetPoint.X:= putX;
   549 			TargetPoint.Y:= putY
   549             TargetPoint.Y:= putY
   550 			end;
   550             end;
   551 		{$IFDEF DEBUGFILE}AddFilelog('put: ' + inttostr(TargetPoint.X) + ', ' + inttostr(TargetPoint.Y));{$ENDIF}
   551         {$IFDEF DEBUGFILE}AddFilelog('put: ' + inttostr(TargetPoint.X) + ', ' + inttostr(TargetPoint.Y));{$ENDIF}
   552 		State:= State and not gstHHChooseTarget;
   552         State:= State and not gstHHChooseTarget;
   553 		if (Ammo^[CurSlot, CurAmmo].Propz and ammoprop_AttackingPut) <> 0 then
   553         if (Ammo^[CurSlot, CurAmmo].Propz and ammoprop_AttackingPut) <> 0 then
   554 			Message:= Message or gm_Attack;
   554             Message:= Message or gm_Attack;
   555 		end
   555         end
   556 	else
   556     else
   557 		if CurrentTeam^.ExtDriven then
   557         if CurrentTeam^.ExtDriven then
   558 			OutError('got /put while not being in choose target mode', false)
   558             OutError('got /put while not being in choose target mode', false)
   559 end;
   559 end;
   560 
   560 
   561 procedure chPut(var s: shortstring);
   561 procedure chPut(var s: shortstring);
   562 begin
   562 begin
   563 doPut(0, 0, false)
   563 doPut(0, 0, false)
   576 end;
   576 end;
   577 
   577 
   578 procedure chSetMap(var s: shortstring);
   578 procedure chSetMap(var s: shortstring);
   579 begin
   579 begin
   580 if isDeveloperMode then
   580 if isDeveloperMode then
   581    begin
   581 begin
   582    Pathz[ptMapCurrent]:= Pathz[ptMaps] + '/' + s;
   582 Pathz[ptMapCurrent]:= Pathz[ptMaps] + '/' + s;
   583    InitStepsFlags:= InitStepsFlags or cifMap
   583 InitStepsFlags:= InitStepsFlags or cifMap
   584    end
   584 end
   585 end;
   585 end;
   586 
   586 
   587 procedure chSetTheme(var s: shortstring);
   587 procedure chSetTheme(var s: shortstring);
   588 begin
   588 begin
   589 if isDeveloperMode then
   589 if isDeveloperMode then
   590    begin
   590 begin
   591    Pathz[ptCurrTheme]:= Pathz[ptThemes] + '/' + s;
   591 Pathz[ptCurrTheme]:= Pathz[ptThemes] + '/' + s;
   592    InitStepsFlags:= InitStepsFlags or cifTheme
   592 InitStepsFlags:= InitStepsFlags or cifTheme
   593    end
   593 end
   594 end;
   594 end;
   595 
   595 
   596 procedure chSetSeed(var s: shortstring);
   596 procedure chSetSeed(var s: shortstring);
   597 begin
   597 begin
   598 if isDeveloperMode then
   598 if isDeveloperMode then
   599    begin
   599 begin
   600    SetRandomSeed(s);
   600 SetRandomSeed(s);
   601    cSeed:= s;
   601 cSeed:= s;
   602    InitStepsFlags:= InitStepsFlags or cifRandomize
   602 InitStepsFlags:= InitStepsFlags or cifRandomize
   603    end
   603 end
   604 end;
   604 end;
   605 
   605 
   606 procedure chAmmoMenu(var s: shortstring);
   606 procedure chAmmoMenu(var s: shortstring);
   607 begin
   607 begin
   608 if CheckNoTeamOrHH then 
   608 if CheckNoTeamOrHH then 
   609    bShowAmmoMenu:= true
   609 bShowAmmoMenu:= true
   610 else
   610 else
   611    with CurrentTeam^ do
   611 with CurrentTeam^ do
   612         with Hedgehogs[CurrHedgehog] do
   612         with Hedgehogs[CurrHedgehog] do
   613              begin
   613             begin
   614              bSelected:= false;
   614             bSelected:= false;
   615 
   615 
   616              if bShowAmmoMenu then bShowAmmoMenu:= false
   616             if bShowAmmoMenu then bShowAmmoMenu:= false
   617              else if ((Gear^.State and (gstAttacking or gstAttacked)) <> 0) or (MultiShootAttacks > 0)
   617             else if ((Gear^.State and (gstAttacking or gstAttacked)) <> 0) or (MultiShootAttacks > 0)
   618                   or ((Gear^.State and gstHHDriven) = 0) then else bShowAmmoMenu:= true
   618                 or ((Gear^.State and gstHHDriven) = 0) then else bShowAmmoMenu:= true
   619              end
   619             end
   620 end;
   620 end;
   621 
   621 
   622 procedure chFullScr(var s: shortstring);
   622 procedure chFullScr(var s: shortstring);
   623 var flags: Longword = 0;
   623 var flags: Longword = 0;
   624 	ico: PSDL_Surface;
   624     ico: PSDL_Surface;
   625 {$IFDEF DEBUGFILE}
   625 {$IFDEF DEBUGFILE}
   626     buf: array[byte] of char;
   626     buf: array[byte] of char;
   627 {$ENDIF}
   627 {$ENDIF}
   628 {$IFDEF SDL13}
   628 {$IFDEF SDL13}
   629     window: PSDL_Window;
   629     window: PSDL_Window;
   630 {$ENDIF}
   630 {$ENDIF}
   631 begin
   631 begin
   632 	if Length(s) = 0 then cFullScreen:= not cFullScreen
   632     if Length(s) = 0 then cFullScreen:= not cFullScreen
   633 	else cFullScreen:= s = '1';
   633     else cFullScreen:= s = '1';
   634 
   634 
   635 {$IFDEF DEBUGFILE}
   635 {$IFDEF DEBUGFILE}
   636 	AddFileLog('Prepare to change video parameters...');
   636     AddFileLog('Prepare to change video parameters...');
   637 {$ENDIF}
   637 {$ENDIF}
   638 
   638 
   639 	flags:= SDL_OPENGL;// or SDL_RESIZABLE;
   639     flags:= SDL_OPENGL;// or SDL_RESIZABLE;
   640 
   640 
   641 	if cFullScreen then
   641     if cFullScreen then
   642 	begin
   642     begin
   643 		flags:= flags or SDL_FULLSCREEN;
   643         flags:= flags or SDL_FULLSCREEN;
   644 		cScreenWidth:= cInitWidth;
   644         cScreenWidth:= cInitWidth;
   645 		cScreenHeight:= cInitHeight
   645         cScreenHeight:= cInitHeight
   646 	end;
   646     end;
   647 
   647 
   648 	// load window icon
   648     // load window icon
   649 	{$IFNDEF DARWIN}
   649     {$IFNDEF DARWIN}
   650 	ico:= LoadImage(Pathz[ptGraphics] + '/hwengine', ifIgnoreCaps);
   650     ico:= LoadImage(Pathz[ptGraphics] + '/hwengine', ifIgnoreCaps);
   651 	{$ELSE}
   651     {$ELSE}
   652 	ico:= LoadImage(Pathz[ptGraphics] + '/hwengine_mac', ifIgnoreCaps);
   652     ico:= LoadImage(Pathz[ptGraphics] + '/hwengine_mac', ifIgnoreCaps);
   653 	{$ENDIF}
   653     {$ENDIF}
   654 	if ico <> nil then
   654     if ico <> nil then
   655 		begin
   655         begin
   656 		SDL_WM_SetIcon(ico, 0);
   656         SDL_WM_SetIcon(ico, 0);
   657 		SDL_FreeSurface(ico)
   657         SDL_FreeSurface(ico)
   658 		end;
   658         end;
   659 	
   659     
   660 	// set window caption
   660     // set window caption
   661 	SDL_WM_SetCaption('Hedgewars', nil);
   661     SDL_WM_SetCaption('Hedgewars', nil);
   662 	
   662     
   663 	if SDLPrimSurface <> nil then
   663     if SDLPrimSurface <> nil then
   664 	begin
   664     begin
   665 {$IFDEF DEBUGFILE}
   665 {$IFDEF DEBUGFILE}
   666 		AddFileLog('Freeing old primary surface...');
   666         AddFileLog('Freeing old primary surface...');
   667 {$ENDIF}
   667 {$ENDIF}
   668 		SDL_FreeSurface(SDLPrimSurface);
   668         SDL_FreeSurface(SDLPrimSurface);
   669 	end;
   669     end;
   670 	
   670     
   671 {$IFDEF SDL13}
   671 {$IFDEF SDL13}
   672 	window:= SDL_CreateWindow('Hedgewars', 0, 0, cScreenWidth, cScreenHeight,
   672     window:= SDL_CreateWindow('Hedgewars', 0, 0, cScreenWidth, cScreenHeight,
   673 		SDL_WINDOW_OPENGL or SDL_WINDOW_SHOWN 	 
   673         SDL_WINDOW_OPENGL or SDL_WINDOW_SHOWN 	 
   674 	        {$IFDEF IPHONEOS} or SDL_WINDOW_BORDERLESS{$ENDIF}); 	 
   674             {$IFDEF IPHONEOS} or SDL_WINDOW_BORDERLESS{$ENDIF}); 	 
   675 	SDL_CreateRenderer(window, -1, 0); 	 
   675     SDL_CreateRenderer(window, -1, 0); 	 
   676 	PixelFormat:= nil; 	 
   676     PixelFormat:= nil; 	 
   677 	  	 
   677         
   678 	SDL_SetRenderDrawColor(0, 0, 0, 255); 	 
   678     SDL_SetRenderDrawColor(0, 0, 0, 255); 	 
   679 	SDL_RenderFill(nil); 	 
   679     SDL_RenderFill(nil); 	 
   680 	SDL_RenderPresent();
   680     SDL_RenderPresent();
   681 {$ELSE}
   681 {$ELSE}
   682 	SDLPrimSurface:= SDL_SetVideoMode(cScreenWidth, cScreenHeight, cBits, flags);
   682     SDLPrimSurface:= SDL_SetVideoMode(cScreenWidth, cScreenHeight, cBits, flags);
   683 	SDLTry(SDLPrimSurface <> nil, true);
   683     SDLTry(SDLPrimSurface <> nil, true);
   684 	PixelFormat:= SDLPrimSurface^.format;
   684     PixelFormat:= SDLPrimSurface^.format;
   685 {$ENDIF}
   685 {$ENDIF}
   686 
   686 
   687 {$IFDEF DEBUGFILE}
   687 {$IFDEF DEBUGFILE}
   688 	AddFileLog('Setting up OpenGL...');
   688     AddFileLog('Setting up OpenGL...');
   689 	AddFileLog('SDL video driver: ' + shortstring(SDL_VideoDriverName(buf, sizeof(buf))));
   689     AddFileLog('SDL video driver: ' + shortstring(SDL_VideoDriverName(buf, sizeof(buf))));
   690 {$ENDIF}
   690 {$ENDIF}
   691 	SetupOpenGL();
   691     SetupOpenGL();
   692 end;
   692 end;
   693 
   693 
   694 procedure chVol_p(var s: shortstring);
   694 procedure chVol_p(var s: shortstring);
   695 begin
   695 begin
   696 inc(cVolumeDelta, 3)
   696 inc(cVolumeDelta, 3)
   709 end;
   709 end;
   710 
   710 
   711 procedure chPause(var s: shortstring);
   711 procedure chPause(var s: shortstring);
   712 begin
   712 begin
   713 if gameType <> gmtNet then
   713 if gameType <> gmtNet then
   714 	isPaused:= not isPaused;
   714     isPaused:= not isPaused;
   715 SDL_ShowCursor(ord(isPaused))
   715 SDL_ShowCursor(ord(isPaused))
   716 end;
   716 end;
   717 
   717 
   718 procedure chRotateMask(var s: shortstring);
   718 procedure chRotateMask(var s: shortstring);
   719 begin
   719 begin
   720 inc(cTagsMaskIndex);
   720 if ((GameFlags and gfInvulnerable) = 0) then cTagsMask:= cTagsMasks[cTagsMask] else cTagsMask:= cTagsMasksNoHealth[cTagsMask];
   721 if cTagsMaskIndex > High(cTagsMasks) then cTagsMaskIndex:= Low(cTagsMasks);
   721 addfilelog('tagmask = ' + inttostr(ctagsmask));
   722 
       
   723 // HACK: skip "health only" if all hogs are invulnerable
       
   724 if ((GameFlags and gfInvulnerable) <> 0) and ((cTagsMasks[cTagsMaskIndex] and not htTransparent) = htHealth) then chRotateMask(s);
       
   725 end;
   722 end;
   726 
   723 
   727 procedure chAddTrigger(var s: shortstring);
   724 procedure chAddTrigger(var s: shortstring);
   728 const MAXPARAMS = 16;
   725 const MAXPARAMS = 16;
   729 var params: array[0..Pred(MAXPARAMS)] of Longword;
   726 var params: array[0..Pred(MAXPARAMS)] of Longword;
   734 c:= s[1];
   731 c:= s[1];
   735 Delete(s, 1, 1);
   732 Delete(s, 1, 1);
   736 
   733 
   737 i:= 0;
   734 i:= 0;
   738 while (i < MAXPARAMS) and
   735 while (i < MAXPARAMS) and
   739       (Length(s) > 0) do
   736     (Length(s) > 0) do
   740     begin
   737     begin
   741     SplitBySpace(s, tmp);
   738     SplitBySpace(s, tmp);
   742     val(s, params[i]);
   739     val(s, params[i]);
   743     s:= tmp;
   740     s:= tmp;
   744     inc(i)
   741     inc(i)
   745     end;
   742     end;
   746 
   743 
   747 case c of
   744 case c of
   748   's': begin // sTYPE TICKS LIVES GEARTYPE X Y GEARTRIGGER
   745 's': begin // sTYPE TICKS LIVES GEARTYPE X Y GEARTRIGGER
   749        TryDo(i = 7, errmsgWrongNumber, true);
   746     TryDo(i = 7, errmsgWrongNumber, true);
   750        AddTriggerSpawner(params[0], params[1], params[2], TGearType(params[3]), params[4], params[5], params[6]);
   747     AddTriggerSpawner(params[0], params[1], params[2], TGearType(params[3]), params[4], params[5], params[6]);
   751        end;
   748     end;
   752   'C': begin
   749 'C': begin
   753        TryDo(i = 3, errmsgWrongNumber, true);
   750     TryDo(i = 3, errmsgWrongNumber, true);
   754        AddTriggerSuccess(params[0], params[1], params[2]);
   751     AddTriggerSuccess(params[0], params[1], params[2]);
   755        end;
   752     end;
   756   'F': begin
   753 'F': begin
   757        TryDo(i = 3, errmsgWrongNumber, true);
   754     TryDo(i = 3, errmsgWrongNumber, true);
   758        AddTriggerFail(params[0], params[1], params[2]);
   755     AddTriggerFail(params[0], params[1], params[2]);
   759        end;
   756     end;
   760   end
   757 end
   761 end;
   758 end;
   762 
   759 
   763 procedure chSpeedup_p(var s: shortstring);
   760 procedure chSpeedup_p(var s: shortstring);
   764 begin
   761 begin
   765 isSpeed:= true
   762 isSpeed:= true