1 /*
2 ** p_acs.h
3 ** ACS script stuff
4 **
5 **---------------------------------------------------------------------------
6 ** Copyright 1998-2012 Randy Heit
7 ** All rights reserved.
8 **
9 ** Redistribution and use in source and binary forms, with or without
10 ** modification, are permitted provided that the following conditions
11 ** are met:
12 **
13 ** 1. Redistributions of source code must retain the above copyright
14 **    notice, this list of conditions and the following disclaimer.
15 ** 2. Redistributions in binary form must reproduce the above copyright
16 **    notice, this list of conditions and the following disclaimer in the
17 **    documentation and/or other materials provided with the distribution.
18 ** 3. The name of the author may not be used to endorse or promote products
19 **    derived from this software without specific prior written permission.
20 **
21 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 **---------------------------------------------------------------------------
32 **
33 */
34 
35 #ifndef __P_ACS_H__
36 #define __P_ACS_H__
37 
38 #include "dobject.h"
39 #include "dthinker.h"
40 #include "doomtype.h"
41 
42 #define LOCAL_SIZE				20
43 #define NUM_MAPVARS				128
44 
45 class FFont;
46 class FileReader;
47 
48 
49 enum
50 {
51 	NUM_WORLDVARS = 256,
52 	NUM_GLOBALVARS = 64
53 };
54 
55 struct InitIntToZero
56 {
InitInitIntToZero57 	void Init(int &v)
58 	{
59 		v = 0;
60 	}
61 };
62 typedef TMap<SDWORD, SDWORD, THashTraits<SDWORD>, InitIntToZero> FWorldGlobalArray;
63 
64 // ACS variables with world scope
65 extern SDWORD ACS_WorldVars[NUM_WORLDVARS];
66 extern FWorldGlobalArray ACS_WorldArrays[NUM_WORLDVARS];
67 
68 // ACS variables with global scope
69 extern SDWORD ACS_GlobalVars[NUM_GLOBALVARS];
70 extern FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS];
71 
72 #define LIBRARYID_MASK			0xFFF00000
73 #define LIBRARYID_SHIFT			20
74 
75 // Global ACS string table
76 #define STRPOOL_LIBRARYID		(INT_MAX >> LIBRARYID_SHIFT)
77 #define STRPOOL_LIBRARYID_OR	(STRPOOL_LIBRARYID << LIBRARYID_SHIFT)
78 
79 class ACSStringPool
80 {
81 public:
82 	ACSStringPool();
83 	int AddString(const char *str);
84 	int AddString(FString &str);
85 	const char *GetString(int strnum);
86 	void LockString(int strnum);
87 	void UnlockString(int strnum);
88 	void UnlockAll();
89 	void MarkString(int strnum);
90 	void LockStringArray(const int *strnum, unsigned int count);
91 	void UnlockStringArray(const int *strnum, unsigned int count);
92 	void MarkStringArray(const int *strnum, unsigned int count);
93 	void MarkStringMap(const FWorldGlobalArray &array);
94 	void PurgeStrings();
95 	void Clear();
96 	void Dump() const;
97 	void ReadStrings(PNGHandle *png, DWORD id);
98 	void WriteStrings(FILE *file, DWORD id) const;
99 
100 private:
101 	int FindString(const char *str, size_t len, unsigned int h, unsigned int bucketnum);
102 	int InsertString(FString &str, unsigned int h, unsigned int bucketnum);
103 	void FindFirstFreeEntry(unsigned int base);
104 
105 	enum { NUM_BUCKETS = 251 };
106 	enum { FREE_ENTRY = 0xFFFFFFFE };	// Stored in PoolEntry's Next field
107 	enum { NO_ENTRY = 0xFFFFFFFF };
108 	enum { MIN_GC_SIZE = 100 };			// Don't auto-collect until there are this many strings
109 	struct PoolEntry
110 	{
111 		FString Str;
112 		unsigned int Hash;
113 		unsigned int Next;
114 		unsigned int LockCount;
115 	};
116 	TArray<PoolEntry> Pool;
117 	unsigned int PoolBuckets[NUM_BUCKETS];
118 	unsigned int FirstFreeEntry;
119 };
120 extern ACSStringPool GlobalACSStrings;
121 
122 void P_CollectACSGlobalStrings();
123 void P_ReadACSVars(PNGHandle *);
124 void P_WriteACSVars(FILE*);
125 void P_ClearACSVars(bool);
126 void P_SerializeACSScriptNumber(FArchive &arc, int &scriptnum, bool was2byte);
127 
128 struct ACSProfileInfo
129 {
130 	unsigned long long TotalInstr;
131 	unsigned int NumRuns;
132 	unsigned int MinInstrPerRun;
133 	unsigned int MaxInstrPerRun;
134 
135 	ACSProfileInfo();
136 	void AddRun(unsigned int num_instr);
137 	void Reset();
138 };
139 
140 struct ProfileCollector
141 {
142 	ACSProfileInfo *ProfileData;
143 	class FBehavior *Module;
144 	int Index;
145 };
146 
147 struct ACSLocalArrayInfo
148 {
149 	unsigned int Size;
150 	int Offset;
151 };
152 
153 struct ACSLocalArrays
154 {
155 	unsigned int Count;
156 	ACSLocalArrayInfo *Info;
157 
ACSLocalArraysACSLocalArrays158 	ACSLocalArrays()
159 	{
160 		Count = 0;
161 		Info = NULL;
162 	}
~ACSLocalArraysACSLocalArrays163 	~ACSLocalArrays()
164 	{
165 		if (Info != NULL)
166 		{
167 			delete[] Info;
168 			Info = NULL;
169 		}
170 	}
171 
172 	// Bounds-checking Set and Get for local arrays
SetACSLocalArrays173 	void Set(int *locals, int arraynum, int arrayentry, int value)
174 	{
175 		if ((unsigned int)arraynum < Count &&
176 			(unsigned int)arrayentry < Info[arraynum].Size)
177 		{
178 			locals[Info[arraynum].Offset + arrayentry] = value;
179 		}
180 	}
GetACSLocalArrays181 	int Get(int *locals, int arraynum, int arrayentry)
182 	{
183 		if ((unsigned int)arraynum < Count &&
184 			(unsigned int)arrayentry < Info[arraynum].Size)
185 		{
186 			return locals[Info[arraynum].Offset + arrayentry];
187 		}
188 		return 0;
189 	}
190 };
191 
192 // The in-memory version
193 struct ScriptPtr
194 {
195 	int Number;
196 	DWORD Address;
197 	BYTE Type;
198 	BYTE ArgCount;
199 	WORD VarCount;
200 	WORD Flags;
201 	ACSLocalArrays LocalArrays;
202 
203 	ACSProfileInfo ProfileData;
204 };
205 
206 // The present ZDoom version
207 struct ScriptPtr3
208 {
209 	SWORD Number;
210 	BYTE Type;
211 	BYTE ArgCount;
212 	DWORD Address;
213 };
214 
215 // The intermediate ZDoom version
216 struct ScriptPtr1
217 {
218 	SWORD Number;
219 	WORD Type;
220 	DWORD Address;
221 	DWORD ArgCount;
222 };
223 
224 // The old Hexen version
225 struct ScriptPtr2
226 {
227 	DWORD Number;	// Type is Number / 1000
228 	DWORD Address;
229 	DWORD ArgCount;
230 };
231 
232 struct ScriptFlagsPtr
233 {
234 	WORD Number;
235 	WORD Flags;
236 };
237 
238 struct ScriptFunctionInFile
239 {
240 	BYTE ArgCount;
241 	BYTE LocalCount;
242 	BYTE HasReturnValue;
243 	BYTE ImportNum;
244 	DWORD Address;
245 };
246 
247 struct ScriptFunction
248 {
249 	BYTE ArgCount;
250 	BYTE HasReturnValue;
251 	BYTE ImportNum;
252 	int  LocalCount;
253 	DWORD Address;
254 	ACSLocalArrays LocalArrays;
255 };
256 
257 // Script types
258 enum
259 {
260 	SCRIPT_Closed		= 0,
261 	SCRIPT_Open			= 1,
262 	SCRIPT_Respawn		= 2,
263 	SCRIPT_Death		= 3,
264 	SCRIPT_Enter		= 4,
265 	SCRIPT_Pickup		= 5,
266 	SCRIPT_BlueReturn	= 6,
267 	SCRIPT_RedReturn	= 7,
268 	SCRIPT_WhiteReturn	= 8,
269 	SCRIPT_Lightning	= 12,
270 	SCRIPT_Unloading	= 13,
271 	SCRIPT_Disconnect	= 14,
272 	SCRIPT_Return		= 15,
273 };
274 
275 // Script flags
276 enum
277 {
278 	SCRIPTF_Net = 0x0001	// Safe to "puke" in multiplayer
279 };
280 
281 enum ACSFormat { ACS_Old, ACS_Enhanced, ACS_LittleEnhanced, ACS_Unknown };
282 
283 class FBehavior
284 {
285 public:
286 	FBehavior ();
287 	~FBehavior ();
288 	bool Init(int lumpnum, FileReader * fr = NULL, int len = 0);
289 
290 	bool IsGood ();
291 	BYTE *FindChunk (DWORD id) const;
292 	BYTE *NextChunk (BYTE *chunk) const;
293 	const ScriptPtr *FindScript (int number) const;
294 	void StartTypedScripts (WORD type, AActor *activator, bool always, int arg1, bool runNow);
PC2Ofs(int * pc)295 	DWORD PC2Ofs (int *pc) const { return (DWORD)((BYTE *)pc - Data); }
Ofs2PC(DWORD ofs)296 	int *Ofs2PC (DWORD ofs) const {	return (int *)(Data + ofs); }
Jump2PC(DWORD jumpPoint)297 	int *Jump2PC (DWORD jumpPoint) const { return Ofs2PC(JumpPoints[jumpPoint]); }
GetFormat()298 	ACSFormat GetFormat() const { return Format; }
299 	ScriptFunction *GetFunction (int funcnum, FBehavior *&module) const;
300 	int GetArrayVal (int arraynum, int index) const;
301 	void SetArrayVal (int arraynum, int index, int value);
302 	inline bool CopyStringToArray(int arraynum, int index, int maxLength, const char * string);
303 
304 	int FindFunctionName (const char *funcname) const;
305 	int FindMapVarName (const char *varname) const;
306 	int FindMapArray (const char *arrayname) const;
GetLibraryID()307 	int GetLibraryID () const { return LibraryID; }
GetScriptAddress(const ScriptPtr * ptr)308 	int *GetScriptAddress (const ScriptPtr *ptr) const { return (int *)(ptr->Address + Data); }
GetScriptIndex(const ScriptPtr * ptr)309 	int GetScriptIndex (const ScriptPtr *ptr) const { ptrdiff_t index = ptr - Scripts; return index >= NumScripts ? -1 : (int)index; }
GetScriptPtr(int index)310 	ScriptPtr *GetScriptPtr(int index) const { return index >= 0 && index < NumScripts ? &Scripts[index] : NULL; }
GetLumpNum()311 	int GetLumpNum() const { return LumpNum; }
GetDataSize()312 	int GetDataSize() const { return DataSize; }
GetModuleName()313 	const char *GetModuleName() const { return ModuleName; }
GetFunctionProfileData(int index)314 	ACSProfileInfo *GetFunctionProfileData(int index) { return index >= 0 && index < NumFunctions ? &FunctionProfileData[index] : NULL; }
GetFunctionProfileData(ScriptFunction * func)315 	ACSProfileInfo *GetFunctionProfileData(ScriptFunction *func) { return GetFunctionProfileData((int)(func - (ScriptFunction *)Functions)); }
316 	const char *LookupString (DWORD index) const;
317 
318 	SDWORD *MapVars[NUM_MAPVARS];
319 
320 	static FBehavior *StaticLoadModule (int lumpnum, FileReader * fr=NULL, int len=0);
321 	static void StaticLoadDefaultModules ();
322 	static void StaticUnloadModules ();
323 	static bool StaticCheckAllGood ();
324 	static FBehavior *StaticGetModule (int lib);
325 	static void StaticSerializeModuleStates (FArchive &arc);
326 	static void StaticMarkLevelVarStrings();
327 	static void StaticLockLevelVarStrings();
328 	static void StaticUnlockLevelVarStrings();
329 
330 	static const ScriptPtr *StaticFindScript (int script, FBehavior *&module);
331 	static const char *StaticLookupString (DWORD index);
332 	static void StaticStartTypedScripts (WORD type, AActor *activator, bool always, int arg1=0, bool runNow=false);
333 	static void StaticStopMyScripts (AActor *actor);
334 
335 private:
336 	struct ArrayInfo;
337 
338 	ACSFormat Format;
339 
340 	int LumpNum;
341 	BYTE *Data;
342 	int DataSize;
343 	BYTE *Chunks;
344 	ScriptPtr *Scripts;
345 	int NumScripts;
346 	ScriptFunction *Functions;
347 	ACSProfileInfo *FunctionProfileData;
348 	int NumFunctions;
349 	ArrayInfo *ArrayStore;
350 	int NumArrays;
351 	ArrayInfo **Arrays;
352 	int NumTotalArrays;
353 	DWORD StringTable;
354 	SDWORD MapVarStore[NUM_MAPVARS];
355 	TArray<FBehavior *> Imports;
356 	DWORD LibraryID;
357 	char ModuleName[9];
358 	TArray<int> JumpPoints;
359 
360 	static TArray<FBehavior *> StaticModules;
361 
362 	void LoadScriptsDirectory ();
363 
364 	static int STACK_ARGS SortScripts (const void *a, const void *b);
365 	void UnencryptStrings ();
366 	void UnescapeStringTable(BYTE *chunkstart, BYTE *datastart, bool haspadding);
367 	int FindStringInChunk (DWORD *chunk, const char *varname) const;
368 
369 	void SerializeVars (FArchive &arc);
370 	void SerializeVarSet (FArchive &arc, SDWORD *vars, int max);
371 
372 	void MarkMapVarStrings() const;
373 	void LockMapVarStrings() const;
374 	void UnlockMapVarStrings() const;
375 
376 	friend void ArrangeScriptProfiles(TArray<ProfileCollector> &profiles);
377 	friend void ArrangeFunctionProfiles(TArray<ProfileCollector> &profiles);
378 };
379 
380 class DLevelScript : public DObject
381 {
382 	DECLARE_CLASS (DLevelScript, DObject)
383 	HAS_OBJECT_POINTERS
384 public:
385 
386 	// P-codes for ACS scripts
387 	enum
388 	{
389 /*  0*/	PCD_NOP,
390 		PCD_TERMINATE,
391 		PCD_SUSPEND,
392 		PCD_PUSHNUMBER,
393 		PCD_LSPEC1,
394 		PCD_LSPEC2,
395 		PCD_LSPEC3,
396 		PCD_LSPEC4,
397 		PCD_LSPEC5,
398 		PCD_LSPEC1DIRECT,
399 /* 10*/	PCD_LSPEC2DIRECT,
400 		PCD_LSPEC3DIRECT,
401 		PCD_LSPEC4DIRECT,
402 		PCD_LSPEC5DIRECT,
403 		PCD_ADD,
404 		PCD_SUBTRACT,
405 		PCD_MULTIPLY,
406 		PCD_DIVIDE,
407 		PCD_MODULUS,
408 		PCD_EQ,
409 /* 20*/ PCD_NE,
410 		PCD_LT,
411 		PCD_GT,
412 		PCD_LE,
413 		PCD_GE,
414 		PCD_ASSIGNSCRIPTVAR,
415 		PCD_ASSIGNMAPVAR,
416 		PCD_ASSIGNWORLDVAR,
417 		PCD_PUSHSCRIPTVAR,
418 		PCD_PUSHMAPVAR,
419 /* 30*/	PCD_PUSHWORLDVAR,
420 		PCD_ADDSCRIPTVAR,
421 		PCD_ADDMAPVAR,
422 		PCD_ADDWORLDVAR,
423 		PCD_SUBSCRIPTVAR,
424 		PCD_SUBMAPVAR,
425 		PCD_SUBWORLDVAR,
426 		PCD_MULSCRIPTVAR,
427 		PCD_MULMAPVAR,
428 		PCD_MULWORLDVAR,
429 /* 40*/	PCD_DIVSCRIPTVAR,
430 		PCD_DIVMAPVAR,
431 		PCD_DIVWORLDVAR,
432 		PCD_MODSCRIPTVAR,
433 		PCD_MODMAPVAR,
434 		PCD_MODWORLDVAR,
435 		PCD_INCSCRIPTVAR,
436 		PCD_INCMAPVAR,
437 		PCD_INCWORLDVAR,
438 		PCD_DECSCRIPTVAR,
439 /* 50*/	PCD_DECMAPVAR,
440 		PCD_DECWORLDVAR,
441 		PCD_GOTO,
442 		PCD_IFGOTO,
443 		PCD_DROP,
444 		PCD_DELAY,
445 		PCD_DELAYDIRECT,
446 		PCD_RANDOM,
447 		PCD_RANDOMDIRECT,
448 		PCD_THINGCOUNT,
449 /* 60*/	PCD_THINGCOUNTDIRECT,
450 		PCD_TAGWAIT,
451 		PCD_TAGWAITDIRECT,
452 		PCD_POLYWAIT,
453 		PCD_POLYWAITDIRECT,
454 		PCD_CHANGEFLOOR,
455 		PCD_CHANGEFLOORDIRECT,
456 		PCD_CHANGECEILING,
457 		PCD_CHANGECEILINGDIRECT,
458 		PCD_RESTART,
459 /* 70*/	PCD_ANDLOGICAL,
460 		PCD_ORLOGICAL,
461 		PCD_ANDBITWISE,
462 		PCD_ORBITWISE,
463 		PCD_EORBITWISE,
464 		PCD_NEGATELOGICAL,
465 		PCD_LSHIFT,
466 		PCD_RSHIFT,
467 		PCD_UNARYMINUS,
468 		PCD_IFNOTGOTO,
469 /* 80*/	PCD_LINESIDE,
470 		PCD_SCRIPTWAIT,
471 		PCD_SCRIPTWAITDIRECT,
472 		PCD_CLEARLINESPECIAL,
473 		PCD_CASEGOTO,
474 		PCD_BEGINPRINT,
475 		PCD_ENDPRINT,
476 		PCD_PRINTSTRING,
477 		PCD_PRINTNUMBER,
478 		PCD_PRINTCHARACTER,
479 /* 90*/	PCD_PLAYERCOUNT,
480 		PCD_GAMETYPE,
481 		PCD_GAMESKILL,
482 		PCD_TIMER,
483 		PCD_SECTORSOUND,
484 		PCD_AMBIENTSOUND,
485 		PCD_SOUNDSEQUENCE,
486 		PCD_SETLINETEXTURE,
487 		PCD_SETLINEBLOCKING,
488 		PCD_SETLINESPECIAL,
489 /*100*/	PCD_THINGSOUND,
490 		PCD_ENDPRINTBOLD,		// [RH] End of Hexen p-codes
491 		PCD_ACTIVATORSOUND,
492 		PCD_LOCALAMBIENTSOUND,
493 		PCD_SETLINEMONSTERBLOCKING,
494 		PCD_PLAYERBLUESKULL,	// [BC] Start of new [Skull Tag] pcodes
495 		PCD_PLAYERREDSKULL,
496 		PCD_PLAYERYELLOWSKULL,
497 		PCD_PLAYERMASTERSKULL,
498 		PCD_PLAYERBLUECARD,
499 /*110*/	PCD_PLAYERREDCARD,
500 		PCD_PLAYERYELLOWCARD,
501 		PCD_PLAYERMASTERCARD,
502 		PCD_PLAYERBLACKSKULL,
503 		PCD_PLAYERSILVERSKULL,
504 		PCD_PLAYERGOLDSKULL,
505 		PCD_PLAYERBLACKCARD,
506 		PCD_PLAYERSILVERCARD,
507 		PCD_PLAYERONTEAM,
508 		PCD_PLAYERTEAM,
509 /*120*/	PCD_PLAYERHEALTH,
510 		PCD_PLAYERARMORPOINTS,
511 		PCD_PLAYERFRAGS,
512 		PCD_PLAYEREXPERT,
513 		PCD_BLUETEAMCOUNT,
514 		PCD_REDTEAMCOUNT,
515 		PCD_BLUETEAMSCORE,
516 		PCD_REDTEAMSCORE,
517 		PCD_ISONEFLAGCTF,
518 		PCD_LSPEC6,				// These are never used. They should probably
519 /*130*/	PCD_LSPEC6DIRECT,		// be given names like PCD_DUMMY.
520 		PCD_PRINTNAME,
521 		PCD_MUSICCHANGE,
522 		PCD_TEAM2FRAGPOINTS,
523 		PCD_CONSOLECOMMAND,
524 		PCD_SINGLEPLAYER,		// [RH] End of Skull Tag p-codes
525 		PCD_FIXEDMUL,
526 		PCD_FIXEDDIV,
527 		PCD_SETGRAVITY,
528 		PCD_SETGRAVITYDIRECT,
529 /*140*/	PCD_SETAIRCONTROL,
530 		PCD_SETAIRCONTROLDIRECT,
531 		PCD_CLEARINVENTORY,
532 		PCD_GIVEINVENTORY,
533 		PCD_GIVEINVENTORYDIRECT,
534 		PCD_TAKEINVENTORY,
535 		PCD_TAKEINVENTORYDIRECT,
536 		PCD_CHECKINVENTORY,
537 		PCD_CHECKINVENTORYDIRECT,
538 		PCD_SPAWN,
539 /*150*/	PCD_SPAWNDIRECT,
540 		PCD_SPAWNSPOT,
541 		PCD_SPAWNSPOTDIRECT,
542 		PCD_SETMUSIC,
543 		PCD_SETMUSICDIRECT,
544 		PCD_LOCALSETMUSIC,
545 		PCD_LOCALSETMUSICDIRECT,
546 		PCD_PRINTFIXED,
547 		PCD_PRINTLOCALIZED,
548 		PCD_MOREHUDMESSAGE,
549 /*160*/	PCD_OPTHUDMESSAGE,
550 		PCD_ENDHUDMESSAGE,
551 		PCD_ENDHUDMESSAGEBOLD,
552 		PCD_SETSTYLE,
553 		PCD_SETSTYLEDIRECT,
554 		PCD_SETFONT,
555 		PCD_SETFONTDIRECT,
556 		PCD_PUSHBYTE,
557 		PCD_LSPEC1DIRECTB,
558 		PCD_LSPEC2DIRECTB,
559 /*170*/	PCD_LSPEC3DIRECTB,
560 		PCD_LSPEC4DIRECTB,
561 		PCD_LSPEC5DIRECTB,
562 		PCD_DELAYDIRECTB,
563 		PCD_RANDOMDIRECTB,
564 		PCD_PUSHBYTES,
565 		PCD_PUSH2BYTES,
566 		PCD_PUSH3BYTES,
567 		PCD_PUSH4BYTES,
568 		PCD_PUSH5BYTES,
569 /*180*/	PCD_SETTHINGSPECIAL,
570 		PCD_ASSIGNGLOBALVAR,
571 		PCD_PUSHGLOBALVAR,
572 		PCD_ADDGLOBALVAR,
573 		PCD_SUBGLOBALVAR,
574 		PCD_MULGLOBALVAR,
575 		PCD_DIVGLOBALVAR,
576 		PCD_MODGLOBALVAR,
577 		PCD_INCGLOBALVAR,
578 		PCD_DECGLOBALVAR,
579 /*190*/	PCD_FADETO,
580 		PCD_FADERANGE,
581 		PCD_CANCELFADE,
582 		PCD_PLAYMOVIE,
583 		PCD_SETFLOORTRIGGER,
584 		PCD_SETCEILINGTRIGGER,
585 		PCD_GETACTORX,
586 		PCD_GETACTORY,
587 		PCD_GETACTORZ,
588 		PCD_STARTTRANSLATION,
589 /*200*/	PCD_TRANSLATIONRANGE1,
590 		PCD_TRANSLATIONRANGE2,
591 		PCD_ENDTRANSLATION,
592 		PCD_CALL,
593 		PCD_CALLDISCARD,
594 		PCD_RETURNVOID,
595 		PCD_RETURNVAL,
596 		PCD_PUSHMAPARRAY,
597 		PCD_ASSIGNMAPARRAY,
598 		PCD_ADDMAPARRAY,
599 /*210*/	PCD_SUBMAPARRAY,
600 		PCD_MULMAPARRAY,
601 		PCD_DIVMAPARRAY,
602 		PCD_MODMAPARRAY,
603 		PCD_INCMAPARRAY,
604 		PCD_DECMAPARRAY,
605 		PCD_DUP,
606 		PCD_SWAP,
607 		PCD_WRITETOINI,
608 		PCD_GETFROMINI,
609 /*220*/ PCD_SIN,
610 		PCD_COS,
611 		PCD_VECTORANGLE,
612 		PCD_CHECKWEAPON,
613 		PCD_SETWEAPON,
614 		PCD_TAGSTRING,
615 		PCD_PUSHWORLDARRAY,
616 		PCD_ASSIGNWORLDARRAY,
617 		PCD_ADDWORLDARRAY,
618 		PCD_SUBWORLDARRAY,
619 /*230*/	PCD_MULWORLDARRAY,
620 		PCD_DIVWORLDARRAY,
621 		PCD_MODWORLDARRAY,
622 		PCD_INCWORLDARRAY,
623 		PCD_DECWORLDARRAY,
624 		PCD_PUSHGLOBALARRAY,
625 		PCD_ASSIGNGLOBALARRAY,
626 		PCD_ADDGLOBALARRAY,
627 		PCD_SUBGLOBALARRAY,
628 		PCD_MULGLOBALARRAY,
629 /*240*/	PCD_DIVGLOBALARRAY,
630 		PCD_MODGLOBALARRAY,
631 		PCD_INCGLOBALARRAY,
632 		PCD_DECGLOBALARRAY,
633 		PCD_SETMARINEWEAPON,
634 		PCD_SETACTORPROPERTY,
635 		PCD_GETACTORPROPERTY,
636 		PCD_PLAYERNUMBER,
637 		PCD_ACTIVATORTID,
638 		PCD_SETMARINESPRITE,
639 /*250*/	PCD_GETSCREENWIDTH,
640 		PCD_GETSCREENHEIGHT,
641 		PCD_THING_PROJECTILE2,
642 		PCD_STRLEN,
643 		PCD_SETHUDSIZE,
644 		PCD_GETCVAR,
645 		PCD_CASEGOTOSORTED,
646 		PCD_SETRESULTVALUE,
647 		PCD_GETLINEROWOFFSET,
648 		PCD_GETACTORFLOORZ,
649 /*260*/	PCD_GETACTORANGLE,
650 		PCD_GETSECTORFLOORZ,
651 		PCD_GETSECTORCEILINGZ,
652 		PCD_LSPEC5RESULT,
653 		PCD_GETSIGILPIECES,
654 		PCD_GETLEVELINFO,
655 		PCD_CHANGESKY,
656 		PCD_PLAYERINGAME,
657 		PCD_PLAYERISBOT,
658 		PCD_SETCAMERATOTEXTURE,
659 /*270*/	PCD_ENDLOG,
660 		PCD_GETAMMOCAPACITY,
661 		PCD_SETAMMOCAPACITY,
662 		PCD_PRINTMAPCHARARRAY,		// [JB] start of new p-codes
663 		PCD_PRINTWORLDCHARARRAY,
664 		PCD_PRINTGLOBALCHARARRAY,	// [JB] end of new p-codes
665 		PCD_SETACTORANGLE,			// [GRB]
666 		PCD_GRABINPUT,				// Unused but acc defines them
667 		PCD_SETMOUSEPOINTER,		// "
668 		PCD_MOVEMOUSEPOINTER,		// "
669 /*280*/	PCD_SPAWNPROJECTILE,
670 		PCD_GETSECTORLIGHTLEVEL,
671 		PCD_GETACTORCEILINGZ,
672 		PCD_SETACTORPOSITION,
673 		PCD_CLEARACTORINVENTORY,
674 		PCD_GIVEACTORINVENTORY,
675 		PCD_TAKEACTORINVENTORY,
676 		PCD_CHECKACTORINVENTORY,
677 		PCD_THINGCOUNTNAME,
678 		PCD_SPAWNSPOTFACING,
679 /*290*/	PCD_PLAYERCLASS,			// [GRB]
680 		//[MW] start my p-codes
681 		PCD_ANDSCRIPTVAR,
682 		PCD_ANDMAPVAR,
683 		PCD_ANDWORLDVAR,
684 		PCD_ANDGLOBALVAR,
685 		PCD_ANDMAPARRAY,
686 		PCD_ANDWORLDARRAY,
687 		PCD_ANDGLOBALARRAY,
688 		PCD_EORSCRIPTVAR,
689 		PCD_EORMAPVAR,
690 /*300*/	PCD_EORWORLDVAR,
691 		PCD_EORGLOBALVAR,
692 		PCD_EORMAPARRAY,
693 		PCD_EORWORLDARRAY,
694 		PCD_EORGLOBALARRAY,
695 		PCD_ORSCRIPTVAR,
696 		PCD_ORMAPVAR,
697 		PCD_ORWORLDVAR,
698 		PCD_ORGLOBALVAR,
699 		PCD_ORMAPARRAY,
700 /*310*/	PCD_ORWORLDARRAY,
701 		PCD_ORGLOBALARRAY,
702 		PCD_LSSCRIPTVAR,
703 		PCD_LSMAPVAR,
704 		PCD_LSWORLDVAR,
705 		PCD_LSGLOBALVAR,
706 		PCD_LSMAPARRAY,
707 		PCD_LSWORLDARRAY,
708 		PCD_LSGLOBALARRAY,
709 		PCD_RSSCRIPTVAR,
710 /*320*/	PCD_RSMAPVAR,
711 		PCD_RSWORLDVAR,
712 		PCD_RSGLOBALVAR,
713 		PCD_RSMAPARRAY,
714 		PCD_RSWORLDARRAY,
715 		PCD_RSGLOBALARRAY,
716 		//[MW] end my p-codes
717 		PCD_GETPLAYERINFO,			// [GRB]
718 		PCD_CHANGELEVEL,
719 		PCD_SECTORDAMAGE,
720 		PCD_REPLACETEXTURES,
721 /*330*/	PCD_NEGATEBINARY,
722 		PCD_GETACTORPITCH,
723 		PCD_SETACTORPITCH,
724 		PCD_PRINTBIND,
725 		PCD_SETACTORSTATE,
726 		PCD_THINGDAMAGE2,
727 		PCD_USEINVENTORY,
728 		PCD_USEACTORINVENTORY,
729 		PCD_CHECKACTORCEILINGTEXTURE,
730 		PCD_CHECKACTORFLOORTEXTURE,
731 /*340*/	PCD_GETACTORLIGHTLEVEL,
732 		PCD_SETMUGSHOTSTATE,
733 		PCD_THINGCOUNTSECTOR,
734 		PCD_THINGCOUNTNAMESECTOR,
735 		PCD_CHECKPLAYERCAMERA,		// [TN]
736 		PCD_MORPHACTOR,				// [MH]
737 		PCD_UNMORPHACTOR,			// [MH]
738 		PCD_GETPLAYERINPUT,
739 		PCD_CLASSIFYACTOR,
740 		PCD_PRINTBINARY,
741 /*350*/	PCD_PRINTHEX,
742 		PCD_CALLFUNC,
743 		PCD_SAVESTRING,			// [FDARI] create string (temporary)
744 		PCD_PRINTMAPCHRANGE,	// [FDARI] output range (print part of array)
745 		PCD_PRINTWORLDCHRANGE,
746 		PCD_PRINTGLOBALCHRANGE,
747 		PCD_STRCPYTOMAPCHRANGE,	// [FDARI] input range (copy string to all/part of array)
748 		PCD_STRCPYTOWORLDCHRANGE,
749 		PCD_STRCPYTOGLOBALCHRANGE,
750 		PCD_PUSHFUNCTION,		// from Eternity
751 /*360*/	PCD_CALLSTACK,			// from Eternity
752 		PCD_SCRIPTWAITNAMED,
753 		PCD_TRANSLATIONRANGE3,
754 		PCD_GOTOSTACK,
755 		PCD_ASSIGNSCRIPTARRAY,
756 		PCD_PUSHSCRIPTARRAY,
757 		PCD_ADDSCRIPTARRAY,
758 		PCD_SUBSCRIPTARRAY,
759 		PCD_MULSCRIPTARRAY,
760 		PCD_DIVSCRIPTARRAY,
761 /*370*/	PCD_MODSCRIPTARRAY,
762 		PCD_INCSCRIPTARRAY,
763 		PCD_DECSCRIPTARRAY,
764 		PCD_ANDSCRIPTARRAY,
765 		PCD_EORSCRIPTARRAY,
766 		PCD_ORSCRIPTARRAY,
767 		PCD_LSSCRIPTARRAY,
768 		PCD_RSSCRIPTARRAY,
769 		PCD_PRINTSCRIPTCHARARRAY,
770 		PCD_PRINTSCRIPTCHRANGE,
771 /*380*/	PCD_STRCPYTOSCRIPTCHRANGE,
772 
773 /*381*/	PCODE_COMMAND_COUNT
774 	};
775 
776 	// Some constants used by ACS scripts
777 	enum {
778 		LINE_FRONT =			0,
779 		LINE_BACK =				1
780 	};
781 	enum {
782 		SIDE_FRONT =			0,
783 		SIDE_BACK =				1
784 	};
785 	enum {
786 		TEXTURE_TOP =			0,
787 		TEXTURE_MIDDLE =		1,
788 		TEXTURE_BOTTOM =		2
789 	};
790 	enum {
791 		GAME_SINGLE_PLAYER =	0,
792 		GAME_NET_COOPERATIVE =	1,
793 		GAME_NET_DEATHMATCH =	2,
794 		GAME_TITLE_MAP =		3
795 	};
796 	enum {
797 		CLASS_FIGHTER =			0,
798 		CLASS_CLERIC =			1,
799 		CLASS_MAGE =			2
800 	};
801 	enum {
802 		SKILL_VERY_EASY =		0,
803 		SKILL_EASY =			1,
804 		SKILL_NORMAL =			2,
805 		SKILL_HARD =			3,
806 		SKILL_VERY_HARD =		4
807 	};
808 	enum {
809 		BLOCK_NOTHING =			0,
810 		BLOCK_CREATURES =		1,
811 		BLOCK_EVERYTHING =		2,
812 		BLOCK_RAILING =			3,
813 		BLOCK_PLAYERS =			4
814 	};
815 	enum {
816 		LEVELINFO_PAR_TIME,
817 		LEVELINFO_CLUSTERNUM,
818 		LEVELINFO_LEVELNUM,
819 		LEVELINFO_TOTAL_SECRETS,
820 		LEVELINFO_FOUND_SECRETS,
821 		LEVELINFO_TOTAL_ITEMS,
822 		LEVELINFO_FOUND_ITEMS,
823 		LEVELINFO_TOTAL_MONSTERS,
824 		LEVELINFO_KILLED_MONSTERS,
825 		LEVELINFO_SUCK_TIME
826 	};
827 	enum {
828 		PLAYERINFO_TEAM,
829 		PLAYERINFO_AIMDIST,
830 		PLAYERINFO_COLOR,
831 		PLAYERINFO_GENDER,
832 		PLAYERINFO_NEVERSWITCH,
833 		PLAYERINFO_MOVEBOB,
834 		PLAYERINFO_STILLBOB,
835 		PLAYERINFO_PLAYERCLASS,
836 		PLAYERINFO_FOV,
837 		PLAYERINFO_DESIREDFOV,
838 	};
839 
840 	enum EScriptState
841 	{
842 		SCRIPT_Running,
843 		SCRIPT_Suspended,
844 		SCRIPT_Delayed,
845 		SCRIPT_TagWait,
846 		SCRIPT_PolyWait,
847 		SCRIPT_ScriptWaitPre,
848 		SCRIPT_ScriptWait,
849 		SCRIPT_PleaseRemove,
850 		SCRIPT_DivideBy0,
851 		SCRIPT_ModulusBy0,
852 	};
853 
854 	DLevelScript (AActor *who, line_t *where, int num, const ScriptPtr *code, FBehavior *module,
855 		const int *args, int argcount, int flags);
856 	~DLevelScript ();
857 
858 	void Serialize (FArchive &arc);
859 	int RunScript ();
860 
SetState(EScriptState newstate)861 	inline void SetState (EScriptState newstate) { state = newstate; }
GetState()862 	inline EScriptState GetState () { return state; }
863 
GetNext()864 	DLevelScript *GetNext() const { return next; }
865 
MarkLocalVarStrings()866 	void MarkLocalVarStrings() const
867 	{
868 		GlobalACSStrings.MarkStringArray(localvars, numlocalvars);
869 	}
LockLocalVarStrings()870 	void LockLocalVarStrings() const
871 	{
872 		GlobalACSStrings.LockStringArray(localvars, numlocalvars);
873 	}
UnlockLocalVarStrings()874 	void UnlockLocalVarStrings() const
875 	{
876 		GlobalACSStrings.UnlockStringArray(localvars, numlocalvars);
877 	}
878 
879 protected:
880 	DLevelScript	*next, *prev;
881 	int				script;
882 	SDWORD			*localvars;
883 	int				numlocalvars;
884 	int				*pc;
885 	EScriptState	state;
886 	int				statedata;
887 	TObjPtr<AActor>	activator;
888 	line_t			*activationline;
889 	bool			backSide;
890 	FFont			*activefont;
891 	int				hudwidth, hudheight;
892 	int				ClipRectLeft, ClipRectTop, ClipRectWidth, ClipRectHeight;
893 	int				WrapWidth;
894 	bool			HandleAspect;
895 	FBehavior	    *activeBehavior;
896 	int				InModuleScriptNumber;
897 
898 	void Link ();
899 	void Unlink ();
900 	void PutLast ();
901 	void PutFirst ();
902 	static int Random (int min, int max);
903 	static int ThingCount (int type, int stringid, int tid, int tag);
904 	static void ChangeFlat (int tag, int name, bool floorOrCeiling);
905 	static int CountPlayers ();
906 	static void SetLineTexture (int lineid, int side, int position, int name);
907 	static void ReplaceTextures (int fromname, int toname, int flags);
908 	static int DoSpawn (int type, fixed_t x, fixed_t y, fixed_t z, int tid, int angle, bool force);
909 	static bool DoCheckActorTexture(int tid, AActor *activator, int string, bool floor);
910 	int DoSpawnSpot (int type, int spot, int tid, int angle, bool forced);
911 	int DoSpawnSpotFacing (int type, int spot, int tid, bool forced);
912 	int DoClassifyActor (int tid);
913 	int CallFunction(int argCount, int funcIndex, SDWORD *args);
914 
915 	void DoFadeTo (int r, int g, int b, int a, fixed_t time);
916 	void DoFadeRange (int r1, int g1, int b1, int a1,
917 		int r2, int g2, int b2, int a2, fixed_t time);
918 	void DoSetFont (int fontnum);
919 	void SetActorProperty (int tid, int property, int value);
920 	void DoSetActorProperty (AActor *actor, int property, int value);
921 	int GetActorProperty (int tid, int property);
922 	int CheckActorProperty (int tid, int property, int value);
923 	int GetPlayerInput (int playernum, int inputnum);
924 
925 	int LineFromID(int id);
926 	int SideFromID(int id, int side);
927 
928 private:
929 	DLevelScript ();
930 
931 	friend class DACSThinker;
932 };
933 
934 class DACSThinker : public DThinker
935 {
936 	DECLARE_CLASS (DACSThinker, DThinker)
937 	HAS_OBJECT_POINTERS
938 public:
939 	DACSThinker ();
940 	~DACSThinker ();
941 
942 	void Serialize (FArchive &arc);
943 	void Tick ();
944 
945 	typedef TMap<int, DLevelScript *> ScriptMap;
946 	ScriptMap RunningScripts;	// Array of all synchronous scripts
947 	static TObjPtr<DACSThinker> ActiveThinker;
948 
949 	void DumpScriptStatus();
950 	void StopScriptsFor (AActor *actor);
951 
952 private:
953 	DLevelScript *LastScript;
954 	DLevelScript *Scripts;				// List of all running scripts
955 
956 	friend class DLevelScript;
957 	friend class FBehavior;
958 };
959 
960 // The structure used to control scripts between maps
961 struct acsdefered_t
962 {
963 	struct acsdefered_t *next;
964 
965 	enum EType
966 	{
967 		defexecute,
968 		defexealways,
969 		defsuspend,
970 		defterminate
971 	} type;
972 	int script;
973 	int args[3];
974 	int playernum;
975 };
976 
977 FArchive &operator<< (FArchive &arc, acsdefered_t *&defer);
978 
979 #endif //__P_ACS_H__
980