117 IPCSock:= SDLNet_TCP_Open(ipaddr); |
116 IPCSock:= SDLNet_TCP_Open(ipaddr); |
118 SDLTry(IPCSock <> nil, 'SDLNet_TCP_Open', true); |
117 SDLTry(IPCSock <> nil, 'SDLNet_TCP_Open', true); |
119 WriteLnToConsole(msgOK) |
118 WriteLnToConsole(msgOK) |
120 end; |
119 end; |
121 |
120 |
|
121 procedure ParseChatCommand(command: shortstring; message: shortstring; |
|
122 messageStartIndex: Byte); |
|
123 var |
|
124 text: shortstring; |
|
125 begin |
|
126 text:= copy(message, messageStartIndex, |
|
127 Length(message) - messageStartIndex + 1); |
|
128 ParseCommand(command + text, true); |
|
129 WriteLnToConsole(text) |
|
130 end; |
|
131 |
122 procedure ParseIPCCommand(s: shortstring); |
132 procedure ParseIPCCommand(s: shortstring); |
123 var loTicks: Word; |
133 var loTicks: Word; |
124 begin |
134 isProcessed: boolean; |
|
135 begin |
|
136 isProcessed := true; |
|
137 |
125 case s[1] of |
138 case s[1] of |
126 '!': begin AddFileLog('Ping? Pong!'); isPonged:= true; end; |
139 '!': begin AddFileLog('Ping? Pong!'); isPonged:= true; end; |
127 '?': SendIPC(_S'!'); |
140 '?': SendIPC(_S'!'); |
128 'e': ParseCommand(copy(s, 2, Length(s) - 1), true); |
141 'e': ParseCommand(copy(s, 2, Length(s) - 1), true); |
129 'E': OutError(copy(s, 2, Length(s) - 1), true); |
142 'E': OutError(copy(s, 2, Length(s) - 1), true); |
138 'V': GameType:= gmtRecord; |
151 'V': GameType:= gmtRecord; |
139 else OutError(errmsgIncorrectUse + ' IPC "T" :' + s[2], true) end; |
152 else OutError(errmsgIncorrectUse + ' IPC "T" :' + s[2], true) end; |
140 'V': begin |
153 'V': begin |
141 if s[2] = '.' then |
154 if s[2] = '.' then |
142 ParseCommand('campvar ' + copy(s, 3, length(s) - 2), true); |
155 ParseCommand('campvar ' + copy(s, 3, length(s) - 2), true); |
143 end |
156 end; |
|
157 'I': ParseCommand('pause server', true); |
|
158 's': if gameType = gmtNet then |
|
159 ParseChatCommand('chatmsg ', s, 2) |
|
160 else |
|
161 isProcessed:= false; |
|
162 'b': if gameType = gmtNet then |
|
163 ParseChatCommand('chatmsg ' + #4, s, 2) |
|
164 else |
|
165 isProcessed:= false; |
|
166 'Y': ChatPasteBuffer:= copy(s, 2, Length(s) - 1); |
144 else |
167 else |
145 loTicks:= SDLNet_Read16(@s[byte(s[0]) - 1]); |
168 isProcessed:= false; |
146 AddCmd(loTicks, s); |
169 end; |
147 AddFileLog('[IPC in] ' + sanitizeCharForLog(s[1]) + ' ticks ' + IntToStr(lastcmd^.loTime)); |
170 |
148 end |
171 if (not isProcessed) then |
|
172 begin |
|
173 loTicks:= SDLNet_Read16(@s[byte(s[0]) - 1]); |
|
174 AddCmd(loTicks, s); |
|
175 AddFileLog('[IPC in] ' + sanitizeCharForLog(s[1]) + ' ticks ' + IntToStr(lastcmd^.loTime)); |
|
176 end |
149 end; |
177 end; |
150 |
178 |
151 procedure IPCCheckSock; |
179 procedure IPCCheckSock; |
152 var i: LongInt; |
180 var i: LongInt; |
153 s: shortstring; |
181 s: shortstring; |
219 SendIPCRaw(@buf[0], length(buf) + 1) |
246 SendIPCRaw(@buf[0], length(buf) + 1) |
220 end; |
247 end; |
221 |
248 |
222 function isSyncedCommand(c: char): boolean; |
249 function isSyncedCommand(c: char): boolean; |
223 begin |
250 begin |
224 isSyncedCommand:= (c in ['+', '#', 'L', 'l', 'R', 'r', 'U', 'u', 'D', 'd', 'Z', 'z', 'A', 'a', 'S', 'j', 'J', ',', 'c', 'N', 'p', 'P', 'w', 't', '1', '2', '3', '4', '5']) or ((c >= #128) and (c <= char(128 + cMaxSlotIndex))) |
251 case c of |
|
252 '+', '#', 'L', 'l', 'R', 'r', 'U' |
|
253 , 'u', 'D', 'd', 'Z', 'z', 'A', 'a' |
|
254 , 'S', 'j', 'J', ',', 'c', 'N', 'p' |
|
255 , 'P', 'w', 't', '1', '2', '3', '4' |
|
256 , '5', 'f', 'g': isSyncedCommand:= true; |
|
257 else |
|
258 isSyncedCommand:= ((byte(c) >= 128) and (byte(c) <= 128 + cMaxSlotIndex)) |
|
259 end |
225 end; |
260 end; |
226 |
261 |
227 procedure flushBuffer(); |
262 procedure flushBuffer(); |
228 begin |
263 begin |
229 if IPCSock <> nil then |
264 if IPCSock <> nil then |
347 ',': ParseCommand('skip', true); |
383 ',': ParseCommand('skip', true); |
348 'c': begin |
384 'c': begin |
349 s:= copy(headcmd^.str, 2, Pred(headcmd^.len)); |
385 s:= copy(headcmd^.str, 2, Pred(headcmd^.len)); |
350 ParseCommand('gencmd ' + s, true); |
386 ParseCommand('gencmd ' + s, true); |
351 end; |
387 end; |
352 's': begin |
388 's': ParseChatCommand('chatmsg ', headcmd^.str, 2); |
353 s:= copy(headcmd^.str, 2, Pred(headcmd^.len)); |
389 'b': ParseChatCommand('chatmsg ' + #4, headcmd^.str, 2); |
354 ParseCommand('chatmsg ' + s, true); |
390 'F': ParseCommand('teamgone u' + copy(headcmd^.str, 2, Pred(headcmd^.len)), true); |
355 WriteLnToConsole(s) |
391 'G': ParseCommand('teamback u' + copy(headcmd^.str, 2, Pred(headcmd^.len)), true); |
356 end; |
392 'f': ParseCommand('teamgone s' + copy(headcmd^.str, 2, Pred(headcmd^.len)), true); |
357 'b': begin |
393 'g': ParseCommand('teamback s' + copy(headcmd^.str, 2, Pred(headcmd^.len)), true); |
358 s:= copy(headcmd^.str, 2, Pred(headcmd^.len)); |
|
359 ParseCommand('chatmsg ' + #4 + s, true); |
|
360 WriteLnToConsole(s) |
|
361 end; |
|
362 // TODO: deprecate 'F' |
|
363 'F': ParseCommand('teamgone ' + copy(headcmd^.str, 2, Pred(headcmd^.len)), true); |
|
364 'N': begin |
394 'N': begin |
365 tmpflag:= false; |
395 tmpflag:= false; |
366 lastTurnChecksum:= SDLNet_Read32(@headcmd^.str[2]); |
396 lastTurnChecksum:= SDLNet_Read32(@headcmd^.str[2]); |
367 AddFileLog('got cmd "N": time '+IntToStr(hiTicks shl 16 + headcmd^.loTime)) |
397 AddFileLog('got cmd "N": time '+IntToStr(hiTicks shl 16 + headcmd^.loTime)) |
368 end; |
398 end; |
369 'p': begin |
399 'p': begin |
370 x32:= SDLNet_Read32(@(headcmd^.X)); |
400 x32:= SDLNet_Read32(@(headcmd^.str[2])); |
371 y32:= SDLNet_Read32(@(headcmd^.Y)); |
401 y32:= SDLNet_Read32(@(headcmd^.str[6])); |
372 doPut(x32, y32, false) |
402 doPut(x32, y32, false) |
373 end; |
403 end; |
374 'P': begin |
404 'P': begin |
375 // these are equations solved for CursorPoint |
405 // these are equations solved for CursorPoint |
376 // SDLNet_Read16(@(headcmd^.X)) == CursorPoint.X - WorldDx; |
406 // SDLNet_Read16(@(headcmd^.X)) == CursorPoint.X - WorldDx; |
377 // SDLNet_Read16(@(headcmd^.Y)) == cScreenHeight - CursorPoint.Y - WorldDy; |
407 // SDLNet_Read16(@(headcmd^.Y)) == cScreenHeight - CursorPoint.Y - WorldDy; |
378 if CurrentTeam^.ExtDriven then |
408 if CurrentTeam^.ExtDriven then |
379 begin |
409 begin |
380 TargetCursorPoint.X:= LongInt(SDLNet_Read32(@(headcmd^.X))) + WorldDx; |
410 TargetCursorPoint.X:= LongInt(SDLNet_Read32(@(headcmd^.str[2]))) + WorldDx; |
381 TargetCursorPoint.Y:= cScreenHeight - LongInt(SDLNet_Read32(@(headcmd^.Y))) - WorldDy; |
411 TargetCursorPoint.Y:= cScreenHeight - LongInt(SDLNet_Read32(@(headcmd^.str[6]))) - WorldDy; |
382 if not bShowAmmoMenu and autoCameraOn then |
412 if not bShowAmmoMenu and autoCameraOn then |
383 CursorPoint:= TargetCursorPoint |
413 CursorPoint:= TargetCursorPoint |
384 end |
414 end |
385 end; |
415 end; |
386 'w': ParseCommand('setweap ' + headcmd^.str[2], true); |
416 'w': ParseCommand('setweap ' + headcmd^.str[2], true); |
387 't': ParseCommand('taunt ' + headcmd^.str[2], true); |
417 't': ParseCommand('taunt ' + headcmd^.str[2], true); |
388 'h': ParseCommand('hogsay ' + copy(headcmd^.str, 2, Pred(headcmd^.len)), true); |
418 'h': ParseCommand('hogsay ' + copy(headcmd^.str, 2, Pred(headcmd^.len)), true); |
389 '1'..'5': ParseCommand('timer ' + headcmd^.cmd, true); |
419 '1'..'5': ParseCommand('timer ' + headcmd^.cmd, true); |
390 else |
420 else |
391 if (headcmd^.cmd >= #128) and (headcmd^.cmd <= char(128 + cMaxSlotIndex)) then |
421 if (byte(headcmd^.cmd) >= 128) and (byte(headcmd^.cmd) <= 128 + cMaxSlotIndex) then |
392 ParseCommand('slot ' + char(byte(headcmd^.cmd) - 79), true) |
422 ParseCommand('slot ' + char(byte(headcmd^.cmd) - 79), true) |
393 else |
423 else |
394 OutError('Unexpected protocol command: ' + headcmd^.cmd, True) |
424 OutError('Unexpected protocol command: ' + headcmd^.cmd, True) |
395 end; |
425 end; |
396 RemoveCmd |
426 RemoveCmd |
397 end; |
427 end; |
398 |
428 |
399 if (headcmd <> nil) and tmpflag and (not CurrentTeam^.hasGone) then |
429 if (headcmd <> nil) and tmpflag and (not CurrentTeam^.hasGone) then |
400 TryDo(GameTicks < hiTicks shl 16 + headcmd^.loTime, |
430 TryDo(GameTicks < LongWord(hiTicks shl 16) + headcmd^.loTime, |
401 'oops, queue error. in buffer: ' + headcmd^.cmd + |
431 'oops, queue error. in buffer: ' + headcmd^.cmd + |
402 ' (' + IntToStr(GameTicks) + ' > ' + |
432 ' (' + IntToStr(GameTicks) + ' > ' + |
403 IntToStr(hiTicks shl 16 + headcmd^.loTime) + ')', |
433 IntToStr(hiTicks shl 16 + headcmd^.loTime) + ')', |
404 true); |
434 true); |
405 |
435 |
406 isInLag:= (headcmd = nil) and tmpflag and (not CurrentTeam^.hasGone); |
436 isInLag:= (headcmd = nil) and tmpflag and (not CurrentTeam^.hasGone); |
407 |
437 |
408 if isInLag then fastUntilLag:= false |
438 if isInLag and fastUntilLag then |
|
439 begin |
|
440 ParseCommand('spectate 0', true); |
|
441 fastUntilLag:= false |
|
442 end; |
409 end; |
443 end; |
410 |
444 |
411 procedure chFatalError(var s: shortstring); |
445 procedure chFatalError(var s: shortstring); |
412 begin |
446 begin |
413 SendIPC('E' + s); |
447 SendIPC('E' + s); |
414 // TODO: should we try to clean more stuff here? |
448 // TODO: should we try to clean more stuff here? |
415 SDL_Quit; |
449 SDL_Quit; |
416 halt(2) |
450 |
|
451 if IPCSock <> nil then |
|
452 halt(HaltFatalError) |
|
453 else |
|
454 halt(HaltFatalErrorNoIPC); |
417 end; |
455 end; |
418 |
456 |
419 procedure doPut(putX, putY: LongInt; fromAI: boolean); |
457 procedure doPut(putX, putY: LongInt; fromAI: boolean); |
420 begin |
458 begin |
421 if CheckNoTeamOrHH or isPaused then |
459 if CheckNoTeamOrHH or isPaused then |
422 exit; |
460 exit; |
423 bShowFinger:= false; |
461 bShowFinger:= false; |
424 if not CurrentTeam^.ExtDriven and bShowAmmoMenu then |
462 if (not CurrentTeam^.ExtDriven) and bShowAmmoMenu then |
425 begin |
463 begin |
426 bSelected:= true; |
464 bSelected:= true; |
427 exit |
465 exit |
428 end; |
466 end; |
429 |
467 |
430 with CurrentHedgehog^.Gear^, |
468 with CurrentHedgehog^.Gear^, |
431 CurrentHedgehog^ do |
469 CurrentHedgehog^ do |
432 if (State and gstHHChooseTarget) <> 0 then |
470 if (State and gstChooseTarget) <> 0 then |
433 begin |
471 begin |
434 isCursorVisible:= false; |
472 isCursorVisible:= false; |
435 if not CurrentTeam^.ExtDriven then |
473 if not CurrentTeam^.ExtDriven then |
436 begin |
474 begin |
437 if fromAI then |
475 if fromAI then |