1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 1993-2008 Raven Software
4 // Copyright(C) 2005-2014 Simon Howard
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16
17
18 // HEADER FILES ------------------------------------------------------------
19
20 #include "h2def.h"
21 #include "m_misc.h"
22 #include "m_random.h"
23 #include "s_sound.h"
24 #include "i_swap.h"
25 #include "i_system.h"
26 #include "p_local.h"
27
28 // MACROS ------------------------------------------------------------------
29
30 #define MAX_SCRIPT_ARGS 3
31 #define SCRIPT_CONTINUE 0
32 #define SCRIPT_STOP 1
33 #define SCRIPT_TERMINATE 2
34 #define OPEN_SCRIPTS_BASE 1000
35 #define PRINT_BUFFER_SIZE 256
36 #define GAME_SINGLE_PLAYER 0
37 #define GAME_NET_COOPERATIVE 1
38 #define GAME_NET_DEATHMATCH 2
39 #define TEXTURE_TOP 0
40 #define TEXTURE_MIDDLE 1
41 #define TEXTURE_BOTTOM 2
42
43 // TYPES -------------------------------------------------------------------
44
45 typedef PACKED_STRUCT (
46 {
47 int marker;
48 int infoOffset;
49 int code;
50 }) acsHeader_t;
51
52 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
53
54 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
55
56 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
57
58 static void StartOpenACS(int number, int infoIndex, int offset);
59 static void ScriptFinished(int number);
60 static boolean TagBusy(int tag);
61 static boolean AddToACSStore(int map, int number, byte * args);
62 static int GetACSIndex(int number);
63 static void Push(int value);
64 static int Pop(void);
65 static int Top(void);
66 static void Drop(void);
67
68 static int CmdNOP(void);
69 static int CmdTerminate(void);
70 static int CmdSuspend(void);
71 static int CmdPushNumber(void);
72 static int CmdLSpec1(void);
73 static int CmdLSpec2(void);
74 static int CmdLSpec3(void);
75 static int CmdLSpec4(void);
76 static int CmdLSpec5(void);
77 static int CmdLSpec1Direct(void);
78 static int CmdLSpec2Direct(void);
79 static int CmdLSpec3Direct(void);
80 static int CmdLSpec4Direct(void);
81 static int CmdLSpec5Direct(void);
82 static int CmdAdd(void);
83 static int CmdSubtract(void);
84 static int CmdMultiply(void);
85 static int CmdDivide(void);
86 static int CmdModulus(void);
87 static int CmdEQ(void);
88 static int CmdNE(void);
89 static int CmdLT(void);
90 static int CmdGT(void);
91 static int CmdLE(void);
92 static int CmdGE(void);
93 static int CmdAssignScriptVar(void);
94 static int CmdAssignMapVar(void);
95 static int CmdAssignWorldVar(void);
96 static int CmdPushScriptVar(void);
97 static int CmdPushMapVar(void);
98 static int CmdPushWorldVar(void);
99 static int CmdAddScriptVar(void);
100 static int CmdAddMapVar(void);
101 static int CmdAddWorldVar(void);
102 static int CmdSubScriptVar(void);
103 static int CmdSubMapVar(void);
104 static int CmdSubWorldVar(void);
105 static int CmdMulScriptVar(void);
106 static int CmdMulMapVar(void);
107 static int CmdMulWorldVar(void);
108 static int CmdDivScriptVar(void);
109 static int CmdDivMapVar(void);
110 static int CmdDivWorldVar(void);
111 static int CmdModScriptVar(void);
112 static int CmdModMapVar(void);
113 static int CmdModWorldVar(void);
114 static int CmdIncScriptVar(void);
115 static int CmdIncMapVar(void);
116 static int CmdIncWorldVar(void);
117 static int CmdDecScriptVar(void);
118 static int CmdDecMapVar(void);
119 static int CmdDecWorldVar(void);
120 static int CmdGoto(void);
121 static int CmdIfGoto(void);
122 static int CmdDrop(void);
123 static int CmdDelay(void);
124 static int CmdDelayDirect(void);
125 static int CmdRandom(void);
126 static int CmdRandomDirect(void);
127 static int CmdThingCount(void);
128 static int CmdThingCountDirect(void);
129 static int CmdTagWait(void);
130 static int CmdTagWaitDirect(void);
131 static int CmdPolyWait(void);
132 static int CmdPolyWaitDirect(void);
133 static int CmdChangeFloor(void);
134 static int CmdChangeFloorDirect(void);
135 static int CmdChangeCeiling(void);
136 static int CmdChangeCeilingDirect(void);
137 static int CmdRestart(void);
138 static int CmdAndLogical(void);
139 static int CmdOrLogical(void);
140 static int CmdAndBitwise(void);
141 static int CmdOrBitwise(void);
142 static int CmdEorBitwise(void);
143 static int CmdNegateLogical(void);
144 static int CmdLShift(void);
145 static int CmdRShift(void);
146 static int CmdUnaryMinus(void);
147 static int CmdIfNotGoto(void);
148 static int CmdLineSide(void);
149 static int CmdScriptWait(void);
150 static int CmdScriptWaitDirect(void);
151 static int CmdClearLineSpecial(void);
152 static int CmdCaseGoto(void);
153 static int CmdBeginPrint(void);
154 static int CmdEndPrint(void);
155 static int CmdPrintString(void);
156 static int CmdPrintNumber(void);
157 static int CmdPrintCharacter(void);
158 static int CmdPlayerCount(void);
159 static int CmdGameType(void);
160 static int CmdGameSkill(void);
161 static int CmdTimer(void);
162 static int CmdSectorSound(void);
163 static int CmdAmbientSound(void);
164 static int CmdSoundSequence(void);
165 static int CmdSetLineTexture(void);
166 static int CmdSetLineBlocking(void);
167 static int CmdSetLineSpecial(void);
168 static int CmdThingSound(void);
169 static int CmdEndPrintBold(void);
170
171 static void ThingCount(int type, int tid);
172
173 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
174
175 // PUBLIC DATA DEFINITIONS -------------------------------------------------
176
177 int ACScriptCount;
178 byte *ActionCodeBase;
179 static int ActionCodeSize;
180 acsInfo_t *ACSInfo;
181 int MapVars[MAX_ACS_MAP_VARS];
182 int WorldVars[MAX_ACS_WORLD_VARS];
183 acsstore_t ACSStore[MAX_ACS_STORE + 1]; // +1 for termination marker
184
185 // PRIVATE DATA DEFINITIONS ------------------------------------------------
186
187 static char EvalContext[64];
188 static acs_t *ACScript;
189 static unsigned int PCodeOffset;
190 static byte SpecArgs[8];
191 static int ACStringCount;
192 static char **ACStrings;
193 static char PrintBuffer[PRINT_BUFFER_SIZE];
194 static acs_t *NewScript;
195
196 static int (*PCodeCmds[]) (void) =
197 {
198 CmdNOP,
199 CmdTerminate,
200 CmdSuspend,
201 CmdPushNumber,
202 CmdLSpec1,
203 CmdLSpec2,
204 CmdLSpec3,
205 CmdLSpec4,
206 CmdLSpec5,
207 CmdLSpec1Direct,
208 CmdLSpec2Direct,
209 CmdLSpec3Direct,
210 CmdLSpec4Direct,
211 CmdLSpec5Direct,
212 CmdAdd,
213 CmdSubtract,
214 CmdMultiply,
215 CmdDivide,
216 CmdModulus,
217 CmdEQ,
218 CmdNE,
219 CmdLT,
220 CmdGT,
221 CmdLE,
222 CmdGE,
223 CmdAssignScriptVar,
224 CmdAssignMapVar,
225 CmdAssignWorldVar,
226 CmdPushScriptVar,
227 CmdPushMapVar,
228 CmdPushWorldVar,
229 CmdAddScriptVar,
230 CmdAddMapVar,
231 CmdAddWorldVar,
232 CmdSubScriptVar,
233 CmdSubMapVar,
234 CmdSubWorldVar,
235 CmdMulScriptVar,
236 CmdMulMapVar,
237 CmdMulWorldVar,
238 CmdDivScriptVar,
239 CmdDivMapVar,
240 CmdDivWorldVar,
241 CmdModScriptVar,
242 CmdModMapVar,
243 CmdModWorldVar,
244 CmdIncScriptVar,
245 CmdIncMapVar,
246 CmdIncWorldVar,
247 CmdDecScriptVar,
248 CmdDecMapVar,
249 CmdDecWorldVar,
250 CmdGoto,
251 CmdIfGoto,
252 CmdDrop,
253 CmdDelay,
254 CmdDelayDirect,
255 CmdRandom,
256 CmdRandomDirect,
257 CmdThingCount,
258 CmdThingCountDirect,
259 CmdTagWait,
260 CmdTagWaitDirect,
261 CmdPolyWait,
262 CmdPolyWaitDirect,
263 CmdChangeFloor,
264 CmdChangeFloorDirect,
265 CmdChangeCeiling,
266 CmdChangeCeilingDirect,
267 CmdRestart,
268 CmdAndLogical,
269 CmdOrLogical,
270 CmdAndBitwise,
271 CmdOrBitwise,
272 CmdEorBitwise,
273 CmdNegateLogical,
274 CmdLShift,
275 CmdRShift,
276 CmdUnaryMinus,
277 CmdIfNotGoto,
278 CmdLineSide,
279 CmdScriptWait,
280 CmdScriptWaitDirect,
281 CmdClearLineSpecial,
282 CmdCaseGoto,
283 CmdBeginPrint,
284 CmdEndPrint,
285 CmdPrintString,
286 CmdPrintNumber,
287 CmdPrintCharacter,
288 CmdPlayerCount,
289 CmdGameType,
290 CmdGameSkill,
291 CmdTimer,
292 CmdSectorSound,
293 CmdAmbientSound,
294 CmdSoundSequence,
295 CmdSetLineTexture,
296 CmdSetLineBlocking,
297 CmdSetLineSpecial,
298 CmdThingSound,
299 CmdEndPrintBold,
300 };
301
302 // CODE --------------------------------------------------------------------
303
304 //==========================================================================
305 //
306 // ACSAssert
307 //
308 // Check that the given condition evaluates to true. If it does not, exit
309 // with an I_Error() printing the given message.
310 //
311 //==========================================================================
312
ACSAssert(int condition,const char * fmt,...)313 static void ACSAssert(int condition, const char *fmt, ...)
314 {
315 char buf[128];
316 va_list args;
317
318 if (condition)
319 {
320 return;
321 }
322
323 va_start(args, fmt);
324 M_vsnprintf(buf, sizeof(buf), fmt, args);
325 va_end(args);
326 I_Error("ACS assertion failure: in %s: %s", EvalContext, buf);
327 }
328
329 //==========================================================================
330 //
331 // ReadCodeInt
332 //
333 // Read a 32-bit value from the loaded ACS lump at the location pointed to
334 // by PCodeOffset, advancing PCodeOffset to the next value in the process.
335 //
336 //==========================================================================
337
ReadCodeInt(void)338 static int ReadCodeInt(void)
339 {
340 int result;
341 int *ptr;
342
343 ACSAssert(PCodeOffset + 3 < ActionCodeSize,
344 "unexpectedly reached end of ACS lump");
345
346 ptr = (int *) (ActionCodeBase + PCodeOffset);
347 result = LONG(*ptr);
348 PCodeOffset += 4;
349
350 return result;
351 }
352
353 //==========================================================================
354 //
355 // ReadScriptVar
356 //
357 // Read a script variable index as an immediate value, validating the
358 // result is a valid script variable number.
359 //
360 //==========================================================================
361
ReadScriptVar(void)362 static int ReadScriptVar(void)
363 {
364 int var = ReadCodeInt();
365 ACSAssert(var >= 0, "negative script variable: %d < 0", var);
366 ACSAssert(var < MAX_ACS_SCRIPT_VARS,
367 "invalid script variable: %d >= %d", var, MAX_ACS_SCRIPT_VARS);
368 return var;
369 }
370
371 //==========================================================================
372 //
373 // ReadMapVar
374 //
375 // Read a map variable index as an immediate value, validating the
376 // result is a valid map variable number.
377 //
378 //==========================================================================
379
ReadMapVar(void)380 static int ReadMapVar(void)
381 {
382 int var = ReadCodeInt();
383 ACSAssert(var >= 0, "negative map variable: %d < 0", var);
384 ACSAssert(var < MAX_ACS_MAP_VARS,
385 "invalid map variable: %d >= %d", var, MAX_ACS_MAP_VARS);
386 return var;
387 }
388
389 //==========================================================================
390 //
391 // ReadWorldVar
392 //
393 // Read a world variable index as an immediate value, validating the
394 // result is a valid world variable number.
395 //
396 //==========================================================================
397
ReadWorldVar(void)398 static int ReadWorldVar(void)
399 {
400 int var = ReadCodeInt();
401 ACSAssert(var >= 0, "negative world variable: %d < 0", var);
402 ACSAssert(var < MAX_ACS_WORLD_VARS,
403 "invalid world variable: %d >= %d", var, MAX_ACS_WORLD_VARS);
404 return var;
405 }
406
407 //==========================================================================
408 //
409 // StringLookup
410 //
411 // Look up the given string in the strings table by index, validating that
412 // it is a valid string index.
413 //
414 //==========================================================================
415
StringLookup(int string_index)416 static char *StringLookup(int string_index)
417 {
418 ACSAssert(string_index >= 0,
419 "negative string index: %d < 0", string_index);
420 ACSAssert(string_index < ACStringCount,
421 "invalid string index: %d >= %d", string_index, ACStringCount);
422 return ACStrings[string_index];
423 }
424
425 //==========================================================================
426 //
427 // ReadOffset
428 //
429 // Read a lump offset value, validating that it is an offset within the
430 // range of the lump.
431 //
432 //==========================================================================
433
ReadOffset(void)434 static int ReadOffset(void)
435 {
436 int offset = ReadCodeInt();
437 ACSAssert(offset >= 0, "negative lump offset %d", offset);
438 ACSAssert(offset < ActionCodeSize, "invalid lump offset: %d >= %d",
439 offset, ActionCodeSize);
440 return offset;
441 }
442
443 //==========================================================================
444 //
445 // P_LoadACScripts
446 //
447 //==========================================================================
448
P_LoadACScripts(int lump)449 void P_LoadACScripts(int lump)
450 {
451 int i, offset;
452 acsHeader_t *header;
453 acsInfo_t *info;
454
455 ActionCodeBase = W_CacheLumpNum(lump, PU_LEVEL);
456 ActionCodeSize = W_LumpLength(lump);
457
458 M_snprintf(EvalContext, sizeof(EvalContext),
459 "header parsing of lump #%d", lump);
460
461 header = (acsHeader_t *) ActionCodeBase;
462 PCodeOffset = LONG(header->infoOffset);
463
464 ACScriptCount = ReadCodeInt();
465
466 if (ACScriptCount == 0)
467 { // Empty behavior lump
468 return;
469 }
470
471 ACSInfo = Z_Malloc(ACScriptCount * sizeof(acsInfo_t), PU_LEVEL, 0);
472 memset(ACSInfo, 0, ACScriptCount * sizeof(acsInfo_t));
473 for (i = 0, info = ACSInfo; i < ACScriptCount; i++, info++)
474 {
475 info->number = ReadCodeInt();
476 info->offset = ReadOffset();
477 info->argCount = ReadCodeInt();
478
479 if (info->argCount > MAX_SCRIPT_ARGS)
480 {
481 fprintf(stderr, "Warning: ACS script #%i has %i arguments, more "
482 "than the maximum of %i. Enforcing limit.\n"
483 "If you are seeing this message, please report "
484 "the name of the WAD where you saw it.\n",
485 i, info->argCount, MAX_SCRIPT_ARGS);
486 info->argCount = MAX_SCRIPT_ARGS;
487 }
488
489 if (info->number >= OPEN_SCRIPTS_BASE)
490 { // Auto-activate
491 info->number -= OPEN_SCRIPTS_BASE;
492 StartOpenACS(info->number, i, info->offset);
493 info->state = ASTE_RUNNING;
494 }
495 else
496 {
497 info->state = ASTE_INACTIVE;
498 }
499 }
500
501 ACStringCount = ReadCodeInt();
502 ACSAssert(ACStringCount >= 0, "negative string count %d", ACStringCount);
503 ACStrings = Z_Malloc(ACStringCount * sizeof(char *), PU_LEVEL, NULL);
504
505 for (i=0; i<ACStringCount; ++i)
506 {
507 offset = ReadOffset();
508 ACStrings[i] = (char *) ActionCodeBase + offset;
509 ACSAssert(memchr(ACStrings[i], '\0', ActionCodeSize - offset) != NULL,
510 "string %d missing terminating NUL", i);
511 }
512
513 memset(MapVars, 0, sizeof(MapVars));
514 }
515
516 //==========================================================================
517 //
518 // StartOpenACS
519 //
520 //==========================================================================
521
StartOpenACS(int number,int infoIndex,int offset)522 static void StartOpenACS(int number, int infoIndex, int offset)
523 {
524 acs_t *script;
525
526 script = Z_Malloc(sizeof(acs_t), PU_LEVSPEC, 0);
527 memset(script, 0, sizeof(acs_t));
528 script->number = number;
529
530 // World objects are allotted 1 second for initialization
531 script->delayCount = 35;
532
533 script->infoIndex = infoIndex;
534 script->ip = offset;
535 script->thinker.function = T_InterpretACS;
536 P_AddThinker(&script->thinker);
537 }
538
539 //==========================================================================
540 //
541 // P_CheckACSStore
542 //
543 // Scans the ACS store and executes all scripts belonging to the current
544 // map.
545 //
546 //==========================================================================
547
P_CheckACSStore(void)548 void P_CheckACSStore(void)
549 {
550 acsstore_t *store;
551
552 for (store = ACSStore; store->map != 0; store++)
553 {
554 if (store->map == gamemap)
555 {
556 P_StartACS(store->script, 0, store->args, NULL, NULL, 0);
557 if (NewScript)
558 {
559 NewScript->delayCount = 35;
560 }
561 store->map = -1;
562 }
563 }
564 }
565
566 //==========================================================================
567 //
568 // P_StartACS
569 //
570 // Start an ACS script. The 'args' array should be at least MAX_SCRIPT_ARGS
571 // elements in length.
572 //
573 //==========================================================================
574
575 static char ErrorMsg[128];
576
P_StartACS(int number,int map,byte * args,mobj_t * activator,line_t * line,int side)577 boolean P_StartACS(int number, int map, byte * args, mobj_t * activator,
578 line_t * line, int side)
579 {
580 int i;
581 acs_t *script;
582 int infoIndex;
583 aste_t *statePtr;
584
585 NewScript = NULL;
586 if (map && map != gamemap)
587 { // Add to the script store
588 return AddToACSStore(map, number, args);
589 }
590 infoIndex = GetACSIndex(number);
591 if (infoIndex == -1)
592 { // Script not found
593 //I_Error("P_StartACS: Unknown script number %d", number);
594 M_snprintf(ErrorMsg, sizeof(ErrorMsg),
595 "P_STARTACS ERROR: UNKNOWN SCRIPT %d", number);
596 P_SetMessage(&players[consoleplayer], ErrorMsg, true);
597 }
598 statePtr = &ACSInfo[infoIndex].state;
599 if (*statePtr == ASTE_SUSPENDED)
600 { // Resume a suspended script
601 *statePtr = ASTE_RUNNING;
602 return true;
603 }
604 if (*statePtr != ASTE_INACTIVE)
605 { // Script is already executing
606 return false;
607 }
608 script = Z_Malloc(sizeof(acs_t), PU_LEVSPEC, 0);
609 memset(script, 0, sizeof(acs_t));
610 script->number = number;
611 script->infoIndex = infoIndex;
612 script->activator = activator;
613 script->line = line;
614 script->side = side;
615 script->ip = ACSInfo[infoIndex].offset;
616 script->thinker.function = T_InterpretACS;
617 for (i = 0; i < MAX_SCRIPT_ARGS && i < ACSInfo[infoIndex].argCount; i++)
618 {
619 script->vars[i] = args[i];
620 }
621 *statePtr = ASTE_RUNNING;
622 P_AddThinker(&script->thinker);
623 NewScript = script;
624 return true;
625 }
626
627 //==========================================================================
628 //
629 // AddToACSStore
630 //
631 //==========================================================================
632
AddToACSStore(int map,int number,byte * args)633 static boolean AddToACSStore(int map, int number, byte * args)
634 {
635 int i;
636 int index;
637
638 index = -1;
639 for (i = 0; ACSStore[i].map != 0; i++)
640 {
641 if (ACSStore[i].script == number && ACSStore[i].map == map)
642 { // Don't allow duplicates
643 return false;
644 }
645 if (index == -1 && ACSStore[i].map == -1)
646 { // Remember first empty slot
647 index = i;
648 }
649 }
650 if (index == -1)
651 { // Append required
652 if (i == MAX_ACS_STORE)
653 {
654 I_Error("AddToACSStore: MAX_ACS_STORE (%d) exceeded.",
655 MAX_ACS_STORE);
656 }
657 index = i;
658 ACSStore[index + 1].map = 0;
659 }
660 ACSStore[index].map = map;
661 ACSStore[index].script = number;
662 memcpy(ACSStore[index].args, args, MAX_SCRIPT_ARGS);
663 return true;
664 }
665
666 //==========================================================================
667 //
668 // P_StartLockedACS
669 //
670 //==========================================================================
671
672
P_StartLockedACS(line_t * line,byte * args,mobj_t * mo,int side)673 boolean P_StartLockedACS(line_t * line, byte * args, mobj_t * mo, int side)
674 {
675 int i;
676 int lock;
677 byte newArgs[5];
678 char LockedBuffer[80];
679
680 extern char *TextKeyMessages[11];
681
682 lock = args[4];
683 if (!mo->player)
684 {
685 return false;
686 }
687 if (lock)
688 {
689 if (!(mo->player->keys & (1 << (lock - 1))))
690 {
691 M_snprintf(LockedBuffer, sizeof(LockedBuffer),
692 "YOU NEED THE %s\n", TextKeyMessages[lock - 1]);
693 P_SetMessage(mo->player, LockedBuffer, true);
694 S_StartSound(mo, SFX_DOOR_LOCKED);
695 return false;
696 }
697 }
698 for (i = 0; i < 4; i++)
699 {
700 newArgs[i] = args[i];
701 }
702 newArgs[4] = 0;
703 return P_StartACS(newArgs[0], newArgs[1], &newArgs[2], mo, line, side);
704 }
705
706 //==========================================================================
707 //
708 // P_TerminateACS
709 //
710 //==========================================================================
711
P_TerminateACS(int number,int map)712 boolean P_TerminateACS(int number, int map)
713 {
714 int infoIndex;
715
716 infoIndex = GetACSIndex(number);
717 if (infoIndex == -1)
718 { // Script not found
719 return false;
720 }
721 if (ACSInfo[infoIndex].state == ASTE_INACTIVE
722 || ACSInfo[infoIndex].state == ASTE_TERMINATING)
723 { // States that disallow termination
724 return false;
725 }
726 ACSInfo[infoIndex].state = ASTE_TERMINATING;
727 return true;
728 }
729
730 //==========================================================================
731 //
732 // P_SuspendACS
733 //
734 //==========================================================================
735
P_SuspendACS(int number,int map)736 boolean P_SuspendACS(int number, int map)
737 {
738 int infoIndex;
739
740 infoIndex = GetACSIndex(number);
741 if (infoIndex == -1)
742 { // Script not found
743 return false;
744 }
745 if (ACSInfo[infoIndex].state == ASTE_INACTIVE
746 || ACSInfo[infoIndex].state == ASTE_SUSPENDED
747 || ACSInfo[infoIndex].state == ASTE_TERMINATING)
748 { // States that disallow suspension
749 return false;
750 }
751 ACSInfo[infoIndex].state = ASTE_SUSPENDED;
752 return true;
753 }
754
755 //==========================================================================
756 //
757 // P_Init
758 //
759 //==========================================================================
760
P_ACSInitNewGame(void)761 void P_ACSInitNewGame(void)
762 {
763 memset(WorldVars, 0, sizeof(WorldVars));
764 memset(ACSStore, 0, sizeof(ACSStore));
765 }
766
767 //==========================================================================
768 //
769 // T_InterpretACS
770 //
771 //==========================================================================
772
T_InterpretACS(acs_t * script)773 void T_InterpretACS(acs_t * script)
774 {
775 int cmd;
776 int action;
777
778 if (ACSInfo[script->infoIndex].state == ASTE_TERMINATING)
779 {
780 ACSInfo[script->infoIndex].state = ASTE_INACTIVE;
781 ScriptFinished(ACScript->number);
782 P_RemoveThinker(&ACScript->thinker);
783 return;
784 }
785 if (ACSInfo[script->infoIndex].state != ASTE_RUNNING)
786 {
787 return;
788 }
789 if (script->delayCount)
790 {
791 script->delayCount--;
792 return;
793 }
794 ACScript = script;
795 PCodeOffset = ACScript->ip;
796
797 do
798 {
799 M_snprintf(EvalContext, sizeof(EvalContext), "script %d @0x%x",
800 ACSInfo[script->infoIndex].number, PCodeOffset);
801 cmd = ReadCodeInt();
802 M_snprintf(EvalContext, sizeof(EvalContext), "script %d @0x%x, cmd=%d",
803 ACSInfo[script->infoIndex].number, PCodeOffset, cmd);
804 ACSAssert(cmd >= 0, "negative ACS instruction %d", cmd);
805 ACSAssert(cmd < arrlen(PCodeCmds),
806 "invalid ACS instruction %d (maybe this WAD is designed "
807 "for an advanced source port and is not vanilla "
808 "compatible)", cmd);
809 action = PCodeCmds[cmd]();
810 } while (action == SCRIPT_CONTINUE);
811
812 ACScript->ip = PCodeOffset;
813
814 if (action == SCRIPT_TERMINATE)
815 {
816 ACSInfo[script->infoIndex].state = ASTE_INACTIVE;
817 ScriptFinished(ACScript->number);
818 P_RemoveThinker(&ACScript->thinker);
819 }
820 }
821
822 //==========================================================================
823 //
824 // P_TagFinished
825 //
826 //==========================================================================
827
P_TagFinished(int tag)828 void P_TagFinished(int tag)
829 {
830 int i;
831
832 if (TagBusy(tag) == true)
833 {
834 return;
835 }
836 for (i = 0; i < ACScriptCount; i++)
837 {
838 if (ACSInfo[i].state == ASTE_WAITINGFORTAG
839 && ACSInfo[i].waitValue == tag)
840 {
841 ACSInfo[i].state = ASTE_RUNNING;
842 }
843 }
844 }
845
846 //==========================================================================
847 //
848 // P_PolyobjFinished
849 //
850 //==========================================================================
851
P_PolyobjFinished(int po)852 void P_PolyobjFinished(int po)
853 {
854 int i;
855
856 if (PO_Busy(po) == true)
857 {
858 return;
859 }
860 for (i = 0; i < ACScriptCount; i++)
861 {
862 if (ACSInfo[i].state == ASTE_WAITINGFORPOLY
863 && ACSInfo[i].waitValue == po)
864 {
865 ACSInfo[i].state = ASTE_RUNNING;
866 }
867 }
868 }
869
870 //==========================================================================
871 //
872 // ScriptFinished
873 //
874 //==========================================================================
875
ScriptFinished(int number)876 static void ScriptFinished(int number)
877 {
878 int i;
879
880 for (i = 0; i < ACScriptCount; i++)
881 {
882 if (ACSInfo[i].state == ASTE_WAITINGFORSCRIPT
883 && ACSInfo[i].waitValue == number)
884 {
885 ACSInfo[i].state = ASTE_RUNNING;
886 }
887 }
888 }
889
890 //==========================================================================
891 //
892 // TagBusy
893 //
894 //==========================================================================
895
TagBusy(int tag)896 static boolean TagBusy(int tag)
897 {
898 int sectorIndex;
899
900 sectorIndex = -1;
901 while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
902 {
903 if (sectors[sectorIndex].specialdata)
904 {
905 return true;
906 }
907 }
908 return false;
909 }
910
911 //==========================================================================
912 //
913 // GetACSIndex
914 //
915 // Returns the index of a script number. Returns -1 if the script number
916 // is not found.
917 //
918 //==========================================================================
919
GetACSIndex(int number)920 static int GetACSIndex(int number)
921 {
922 int i;
923
924 for (i = 0; i < ACScriptCount; i++)
925 {
926 if (ACSInfo[i].number == number)
927 {
928 return i;
929 }
930 }
931 return -1;
932 }
933
934 //==========================================================================
935 //
936 // CheckACSPresent
937 //
938 // Placing Korax in a PWAD without extra steps will result in a crash in
939 // Vanilla because the relevant ACS scripts are not initialized
940 //
941 //==========================================================================
942
CheckACSPresent(int number)943 void CheckACSPresent(int number)
944 {
945 if (GetACSIndex(number) == -1)
946 {
947 I_Error("Required ACS script %d not initialized", number);
948 }
949 }
950
951 //==========================================================================
952 //
953 // Push
954 //
955 //==========================================================================
956
Push(int value)957 static void Push(int value)
958 {
959 ACSAssert(ACScript->stackPtr < ACS_STACK_DEPTH,
960 "maximum stack depth exceeded: %d >= %d",
961 ACScript->stackPtr, ACS_STACK_DEPTH);
962 ACScript->stack[ACScript->stackPtr++] = value;
963 }
964
965 //==========================================================================
966 //
967 // Pop
968 //
969 //==========================================================================
970
Pop(void)971 static int Pop(void)
972 {
973 ACSAssert(ACScript->stackPtr > 0, "pop of empty stack");
974 return ACScript->stack[--ACScript->stackPtr];
975 }
976
977 //==========================================================================
978 //
979 // Top
980 //
981 //==========================================================================
982
Top(void)983 static int Top(void)
984 {
985 ACSAssert(ACScript->stackPtr > 0, "read from top of empty stack");
986 return ACScript->stack[ACScript->stackPtr - 1];
987 }
988
989 //==========================================================================
990 //
991 // Drop
992 //
993 //==========================================================================
994
Drop(void)995 static void Drop(void)
996 {
997 ACSAssert(ACScript->stackPtr > 0, "drop on empty stack");
998 ACScript->stackPtr--;
999 }
1000
1001 //==========================================================================
1002 //
1003 // P-Code Commands
1004 //
1005 //==========================================================================
1006
CmdNOP(void)1007 static int CmdNOP(void)
1008 {
1009 return SCRIPT_CONTINUE;
1010 }
1011
CmdTerminate(void)1012 static int CmdTerminate(void)
1013 {
1014 return SCRIPT_TERMINATE;
1015 }
1016
CmdSuspend(void)1017 static int CmdSuspend(void)
1018 {
1019 ACSInfo[ACScript->infoIndex].state = ASTE_SUSPENDED;
1020 return SCRIPT_STOP;
1021 }
1022
CmdPushNumber(void)1023 static int CmdPushNumber(void)
1024 {
1025 Push(ReadCodeInt());
1026 return SCRIPT_CONTINUE;
1027 }
1028
CmdLSpec1(void)1029 static int CmdLSpec1(void)
1030 {
1031 int special;
1032
1033 special = ReadCodeInt();
1034 SpecArgs[0] = Pop();
1035 P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
1036 ACScript->side, ACScript->activator);
1037 return SCRIPT_CONTINUE;
1038 }
1039
CmdLSpec2(void)1040 static int CmdLSpec2(void)
1041 {
1042 int special;
1043
1044 special = ReadCodeInt();
1045 SpecArgs[1] = Pop();
1046 SpecArgs[0] = Pop();
1047 P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
1048 ACScript->side, ACScript->activator);
1049 return SCRIPT_CONTINUE;
1050 }
1051
CmdLSpec3(void)1052 static int CmdLSpec3(void)
1053 {
1054 int special;
1055
1056 special = ReadCodeInt();
1057 SpecArgs[2] = Pop();
1058 SpecArgs[1] = Pop();
1059 SpecArgs[0] = Pop();
1060 P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
1061 ACScript->side, ACScript->activator);
1062 return SCRIPT_CONTINUE;
1063 }
1064
CmdLSpec4(void)1065 static int CmdLSpec4(void)
1066 {
1067 int special;
1068
1069 special = ReadCodeInt();
1070 SpecArgs[3] = Pop();
1071 SpecArgs[2] = Pop();
1072 SpecArgs[1] = Pop();
1073 SpecArgs[0] = Pop();
1074 P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
1075 ACScript->side, ACScript->activator);
1076 return SCRIPT_CONTINUE;
1077 }
1078
CmdLSpec5(void)1079 static int CmdLSpec5(void)
1080 {
1081 int special;
1082
1083 special = ReadCodeInt();
1084 SpecArgs[4] = Pop();
1085 SpecArgs[3] = Pop();
1086 SpecArgs[2] = Pop();
1087 SpecArgs[1] = Pop();
1088 SpecArgs[0] = Pop();
1089 P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
1090 ACScript->side, ACScript->activator);
1091 return SCRIPT_CONTINUE;
1092 }
1093
CmdLSpec1Direct(void)1094 static int CmdLSpec1Direct(void)
1095 {
1096 int special;
1097
1098 special = ReadCodeInt();
1099 SpecArgs[0] = ReadCodeInt();
1100 P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
1101 ACScript->side, ACScript->activator);
1102 return SCRIPT_CONTINUE;
1103 }
1104
CmdLSpec2Direct(void)1105 static int CmdLSpec2Direct(void)
1106 {
1107 int special;
1108
1109 special = ReadCodeInt();
1110 SpecArgs[0] = ReadCodeInt();
1111 SpecArgs[1] = ReadCodeInt();
1112 P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
1113 ACScript->side, ACScript->activator);
1114 return SCRIPT_CONTINUE;
1115 }
1116
CmdLSpec3Direct(void)1117 static int CmdLSpec3Direct(void)
1118 {
1119 int special;
1120
1121 special = ReadCodeInt();
1122 SpecArgs[0] = ReadCodeInt();
1123 SpecArgs[1] = ReadCodeInt();
1124 SpecArgs[2] = ReadCodeInt();
1125 P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
1126 ACScript->side, ACScript->activator);
1127 return SCRIPT_CONTINUE;
1128 }
1129
CmdLSpec4Direct(void)1130 static int CmdLSpec4Direct(void)
1131 {
1132 int special;
1133
1134 special = ReadCodeInt();
1135 SpecArgs[0] = ReadCodeInt();
1136 SpecArgs[1] = ReadCodeInt();
1137 SpecArgs[2] = ReadCodeInt();
1138 SpecArgs[3] = ReadCodeInt();
1139 P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
1140 ACScript->side, ACScript->activator);
1141 return SCRIPT_CONTINUE;
1142 }
1143
CmdLSpec5Direct(void)1144 static int CmdLSpec5Direct(void)
1145 {
1146 int special;
1147
1148 special = ReadCodeInt();
1149 SpecArgs[0] = ReadCodeInt();
1150 SpecArgs[1] = ReadCodeInt();
1151 SpecArgs[2] = ReadCodeInt();
1152 SpecArgs[3] = ReadCodeInt();
1153 SpecArgs[4] = ReadCodeInt();
1154 P_ExecuteLineSpecial(special, SpecArgs, ACScript->line,
1155 ACScript->side, ACScript->activator);
1156 return SCRIPT_CONTINUE;
1157 }
1158
CmdAdd(void)1159 static int CmdAdd(void)
1160 {
1161 Push(Pop() + Pop());
1162 return SCRIPT_CONTINUE;
1163 }
1164
CmdSubtract(void)1165 static int CmdSubtract(void)
1166 {
1167 int operand2;
1168
1169 operand2 = Pop();
1170 Push(Pop() - operand2);
1171 return SCRIPT_CONTINUE;
1172 }
1173
CmdMultiply(void)1174 static int CmdMultiply(void)
1175 {
1176 Push(Pop() * Pop());
1177 return SCRIPT_CONTINUE;
1178 }
1179
CmdDivide(void)1180 static int CmdDivide(void)
1181 {
1182 int operand2;
1183
1184 operand2 = Pop();
1185 Push(Pop() / operand2);
1186 return SCRIPT_CONTINUE;
1187 }
1188
CmdModulus(void)1189 static int CmdModulus(void)
1190 {
1191 int operand2;
1192
1193 operand2 = Pop();
1194 Push(Pop() % operand2);
1195 return SCRIPT_CONTINUE;
1196 }
1197
CmdEQ(void)1198 static int CmdEQ(void)
1199 {
1200 Push(Pop() == Pop());
1201 return SCRIPT_CONTINUE;
1202 }
1203
CmdNE(void)1204 static int CmdNE(void)
1205 {
1206 Push(Pop() != Pop());
1207 return SCRIPT_CONTINUE;
1208 }
1209
CmdLT(void)1210 static int CmdLT(void)
1211 {
1212 int operand2;
1213
1214 operand2 = Pop();
1215 Push(Pop() < operand2);
1216 return SCRIPT_CONTINUE;
1217 }
1218
CmdGT(void)1219 static int CmdGT(void)
1220 {
1221 int operand2;
1222
1223 operand2 = Pop();
1224 Push(Pop() > operand2);
1225 return SCRIPT_CONTINUE;
1226 }
1227
CmdLE(void)1228 static int CmdLE(void)
1229 {
1230 int operand2;
1231
1232 operand2 = Pop();
1233 Push(Pop() <= operand2);
1234 return SCRIPT_CONTINUE;
1235 }
1236
CmdGE(void)1237 static int CmdGE(void)
1238 {
1239 int operand2;
1240
1241 operand2 = Pop();
1242 Push(Pop() >= operand2);
1243 return SCRIPT_CONTINUE;
1244 }
1245
CmdAssignScriptVar(void)1246 static int CmdAssignScriptVar(void)
1247 {
1248 ACScript->vars[ReadScriptVar()] = Pop();
1249 return SCRIPT_CONTINUE;
1250 }
1251
CmdAssignMapVar(void)1252 static int CmdAssignMapVar(void)
1253 {
1254 MapVars[ReadMapVar()] = Pop();
1255 return SCRIPT_CONTINUE;
1256 }
1257
CmdAssignWorldVar(void)1258 static int CmdAssignWorldVar(void)
1259 {
1260 WorldVars[ReadWorldVar()] = Pop();
1261 return SCRIPT_CONTINUE;
1262 }
1263
CmdPushScriptVar(void)1264 static int CmdPushScriptVar(void)
1265 {
1266 Push(ACScript->vars[ReadScriptVar()]);
1267 return SCRIPT_CONTINUE;
1268 }
1269
CmdPushMapVar(void)1270 static int CmdPushMapVar(void)
1271 {
1272 Push(MapVars[ReadMapVar()]);
1273 return SCRIPT_CONTINUE;
1274 }
1275
CmdPushWorldVar(void)1276 static int CmdPushWorldVar(void)
1277 {
1278 Push(WorldVars[ReadWorldVar()]);
1279 return SCRIPT_CONTINUE;
1280 }
1281
CmdAddScriptVar(void)1282 static int CmdAddScriptVar(void)
1283 {
1284 ACScript->vars[ReadScriptVar()] += Pop();
1285 return SCRIPT_CONTINUE;
1286 }
1287
CmdAddMapVar(void)1288 static int CmdAddMapVar(void)
1289 {
1290 MapVars[ReadMapVar()] += Pop();
1291 return SCRIPT_CONTINUE;
1292 }
1293
CmdAddWorldVar(void)1294 static int CmdAddWorldVar(void)
1295 {
1296 WorldVars[ReadWorldVar()] += Pop();
1297 return SCRIPT_CONTINUE;
1298 }
1299
CmdSubScriptVar(void)1300 static int CmdSubScriptVar(void)
1301 {
1302 ACScript->vars[ReadScriptVar()] -= Pop();
1303 return SCRIPT_CONTINUE;
1304 }
1305
CmdSubMapVar(void)1306 static int CmdSubMapVar(void)
1307 {
1308 MapVars[ReadMapVar()] -= Pop();
1309 return SCRIPT_CONTINUE;
1310 }
1311
CmdSubWorldVar(void)1312 static int CmdSubWorldVar(void)
1313 {
1314 WorldVars[ReadWorldVar()] -= Pop();
1315 return SCRIPT_CONTINUE;
1316 }
1317
CmdMulScriptVar(void)1318 static int CmdMulScriptVar(void)
1319 {
1320 ACScript->vars[ReadScriptVar()] *= Pop();
1321 return SCRIPT_CONTINUE;
1322 }
1323
CmdMulMapVar(void)1324 static int CmdMulMapVar(void)
1325 {
1326 MapVars[ReadMapVar()] *= Pop();
1327 return SCRIPT_CONTINUE;
1328 }
1329
CmdMulWorldVar(void)1330 static int CmdMulWorldVar(void)
1331 {
1332 WorldVars[ReadWorldVar()] *= Pop();
1333 return SCRIPT_CONTINUE;
1334 }
1335
CmdDivScriptVar(void)1336 static int CmdDivScriptVar(void)
1337 {
1338 ACScript->vars[ReadScriptVar()] /= Pop();
1339 return SCRIPT_CONTINUE;
1340 }
1341
CmdDivMapVar(void)1342 static int CmdDivMapVar(void)
1343 {
1344 MapVars[ReadMapVar()] /= Pop();
1345 return SCRIPT_CONTINUE;
1346 }
1347
CmdDivWorldVar(void)1348 static int CmdDivWorldVar(void)
1349 {
1350 WorldVars[ReadWorldVar()] /= Pop();
1351 return SCRIPT_CONTINUE;
1352 }
1353
CmdModScriptVar(void)1354 static int CmdModScriptVar(void)
1355 {
1356 ACScript->vars[ReadScriptVar()] %= Pop();
1357 return SCRIPT_CONTINUE;
1358 }
1359
CmdModMapVar(void)1360 static int CmdModMapVar(void)
1361 {
1362 MapVars[ReadMapVar()] %= Pop();
1363 return SCRIPT_CONTINUE;
1364 }
1365
CmdModWorldVar(void)1366 static int CmdModWorldVar(void)
1367 {
1368 WorldVars[ReadWorldVar()] %= Pop();
1369 return SCRIPT_CONTINUE;
1370 }
1371
CmdIncScriptVar(void)1372 static int CmdIncScriptVar(void)
1373 {
1374 ++ACScript->vars[ReadScriptVar()];
1375 return SCRIPT_CONTINUE;
1376 }
1377
CmdIncMapVar(void)1378 static int CmdIncMapVar(void)
1379 {
1380 ++MapVars[ReadMapVar()];
1381 return SCRIPT_CONTINUE;
1382 }
1383
CmdIncWorldVar(void)1384 static int CmdIncWorldVar(void)
1385 {
1386 ++WorldVars[ReadWorldVar()];
1387 return SCRIPT_CONTINUE;
1388 }
1389
CmdDecScriptVar(void)1390 static int CmdDecScriptVar(void)
1391 {
1392 --ACScript->vars[ReadScriptVar()];
1393 return SCRIPT_CONTINUE;
1394 }
1395
CmdDecMapVar(void)1396 static int CmdDecMapVar(void)
1397 {
1398 --MapVars[ReadMapVar()];
1399 return SCRIPT_CONTINUE;
1400 }
1401
CmdDecWorldVar(void)1402 static int CmdDecWorldVar(void)
1403 {
1404 --WorldVars[ReadWorldVar()];
1405 return SCRIPT_CONTINUE;
1406 }
1407
CmdGoto(void)1408 static int CmdGoto(void)
1409 {
1410 PCodeOffset = ReadOffset();
1411 return SCRIPT_CONTINUE;
1412 }
1413
CmdIfGoto(void)1414 static int CmdIfGoto(void)
1415 {
1416 int offset;
1417
1418 offset = ReadOffset();
1419
1420 if (Pop() != 0)
1421 {
1422 PCodeOffset = offset;
1423 }
1424 return SCRIPT_CONTINUE;
1425 }
1426
CmdDrop(void)1427 static int CmdDrop(void)
1428 {
1429 Drop();
1430 return SCRIPT_CONTINUE;
1431 }
1432
CmdDelay(void)1433 static int CmdDelay(void)
1434 {
1435 ACScript->delayCount = Pop();
1436 return SCRIPT_STOP;
1437 }
1438
CmdDelayDirect(void)1439 static int CmdDelayDirect(void)
1440 {
1441 ACScript->delayCount = ReadCodeInt();
1442 return SCRIPT_STOP;
1443 }
1444
CmdRandom(void)1445 static int CmdRandom(void)
1446 {
1447 int low;
1448 int high;
1449
1450 high = Pop();
1451 low = Pop();
1452 Push(low + (P_Random() % (high - low + 1)));
1453 return SCRIPT_CONTINUE;
1454 }
1455
CmdRandomDirect(void)1456 static int CmdRandomDirect(void)
1457 {
1458 int low;
1459 int high;
1460
1461 low = ReadCodeInt();
1462 high = ReadCodeInt();
1463 Push(low + (P_Random() % (high - low + 1)));
1464 return SCRIPT_CONTINUE;
1465 }
1466
CmdThingCount(void)1467 static int CmdThingCount(void)
1468 {
1469 int tid;
1470
1471 tid = Pop();
1472 ThingCount(Pop(), tid);
1473 return SCRIPT_CONTINUE;
1474 }
1475
CmdThingCountDirect(void)1476 static int CmdThingCountDirect(void)
1477 {
1478 int type;
1479
1480 type = ReadCodeInt();
1481 ThingCount(type, ReadCodeInt());
1482 return SCRIPT_CONTINUE;
1483 }
1484
ThingCount(int type,int tid)1485 static void ThingCount(int type, int tid)
1486 {
1487 int count;
1488 int searcher;
1489 mobj_t *mobj;
1490 mobjtype_t moType;
1491 thinker_t *think;
1492
1493 if (!(type + tid))
1494 { // Nothing to count
1495 return;
1496 }
1497 moType = TranslateThingType[type];
1498 count = 0;
1499 searcher = -1;
1500 if (tid)
1501 { // Count TID things
1502 while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
1503 {
1504 if (type == 0)
1505 { // Just count TIDs
1506 count++;
1507 }
1508 else if (moType == mobj->type)
1509 {
1510 if (mobj->flags & MF_COUNTKILL && mobj->health <= 0)
1511 { // Don't count dead monsters
1512 continue;
1513 }
1514 count++;
1515 }
1516 }
1517 }
1518 else
1519 { // Count only types
1520 for (think = thinkercap.next; think != &thinkercap;
1521 think = think->next)
1522 {
1523 if (think->function != P_MobjThinker)
1524 { // Not a mobj thinker
1525 continue;
1526 }
1527 mobj = (mobj_t *) think;
1528 if (mobj->type != moType)
1529 { // Doesn't match
1530 continue;
1531 }
1532 if (mobj->flags & MF_COUNTKILL && mobj->health <= 0)
1533 { // Don't count dead monsters
1534 continue;
1535 }
1536 count++;
1537 }
1538 }
1539 Push(count);
1540 }
1541
CmdTagWait(void)1542 static int CmdTagWait(void)
1543 {
1544 ACSInfo[ACScript->infoIndex].waitValue = Pop();
1545 ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORTAG;
1546 return SCRIPT_STOP;
1547 }
1548
CmdTagWaitDirect(void)1549 static int CmdTagWaitDirect(void)
1550 {
1551 ACSInfo[ACScript->infoIndex].waitValue = ReadCodeInt();
1552 ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORTAG;
1553 return SCRIPT_STOP;
1554 }
1555
CmdPolyWait(void)1556 static int CmdPolyWait(void)
1557 {
1558 ACSInfo[ACScript->infoIndex].waitValue = Pop();
1559 ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORPOLY;
1560 return SCRIPT_STOP;
1561 }
1562
CmdPolyWaitDirect(void)1563 static int CmdPolyWaitDirect(void)
1564 {
1565 ACSInfo[ACScript->infoIndex].waitValue = ReadCodeInt();
1566 ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORPOLY;
1567 return SCRIPT_STOP;
1568 }
1569
CmdChangeFloor(void)1570 static int CmdChangeFloor(void)
1571 {
1572 int tag;
1573 int flat;
1574 int sectorIndex;
1575
1576 flat = R_FlatNumForName(StringLookup(Pop()));
1577 tag = Pop();
1578 sectorIndex = -1;
1579 while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
1580 {
1581 sectors[sectorIndex].floorpic = flat;
1582 }
1583 return SCRIPT_CONTINUE;
1584 }
1585
CmdChangeFloorDirect(void)1586 static int CmdChangeFloorDirect(void)
1587 {
1588 int tag;
1589 int flat;
1590 int sectorIndex;
1591
1592 tag = ReadCodeInt();
1593 flat = R_FlatNumForName(StringLookup(ReadCodeInt()));
1594 sectorIndex = -1;
1595 while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
1596 {
1597 sectors[sectorIndex].floorpic = flat;
1598 }
1599 return SCRIPT_CONTINUE;
1600 }
1601
CmdChangeCeiling(void)1602 static int CmdChangeCeiling(void)
1603 {
1604 int tag;
1605 int flat;
1606 int sectorIndex;
1607
1608 flat = R_FlatNumForName(StringLookup(Pop()));
1609 tag = Pop();
1610 sectorIndex = -1;
1611 while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
1612 {
1613 sectors[sectorIndex].ceilingpic = flat;
1614 }
1615 return SCRIPT_CONTINUE;
1616 }
1617
CmdChangeCeilingDirect(void)1618 static int CmdChangeCeilingDirect(void)
1619 {
1620 int tag;
1621 int flat;
1622 int sectorIndex;
1623
1624 tag = ReadCodeInt();
1625 flat = R_FlatNumForName(StringLookup(ReadCodeInt()));
1626 sectorIndex = -1;
1627 while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
1628 {
1629 sectors[sectorIndex].ceilingpic = flat;
1630 }
1631 return SCRIPT_CONTINUE;
1632 }
1633
CmdRestart(void)1634 static int CmdRestart(void)
1635 {
1636 PCodeOffset = ACSInfo[ACScript->infoIndex].offset;
1637 return SCRIPT_CONTINUE;
1638 }
1639
CmdAndLogical(void)1640 static int CmdAndLogical(void)
1641 {
1642 Push(Pop() && Pop());
1643 return SCRIPT_CONTINUE;
1644 }
1645
CmdOrLogical(void)1646 static int CmdOrLogical(void)
1647 {
1648 Push(Pop() || Pop());
1649 return SCRIPT_CONTINUE;
1650 }
1651
CmdAndBitwise(void)1652 static int CmdAndBitwise(void)
1653 {
1654 Push(Pop() & Pop());
1655 return SCRIPT_CONTINUE;
1656 }
1657
CmdOrBitwise(void)1658 static int CmdOrBitwise(void)
1659 {
1660 Push(Pop() | Pop());
1661 return SCRIPT_CONTINUE;
1662 }
1663
CmdEorBitwise(void)1664 static int CmdEorBitwise(void)
1665 {
1666 Push(Pop() ^ Pop());
1667 return SCRIPT_CONTINUE;
1668 }
1669
CmdNegateLogical(void)1670 static int CmdNegateLogical(void)
1671 {
1672 Push(!Pop());
1673 return SCRIPT_CONTINUE;
1674 }
1675
CmdLShift(void)1676 static int CmdLShift(void)
1677 {
1678 int operand2;
1679
1680 operand2 = Pop();
1681 Push(Pop() << operand2);
1682 return SCRIPT_CONTINUE;
1683 }
1684
CmdRShift(void)1685 static int CmdRShift(void)
1686 {
1687 int operand2;
1688
1689 operand2 = Pop();
1690 Push(Pop() >> operand2);
1691 return SCRIPT_CONTINUE;
1692 }
1693
CmdUnaryMinus(void)1694 static int CmdUnaryMinus(void)
1695 {
1696 Push(-Pop());
1697 return SCRIPT_CONTINUE;
1698 }
1699
CmdIfNotGoto(void)1700 static int CmdIfNotGoto(void)
1701 {
1702 int offset;
1703
1704 offset = ReadOffset();
1705
1706 if (Pop() == 0)
1707 {
1708 PCodeOffset = offset;
1709 }
1710 return SCRIPT_CONTINUE;
1711 }
1712
CmdLineSide(void)1713 static int CmdLineSide(void)
1714 {
1715 Push(ACScript->side);
1716 return SCRIPT_CONTINUE;
1717 }
1718
CmdScriptWait(void)1719 static int CmdScriptWait(void)
1720 {
1721 ACSInfo[ACScript->infoIndex].waitValue = Pop();
1722 ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORSCRIPT;
1723 return SCRIPT_STOP;
1724 }
1725
CmdScriptWaitDirect(void)1726 static int CmdScriptWaitDirect(void)
1727 {
1728 ACSInfo[ACScript->infoIndex].waitValue = ReadCodeInt();
1729 ACSInfo[ACScript->infoIndex].state = ASTE_WAITINGFORSCRIPT;
1730 return SCRIPT_STOP;
1731 }
1732
CmdClearLineSpecial(void)1733 static int CmdClearLineSpecial(void)
1734 {
1735 if (ACScript->line)
1736 {
1737 ACScript->line->special = 0;
1738 }
1739 return SCRIPT_CONTINUE;
1740 }
1741
CmdCaseGoto(void)1742 static int CmdCaseGoto(void)
1743 {
1744 int value;
1745 int offset;
1746
1747 value = ReadCodeInt();
1748 offset = ReadOffset();
1749
1750 if (Top() == value)
1751 {
1752 PCodeOffset = offset;
1753 Drop();
1754 }
1755
1756 return SCRIPT_CONTINUE;
1757 }
1758
CmdBeginPrint(void)1759 static int CmdBeginPrint(void)
1760 {
1761 *PrintBuffer = 0;
1762 return SCRIPT_CONTINUE;
1763 }
1764
CmdEndPrint(void)1765 static int CmdEndPrint(void)
1766 {
1767 player_t *player;
1768
1769 if (ACScript->activator && ACScript->activator->player)
1770 {
1771 player = ACScript->activator->player;
1772 }
1773 else
1774 {
1775 player = &players[consoleplayer];
1776 }
1777 P_SetMessage(player, PrintBuffer, true);
1778 return SCRIPT_CONTINUE;
1779 }
1780
CmdEndPrintBold(void)1781 static int CmdEndPrintBold(void)
1782 {
1783 int i;
1784
1785 for (i = 0; i < maxplayers; i++)
1786 {
1787 if (playeringame[i])
1788 {
1789 P_SetYellowMessage(&players[i], PrintBuffer, true);
1790 }
1791 }
1792 return SCRIPT_CONTINUE;
1793 }
1794
CmdPrintString(void)1795 static int CmdPrintString(void)
1796 {
1797 M_StringConcat(PrintBuffer, StringLookup(Pop()), sizeof(PrintBuffer));
1798 return SCRIPT_CONTINUE;
1799 }
1800
CmdPrintNumber(void)1801 static int CmdPrintNumber(void)
1802 {
1803 char tempStr[16];
1804
1805 M_snprintf(tempStr, sizeof(tempStr), "%d", Pop());
1806 M_StringConcat(PrintBuffer, tempStr, sizeof(PrintBuffer));
1807 return SCRIPT_CONTINUE;
1808 }
1809
CmdPrintCharacter(void)1810 static int CmdPrintCharacter(void)
1811 {
1812 char tempStr[2];
1813
1814 tempStr[0] = Pop();
1815 tempStr[1] = '\0';
1816 M_StringConcat(PrintBuffer, tempStr, sizeof(PrintBuffer));
1817
1818 return SCRIPT_CONTINUE;
1819 }
1820
CmdPlayerCount(void)1821 static int CmdPlayerCount(void)
1822 {
1823 int i;
1824 int count;
1825
1826 count = 0;
1827 for (i = 0; i < maxplayers; i++)
1828 {
1829 count += playeringame[i];
1830 }
1831 Push(count);
1832 return SCRIPT_CONTINUE;
1833 }
1834
CmdGameType(void)1835 static int CmdGameType(void)
1836 {
1837 int gametype;
1838
1839 if (netgame == false)
1840 {
1841 gametype = GAME_SINGLE_PLAYER;
1842 }
1843 else if (deathmatch)
1844 {
1845 gametype = GAME_NET_DEATHMATCH;
1846 }
1847 else
1848 {
1849 gametype = GAME_NET_COOPERATIVE;
1850 }
1851 Push(gametype);
1852 return SCRIPT_CONTINUE;
1853 }
1854
CmdGameSkill(void)1855 static int CmdGameSkill(void)
1856 {
1857 Push(gameskill);
1858 return SCRIPT_CONTINUE;
1859 }
1860
CmdTimer(void)1861 static int CmdTimer(void)
1862 {
1863 Push(leveltime);
1864 return SCRIPT_CONTINUE;
1865 }
1866
CmdSectorSound(void)1867 static int CmdSectorSound(void)
1868 {
1869 int volume;
1870 mobj_t *mobj;
1871
1872 mobj = NULL;
1873 if (ACScript->line)
1874 {
1875 mobj = (mobj_t *) & ACScript->line->frontsector->soundorg;
1876 }
1877 volume = Pop();
1878 S_StartSoundAtVolume(mobj, S_GetSoundID(StringLookup(Pop())), volume);
1879 return SCRIPT_CONTINUE;
1880 }
1881
CmdThingSound(void)1882 static int CmdThingSound(void)
1883 {
1884 int tid;
1885 int sound;
1886 int volume;
1887 mobj_t *mobj;
1888 int searcher;
1889
1890 volume = Pop();
1891 sound = S_GetSoundID(StringLookup(Pop()));
1892 tid = Pop();
1893 searcher = -1;
1894 while ((mobj = P_FindMobjFromTID(tid, &searcher)) != NULL)
1895 {
1896 S_StartSoundAtVolume(mobj, sound, volume);
1897 }
1898 return SCRIPT_CONTINUE;
1899 }
1900
CmdAmbientSound(void)1901 static int CmdAmbientSound(void)
1902 {
1903 int volume;
1904
1905 volume = Pop();
1906 S_StartSoundAtVolume(NULL, S_GetSoundID(StringLookup(Pop())), volume);
1907 return SCRIPT_CONTINUE;
1908 }
1909
CmdSoundSequence(void)1910 static int CmdSoundSequence(void)
1911 {
1912 mobj_t *mobj;
1913
1914 mobj = NULL;
1915 if (ACScript->line)
1916 {
1917 mobj = (mobj_t *) & ACScript->line->frontsector->soundorg;
1918 }
1919 SN_StartSequenceName(mobj, StringLookup(Pop()));
1920 return SCRIPT_CONTINUE;
1921 }
1922
CmdSetLineTexture(void)1923 static int CmdSetLineTexture(void)
1924 {
1925 line_t *line;
1926 int lineTag;
1927 int side;
1928 int position;
1929 int texture;
1930 int searcher;
1931
1932 texture = R_TextureNumForName(StringLookup(Pop()));
1933 position = Pop();
1934 side = Pop();
1935 lineTag = Pop();
1936 searcher = -1;
1937 while ((line = P_FindLine(lineTag, &searcher)) != NULL)
1938 {
1939 if (position == TEXTURE_MIDDLE)
1940 {
1941 sides[line->sidenum[side]].midtexture = texture;
1942 }
1943 else if (position == TEXTURE_BOTTOM)
1944 {
1945 sides[line->sidenum[side]].bottomtexture = texture;
1946 }
1947 else
1948 { // TEXTURE_TOP
1949 sides[line->sidenum[side]].toptexture = texture;
1950 }
1951 }
1952 return SCRIPT_CONTINUE;
1953 }
1954
CmdSetLineBlocking(void)1955 static int CmdSetLineBlocking(void)
1956 {
1957 line_t *line;
1958 int lineTag;
1959 boolean blocking;
1960 int searcher;
1961
1962 blocking = Pop()? ML_BLOCKING : 0;
1963 lineTag = Pop();
1964 searcher = -1;
1965 while ((line = P_FindLine(lineTag, &searcher)) != NULL)
1966 {
1967 line->flags = (line->flags & ~ML_BLOCKING) | blocking;
1968 }
1969 return SCRIPT_CONTINUE;
1970 }
1971
CmdSetLineSpecial(void)1972 static int CmdSetLineSpecial(void)
1973 {
1974 line_t *line;
1975 int lineTag;
1976 int special, arg1, arg2, arg3, arg4, arg5;
1977 int searcher;
1978
1979 arg5 = Pop();
1980 arg4 = Pop();
1981 arg3 = Pop();
1982 arg2 = Pop();
1983 arg1 = Pop();
1984 special = Pop();
1985 lineTag = Pop();
1986 searcher = -1;
1987 while ((line = P_FindLine(lineTag, &searcher)) != NULL)
1988 {
1989 line->special = special;
1990 line->arg1 = arg1;
1991 line->arg2 = arg2;
1992 line->arg3 = arg3;
1993 line->arg4 = arg4;
1994 line->arg5 = arg5;
1995 }
1996 return SCRIPT_CONTINUE;
1997 }
1998