141 end; |
141 end; |
142 |
142 |
143 procedure IPCCheckSock; |
143 procedure IPCCheckSock; |
144 const ss: shortstring = ''; |
144 const ss: shortstring = ''; |
145 var i: LongInt; |
145 var i: LongInt; |
146 buf: array[0..255] of byte; |
146 buf: array[0..255] of byte; |
147 s: shortstring absolute buf; |
147 s: shortstring absolute buf; |
148 begin |
148 begin |
149 if IPCSock = nil then |
149 if IPCSock = nil then |
150 exit; |
150 exit; |
151 |
151 |
152 fds^.numsockets:= 0; |
152 fds^.numsockets:= 0; |
153 SDLNet_AddSocket(fds, IPCSock); |
153 SDLNet_AddSocket(fds, IPCSock); |
154 |
154 |
155 while SDLNet_CheckSockets(fds, 0) > 0 do |
155 while SDLNet_CheckSockets(fds, 0) > 0 do |
156 begin |
156 begin |
157 i:= SDLNet_TCP_Recv(IPCSock, @buf[1], 255 - Length(ss)); |
157 i:= SDLNet_TCP_Recv(IPCSock, @buf[1], 255 - Length(ss)); |
158 if i > 0 then |
158 if i > 0 then |
159 begin |
159 begin |
160 buf[0]:= i; |
160 buf[0]:= i; |
161 ss:= ss + s; |
161 ss:= ss + s; |
162 while (Length(ss) > 1) and (Length(ss) > byte(ss[1])) do |
162 while (Length(ss) > 1) and (Length(ss) > byte(ss[1])) do |
163 begin |
163 begin |
164 ParseIPCCommand(copy(ss, 2, byte(ss[1]))); |
164 ParseIPCCommand(copy(ss, 2, byte(ss[1]))); |
165 Delete(ss, 1, Succ(byte(ss[1]))) |
165 Delete(ss, 1, Succ(byte(ss[1]))) |
166 end |
166 end |
167 end else OutError('IPC connection lost', true) |
167 end else OutError('IPC connection lost', true) |
168 end; |
168 end; |
169 end; |
169 end; |
170 |
170 |
171 procedure LoadRecordFromFile(fileName: shortstring); |
171 procedure LoadRecordFromFile(fileName: shortstring); |
172 var f: file; |
172 var f: file; |
173 ss: shortstring = ''; |
173 ss: shortstring = ''; |
174 i: LongInt; |
174 i: LongInt; |
175 buf: array[0..255] of byte; |
175 buf: array[0..255] of byte; |
176 s: shortstring absolute buf; |
176 s: shortstring absolute buf; |
177 begin |
177 begin |
178 |
178 |
179 // set RDNLY on file open |
179 // set RDNLY on file open |
180 filemode:= 0; |
180 filemode:= 0; |
181 |
181 |
182 assign(f, fileName); |
182 assign(f, fileName); |
183 reset(f, 1); |
183 reset(f, 1); |
184 |
184 |
185 repeat |
185 repeat |
186 BlockRead(f, buf[1], 255 - Length(ss), i); |
186 BlockRead(f, buf[1], 255 - Length(ss), i); |
187 if i > 0 then |
187 if i > 0 then |
188 begin |
188 begin |
189 buf[0]:= i; |
189 buf[0]:= i; |
190 ss:= ss + s; |
190 ss:= ss + s; |
191 while (Length(ss) > 1)and(Length(ss) > byte(ss[1])) do |
191 while (Length(ss) > 1)and(Length(ss) > byte(ss[1])) do |
192 begin |
192 begin |
193 ParseIPCCommand(copy(ss, 2, byte(ss[1]))); |
193 ParseIPCCommand(copy(ss, 2, byte(ss[1]))); |
194 Delete(ss, 1, Succ(byte(ss[1]))) |
194 Delete(ss, 1, Succ(byte(ss[1]))) |
195 end |
195 end |
196 end |
196 end |
197 until i = 0; |
197 until i = 0; |
198 |
198 |
199 close(f) |
199 close(f) |
200 end; |
200 end; |
201 |
201 |
202 procedure SendIPC(s: shortstring); |
202 procedure SendIPC(s: shortstring); |
203 begin |
203 begin |
204 if IPCSock <> nil then |
204 if IPCSock <> nil then |
205 begin |
205 begin |
206 SendEmptyPacketTicks:= 0; |
206 SendEmptyPacketTicks:= 0; |
207 if s[0]>#251 then s[0]:= #251; |
207 if s[0]>#251 then s[0]:= #251; |
208 SDLNet_Write16(GameTicks, @s[Succ(byte(s[0]))]); |
208 SDLNet_Write16(GameTicks, @s[Succ(byte(s[0]))]); |
209 {$IFDEF DEBUGFILE}AddFileLog('IPC send: '+ s[1]);{$ENDIF} |
209 {$IFDEF DEBUGFILE}AddFileLog('IPC send: '+ s[1]);{$ENDIF} |
210 inc(s[0], 2); |
210 inc(s[0], 2); |
211 SDLNet_TCP_Send(IPCSock, @s, Succ(byte(s[0]))) |
211 SDLNet_TCP_Send(IPCSock, @s, Succ(byte(s[0]))) |
212 end |
212 end |
213 end; |
213 end; |
214 |
214 |
215 procedure SendIPCRaw(p: pointer; len: Longword); |
215 procedure SendIPCRaw(p: pointer; len: Longword); |
216 begin |
216 begin |
217 if IPCSock <> nil then |
217 if IPCSock <> nil then |
254 |
254 |
255 procedure SendKeepAliveMessage(Lag: Longword); |
255 procedure SendKeepAliveMessage(Lag: Longword); |
256 begin |
256 begin |
257 inc(SendEmptyPacketTicks, Lag); |
257 inc(SendEmptyPacketTicks, Lag); |
258 if (SendEmptyPacketTicks >= cSendEmptyPacketTime) then |
258 if (SendEmptyPacketTicks >= cSendEmptyPacketTime) then |
259 SendIPC('+') |
259 SendIPC('+') |
260 end; |
260 end; |
261 |
261 |
262 procedure NetGetNextCmd; |
262 procedure NetGetNextCmd; |
263 var tmpflag: boolean; |
263 var tmpflag: boolean; |
264 s: shortstring; |
264 s: shortstring; |
265 x16, y16: SmallInt; |
265 x16, y16: SmallInt; |
266 begin |
266 begin |
267 tmpflag:= true; |
267 tmpflag:= true; |
268 |
268 |
269 while (headcmd <> nil) |
269 while (headcmd <> nil) |
270 and (tmpflag or (headcmd^.cmd = '#')) // '#' is the only cmd which can be sent within same tick after 'N' |
270 and (tmpflag or (headcmd^.cmd = '#')) // '#' is the only cmd which can be sent within same tick after 'N' |
271 and ((GameTicks = hiTicks shl 16 + headcmd^.loTime) |
271 and ((GameTicks = hiTicks shl 16 + headcmd^.loTime) |
272 or (headcmd^.cmd = 's') // for these commands time is not specified |
272 or (headcmd^.cmd = 's') // for these commands time is not specified |
273 or (headcmd^.cmd = '#') |
273 or (headcmd^.cmd = '#') |
274 or (headcmd^.cmd = 'b') |
274 or (headcmd^.cmd = 'b') |
275 or (headcmd^.cmd = 'F')) do |
275 or (headcmd^.cmd = 'F')) do |
276 begin |
276 begin |
277 case headcmd^.cmd of |
277 case headcmd^.cmd of |
278 '+': ; // do nothing - it is just an empty packet |
278 '+': ; // do nothing - it is just an empty packet |
279 '#': inc(hiTicks); |
279 '#': inc(hiTicks); |
280 'L': ParseCommand('+left', true); |
280 'L': ParseCommand('+left', true); |
281 'l': ParseCommand('-left', true); |
281 'l': ParseCommand('-left', true); |
282 'R': ParseCommand('+right', true); |
282 'R': ParseCommand('+right', true); |
283 'r': ParseCommand('-right', true); |
283 'r': ParseCommand('-right', true); |
284 'U': ParseCommand('+up', true); |
284 'U': ParseCommand('+up', true); |
285 'u': ParseCommand('-up', true); |
285 'u': ParseCommand('-up', true); |
286 'D': ParseCommand('+down', true); |
286 'D': ParseCommand('+down', true); |
287 'd': ParseCommand('-down', true); |
287 'd': ParseCommand('-down', true); |
288 'Z': ParseCommand('+precise', true); |
288 'Z': ParseCommand('+precise', true); |
289 'z': ParseCommand('-precise', true); |
289 'z': ParseCommand('-precise', true); |
290 'A': ParseCommand('+attack', true); |
290 'A': ParseCommand('+attack', true); |
291 'a': ParseCommand('-attack', true); |
291 'a': ParseCommand('-attack', true); |
292 'S': ParseCommand('switch', true); |
292 'S': ParseCommand('switch', true); |
293 'j': ParseCommand('ljump', true); |
293 'j': ParseCommand('ljump', true); |
294 'J': ParseCommand('hjump', true); |
294 'J': ParseCommand('hjump', true); |
295 ',': ParseCommand('skip', true); |
295 ',': ParseCommand('skip', true); |
296 's': begin |
296 's': begin |
297 s:= copy(headcmd^.str, 2, Pred(headcmd^.len)); |
297 s:= copy(headcmd^.str, 2, Pred(headcmd^.len)); |
298 AddChatString(s); |
298 AddChatString(s); |
299 WriteLnToConsole(s) |
299 WriteLnToConsole(s) |
300 end; |
300 end; |
301 'b': begin |
301 'b': begin |
302 s:= copy(headcmd^.str, 2, Pred(headcmd^.len)); |
302 s:= copy(headcmd^.str, 2, Pred(headcmd^.len)); |
303 AddChatString(#4 + s); |
303 AddChatString(#4 + s); |
304 WriteLnToConsole(s) |
304 WriteLnToConsole(s) |
305 end; |
305 end; |
306 'F': TeamGone(copy(headcmd^.str, 2, Pred(headcmd^.len))); |
306 'F': TeamGone(copy(headcmd^.str, 2, Pred(headcmd^.len))); |
307 'N': begin |
307 'N': begin |
308 tmpflag:= false; |
308 tmpflag:= false; |
309 {$IFDEF DEBUGFILE}AddFileLog('got cmd "N": time '+inttostr(hiTicks shl 16 + headcmd^.loTime)){$ENDIF} |
309 {$IFDEF DEBUGFILE}AddFileLog('got cmd "N": time '+inttostr(hiTicks shl 16 + headcmd^.loTime)){$ENDIF} |
310 end; |
310 end; |
311 'p': begin |
311 'p': begin |
312 x16:= SDLNet_Read16(@(headcmd^.X)); |
312 x16:= SDLNet_Read16(@(headcmd^.X)); |
313 y16:= SDLNet_Read16(@(headcmd^.Y)); |
313 y16:= SDLNet_Read16(@(headcmd^.Y)); |
314 doPut(x16, y16, false) |
314 doPut(x16, y16, false) |
315 end; |
315 end; |
316 'P': begin |
316 'P': begin |
317 // these are equations solved for CursorPoint |
317 // these are equations solved for CursorPoint |
318 // SDLNet_Read16(@(headcmd^.X)) == CursorPoint.X - WorldDx; |
318 // SDLNet_Read16(@(headcmd^.X)) == CursorPoint.X - WorldDx; |
319 // SDLNet_Read16(@(headcmd^.Y)) == cScreenHeight - CursorPoint.Y - WorldDy; |
319 // SDLNet_Read16(@(headcmd^.Y)) == cScreenHeight - CursorPoint.Y - WorldDy; |
320 CursorPoint.X:= SmallInt(SDLNet_Read16(@(headcmd^.X))) + WorldDx; |
320 CursorPoint.X:= SmallInt(SDLNet_Read16(@(headcmd^.X))) + WorldDx; |
321 CursorPoint.Y:= cScreenHeight - SmallInt(SDLNet_Read16(@(headcmd^.Y))) - WorldDy; |
321 CursorPoint.Y:= cScreenHeight - SmallInt(SDLNet_Read16(@(headcmd^.Y))) - WorldDy; |
322 end; |
322 end; |
323 'w': ParseCommand('setweap ' + headcmd^.str[2], true); |
323 'w': ParseCommand('setweap ' + headcmd^.str[2], true); |
324 't': ParseCommand('taunt ' + headcmd^.str[2], true); |
324 't': ParseCommand('taunt ' + headcmd^.str[2], true); |
325 'g': ParseCommand('newgrave', true); |
325 'g': ParseCommand('newgrave', true); |
326 'h': ParseCommand('hogsay ' + copy(headcmd^.str, 2, Pred(headcmd^.len)), true); |
326 'h': ParseCommand('hogsay ' + copy(headcmd^.str, 2, Pred(headcmd^.len)), true); |
327 '1'..'5': ParseCommand('timer ' + headcmd^.cmd, true); |
327 '1'..'5': ParseCommand('timer ' + headcmd^.cmd, true); |
328 #128..char(128 + cMaxSlotIndex): ParseCommand('slot ' + char(byte(headcmd^.cmd) - 79), true) |
328 #128..char(128 + cMaxSlotIndex): ParseCommand('slot ' + char(byte(headcmd^.cmd) - 79), true) |
329 else |
329 else |
330 OutError('Unexpected protocol command: ' + headcmd^.cmd, True) |
330 OutError('Unexpected protocol command: ' + headcmd^.cmd, True) |
331 end; |
331 end; |
332 RemoveCmd |
332 RemoveCmd |
333 end; |
333 end; |
334 |
334 |
335 if (headcmd <> nil) and tmpflag and (not CurrentTeam^.hasGone) then |
335 if (headcmd <> nil) and tmpflag and (not CurrentTeam^.hasGone) then |
336 TryDo(GameTicks < hiTicks shl 16 + headcmd^.loTime, |
336 TryDo(GameTicks < hiTicks shl 16 + headcmd^.loTime, |
337 'oops, queue error. in buffer: ' + headcmd^.cmd + |
337 'oops, queue error. in buffer: ' + headcmd^.cmd + |
338 ' (' + inttostr(GameTicks) + ' > ' + |
338 ' (' + inttostr(GameTicks) + ' > ' + |
339 inttostr(hiTicks shl 16 + headcmd^.loTime) + ')', |
339 inttostr(hiTicks shl 16 + headcmd^.loTime) + ')', |
340 true); |
340 true); |
341 |
341 |
342 isInLag:= (headcmd = nil) and tmpflag and (not CurrentTeam^.hasGone); |
342 isInLag:= (headcmd = nil) and tmpflag and (not CurrentTeam^.hasGone); |
343 |
343 |
344 if isInLag then fastUntilLag:= false |
344 if isInLag then fastUntilLag:= false |
345 end; |
345 end; |
346 |
346 |
347 procedure init_uIO; |
347 procedure init_uIO; |
348 begin |
348 begin |
349 IPCSock:= nil; |
349 IPCSock:= nil; |
350 |
350 |
351 headcmd:= nil; |
351 headcmd:= nil; |
352 lastcmd:= nil; |
352 lastcmd:= nil; |
353 isPonged:= false; // was const |
353 isPonged:= false; // was const |
354 |
354 |
355 hiTicks:= 0; |
355 hiTicks:= 0; |
356 SendEmptyPacketTicks:= 0; |
356 SendEmptyPacketTicks:= 0; |
357 ipcPort:= 0; |
357 ipcPort:= 0; |
358 end; |
358 end; |
359 |
359 |
360 procedure free_uIO; |
360 procedure free_uIO; |
361 begin |
361 begin |
362 |
362 |