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