1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: p_acs.cpp 4542 2014-02-09 17:39:42Z dr_sean $
5 //
6 // Copyright (C) 1998-2006 by Randy Heit (ZDoom).
7 // Copyright (C) 2006-2014 by The Odamex Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 // DESCRIPTION:
20 //	[RH] p_acs.c: New file to handle ACS scripts
21 //
22 //-----------------------------------------------------------------------------
23 //
24 
25 #include "z_zone.h"
26 #include "doomdef.h"
27 #include "p_local.h"
28 #include "p_spec.h"
29 #include "g_level.h"
30 #include "s_sound.h"
31 #include "p_acs.h"
32 #include "p_saveg.h"
33 #include "p_lnspec.h"
34 #include "m_random.h"
35 #include "doomstat.h"
36 #include "c_console.h"
37 #include "c_dispatch.h"
38 #include "s_sndseq.h"
39 #include "i_system.h"
40 #include "m_vectors.h"
41 
42 #define CLAMPCOLOR(c)	(EColorRange)((unsigned)(c)>CR_UNTRANSLATED?CR_UNTRANSLATED:(c))
43 #define LANGREGIONMASK	MAKE_ID(0,0,0xff,0xff)
44 
45 struct CallReturn
46 {
47 	int ReturnAddress;
48 	ScriptFunction *ReturnFunction;
49 	BYTE bDiscardResult;
50 	BYTE Pad[3];
51 };
52 
53 static int Stack[STACK_SIZE];
54 
55 static bool P_GetScriptGoing (AActor *who, line_t *where, int num, int *code,
56 	int lineSide, int arg0, int arg1, int arg2, int always, bool delay);
57 
58 struct FBehavior::ArrayInfo
59 {
60 	int ArraySize;
61 	SDWORD *Elements;
62 };
63 
64 // Inventory shim for Doom.
65 #include "gi.h"
66 
67 void SV_SendPlayerInfo(player_t &player);
68 
DoClearInv(player_t * player)69 static void DoClearInv(player_t* player)
70 {
71 	memset(player->weaponowned, 0, sizeof(player->weaponowned));
72 	memset(player->powers, 0, sizeof(player->powers));
73 	memset(player->cards, 0, sizeof(player->cards));
74 	memset(player->ammo, 0, sizeof(player->ammo));
75 
76 	if (player->backpack)
77 	{
78 		player->backpack = false;
79 		for (int i = 0; i < NUMAMMO; i++)
80 		{
81 			player->maxammo[i] /= 2;
82 		}
83 	}
84 
85 	player->pendingweapon = NUMWEAPONS;
86 }
87 
ClearInventory(AActor * activator)88 static void ClearInventory(AActor* activator)
89 {
90 	if (activator == NULL)
91 	{
92 		Players::iterator it;
93 		for (it = players.begin();it != players.end();++it)
94 		{
95 			if (it->ingame() && !it->spectator)
96 				DoClearInv(&(*it));
97 				SV_SendPlayerInfo(*it);
98 		}
99 	}
100 	else if (activator->player != NULL)
101 	{
102 		DoClearInv(activator->player);
103 		SV_SendPlayerInfo(*(activator->player));
104 	}
105 }
106 
107 static const char* DoomAmmoNames[4] =
108 {
109 	"Clip", "Shell", "Cell", "RocketAmmo"
110 };
111 static const char* DoomWeaponNames[9] =
112 {
113 	"Fist", "Pistol", "Shotgun", "Chaingun", "RocketLauncher",
114 	"PlasmaRifle", "BFG9000", "Chainsaw", "SuperShotgun"
115 };
116 static const char* DoomKeyNames[6] =
117 {
118 	"BlueCard", "YellowCard", "RedCard",
119 	"BlueSkull", "YellowSkull", "RedSkull"
120 };
121 static const char* DoomPowerNames[7] =
122 {
123 	"InvulnerabilitySphere", "Berserk", "BlurSphere",
124 	"RadSuit", "Allmap", "Infrared"
125 };
126 
127 extern BOOL P_GiveAmmo(player_t *player, ammotype_t ammo, int num);
128 extern BOOL P_GiveWeapon(player_t *player, weapontype_t weapon, BOOL dropped);
129 extern void P_GiveCard(player_t *player, card_t card);
130 extern BOOL P_GivePower(player_t *player, int  power);
131 
GiveBackpack(player_t * player)132 static void GiveBackpack(player_t* player)
133 {
134 	if (!player->backpack)
135 	{
136 		for (int i=0 ; i<NUMAMMO ; i++)
137 		{
138 			player->maxammo[i] *= 2;
139 		}
140 		player->backpack = true;
141 	}
142 	for (int i=0 ; i<NUMAMMO ; i++)
143 	{
144 		P_GiveAmmo(player, static_cast<ammotype_t>(i), 1);
145 	}
146 	SV_SendPlayerInfo(*player);
147 }
148 
DoGiveInv(player_t * player,const char * type,int amount)149 static void DoGiveInv(player_t* player, const char* type, int amount)
150 {
151 	weapontype_t savedpendingweap = player->pendingweapon;
152 
153 	// Give ammo
154 	for (int i = 0; i < NUMAMMO; i++)
155 	{
156 		if (strcmp(DoomAmmoNames[i], type) == 0)
157 		{
158 			player->ammo[i] = MIN(player->ammo[i]+amount, player->maxammo[i]);
159 			return;
160 		}
161 	}
162 
163 	// Give weapon
164 	for (int i = 0; i < NUMWEAPONS; i++)
165 	{
166 		if (strcmp(DoomWeaponNames[i], type) == 0)
167 		{
168 			do
169 			{
170 				P_GiveWeapon(player, static_cast<weapontype_t>(i), false);
171 			}
172 			while (--amount > 0);
173 
174 			// Don't bring it up automatically
175 			player->pendingweapon = savedpendingweap;
176 			return;
177 		}
178 	}
179 
180 	// Give keycard
181 	for (int i = 0; i < NUMCARDS; i++)
182 	{
183 		if (strcmp(DoomKeyNames[i], type) == 0)
184 		{
185 			do
186 			{
187 				P_GiveCard(player, static_cast<card_t>(i));
188 			}
189 			while (--amount > 0);
190 			return;
191 		}
192 	}
193 
194 	// Give power
195 	for (int i = 0; i < NUMPOWERS; i++)
196 	{
197 		if (strcmp(DoomPowerNames[i], type) == 0)
198 		{
199 			do
200 			{
201 				P_GivePower(player, i);
202 			}
203 			while (--amount > 0);
204 			return;
205 		}
206 	}
207 
208 	// Give backpack
209 	if (strcmp("Backpack", type) == 0)
210 	{
211 		do
212 		{
213 			GiveBackpack(player);
214 		}
215 		while (--amount > 0);
216 		return;
217 	}
218 
219 	// Unknown item.
220 	Printf(PRINT_HIGH, "I don't know what %s is\n", type);
221 }
222 
GiveInventory(AActor * activator,const char * type,int amount)223 static void GiveInventory(AActor* activator, const char* type, int amount)
224 {
225 	if (amount <= 0)
226 	{
227 	}
228 	if (activator == NULL)
229 	{
230 		for (int i = 0; i < MAXPLAYERS; ++i)
231 		{
232 			Players::iterator it;
233 			for (it = players.begin();it != players.end();++it)
234 			{
235 				if (it->ingame() && !it->spectator) {
236 					DoGiveInv(&(*it), type, amount);
237 					SV_SendPlayerInfo(*it);
238 				}
239 			}
240 		}
241 	}
242 	else if (activator->player != NULL)
243 	{
244 		DoGiveInv(activator->player, type, amount);
245 		SV_SendPlayerInfo(*(activator->player));
246 	}
247 }
248 
249 extern void P_SwitchWeapon(player_t *player);
250 
TakeWeapon(player_t * player,int weapon)251 static void TakeWeapon(player_t* player, int weapon)
252 {
253 	player->weaponowned[weapon] = false;
254 	if (player->readyweapon == weapon || player->pendingweapon == weapon)
255 	{
256 		P_SwitchWeapon(player);
257 	}
258 	SV_SendPlayerInfo(*player);
259 }
260 
261 extern BOOL P_CheckAmmo (player_t *player);
262 
TakeAmmo(player_t * player,int ammo,int amount)263 static void TakeAmmo(player_t* player, int ammo, int amount)
264 {
265 	if (amount == 0)
266 	{
267 		player->ammo[ammo] = 0;
268 	}
269 	else
270 	{
271 		player->ammo[ammo] = MAX(player->ammo[ammo]-amount, 0);
272 	}
273 	if (player->pendingweapon != wp_nochange)
274 	{
275 		// Make sure we have the ammo for the weapon being switched to
276 		weapontype_t readynow = player->readyweapon;
277 		player->readyweapon = player->pendingweapon;
278 		player->pendingweapon = wp_nochange;
279 		if (P_CheckAmmo(player))
280 		{
281 			// There was enough ammo for the pending weapon, so keep switching
282 			player->pendingweapon = player->readyweapon;
283 			player->readyweapon = readynow;
284 		}
285 		else
286 		{
287 			player->pendingweapon = player->readyweapon = readynow;
288 			P_CheckAmmo(player);
289 		}
290 	}
291 	else
292 	{
293 		// Make sure we still have enough ammo for the current weapon
294 		P_CheckAmmo(player);
295 	}
296 	SV_SendPlayerInfo(*player);
297 }
298 
TakeBackpack(player_t * player)299 static void TakeBackpack(player_t* player)
300 {
301 	if (!player->backpack)
302 		return;
303 
304 	player->backpack = false;
305 	for (int i = 0; i < NUMAMMO; ++i)
306 	{
307 		player->maxammo[i] /= 2;
308 		if (player->ammo[i] > player->maxammo[i])
309 		{
310 			player->ammo[i] = player->maxammo[i];
311 		}
312 	}
313 	SV_SendPlayerInfo(*player);
314 }
315 
DoTakeInv(player_t * player,const char * type,int amount)316 static void DoTakeInv(player_t* player, const char* type, int amount)
317 {
318 	int i;
319 
320 	for (i = 0; i < NUMAMMO; ++i)
321 	{
322 		if (strcmp(DoomAmmoNames[i], type) == 0)
323 		{
324 			TakeAmmo(player, i, amount);
325 			return;
326 		}
327 	}
328 	for (i = 0; i < NUMWEAPONS; ++i)
329 	{
330 		if (strcmp(DoomWeaponNames[i], type) == 0)
331 		{
332 			TakeWeapon(player, i);
333 			return;
334 		}
335 	}
336 	for (i = 0; i < NUMCARDS; ++i)
337 	{
338 		if (strcmp(DoomKeyNames[i], type) == 0)
339 		{
340 			player->cards[i] = 0;
341 		}
342 	}
343 	if (strcmp("Backpack", type) == 0)
344 	{
345 		TakeBackpack(player);
346 	}
347 }
348 
TakeInventory(AActor * activator,const char * type,int amount)349 static void TakeInventory(AActor* activator, const char* type, int amount)
350 {
351 	if (amount < 0)
352 	{
353 	}
354 	if (activator == NULL)
355 	{
356 		Players::iterator it;
357 		for (it = players.begin();it != players.end();++it)
358 		{
359 			if (it->ingame() && !it->spectator) {
360 				DoTakeInv(&(*it), type, amount);
361 				SV_SendPlayerInfo(*it);
362 			}
363 		}
364 	}
365 	else if (activator->player != NULL)
366 	{
367 		DoTakeInv(activator->player, type, amount);
368 		SV_SendPlayerInfo(*(activator->player));
369 	}
370 }
371 
CheckInventory(AActor * activator,const char * type)372 static int CheckInventory(AActor* activator, const char* type)
373 {
374 	if (activator == NULL || activator->player == NULL)
375 		return 0;
376 
377 	player_t* player = activator->player;
378 
379 	for (int i = 0; i < NUMAMMO; ++i)
380 	{
381 		if (strcmp(DoomAmmoNames[i], type) == 0)
382 		{
383 			return player->ammo[i];
384 		}
385 	}
386 	for (int i = 0; i < NUMWEAPONS; ++i)
387 	{
388 		if (strcmp(DoomWeaponNames[i], type) == 0)
389 		{
390 			return player->weaponowned[i] ? 1 : 0;
391 		}
392 	}
393 	for (int i = 0; i < NUMCARDS; ++i)
394 	{
395 		if (strcmp(DoomKeyNames[i], type) == 0)
396 		{
397 			return player->cards[i] ? 1 : 0;
398 		}
399 	}
400 	if (strcmp("Backpack", type) == 0)
401 	{
402 		return player->backpack ? 1 : 0;
403 	}
404 	return 0;
405 }
406 
407 EXTERN_CVAR (sv_skill)
EXTERN_CVAR(sv_gametype)408 EXTERN_CVAR (sv_gametype)
409 
410 //---- ACS lump manager ----//
411 
412 FBehavior::FBehavior (BYTE *object, int len)
413 {
414 	int i;
415 
416 	NumScripts = 0;
417 	NumFunctions = 0;
418 	NumArrays = 0;
419 	Scripts = NULL;
420 	Functions = NULL;
421 	Arrays = NULL;
422 	Chunks = NULL;
423 
424 	if (object[0] != 'A' || object[1] != 'C' || object[2] != 'S')
425 	{
426 		Format = ACS_Unknown;
427 		return;
428 	}
429 
430 	switch (object[3])
431 	{
432 	case 0:
433 		Format = ACS_Old;
434 		break;
435 	case 'E':
436 		Format = ACS_Enhanced;
437 		break;
438 	case 'e':
439 		Format = ACS_LittleEnhanced;
440 		break;
441 	default:
442 		Format = ACS_Unknown;
443 		return;
444 	}
445 
446 	Data = object;
447 	DataSize = len;
448 
449 	if (Format == ACS_Old)
450 	{
451 		Chunks = object + len;
452 		Scripts = object + ((DWORD *)object)[1];
453 		NumScripts = ((DWORD *)Scripts)[0];
454 		// Check for redesigned ACSE/ACSe
455 		if (((DWORD *)object)[1] >= 6*4 &&
456 			(((DWORD *)Scripts)[-1] == MAKE_ID('A','C','S','e') ||
457 			((DWORD *)Scripts)[-1] == MAKE_ID('A','C','S','E')))
458 		{
459 			Format = (((BYTE *)Scripts)[-1] == 'e') ? ACS_LittleEnhanced : ACS_Enhanced;
460 			Chunks = object + ((DWORD *)Scripts)[-2];
461 			// Forget about the compatibility cruft at the end of the lump
462 			DataSize = ((DWORD *)object)[1] - 8;
463 		}
464 		else
465 		{
466 			Scripts += 4;
467 			for (i = 0; i < NumScripts; ++i)
468 			{
469 				ScriptPtr2 ptr1 = *(ScriptPtr2 *)(Scripts + 12*i);
470 				ScriptPtr *ptr2 =  (ScriptPtr  *)(Scripts +  8*i);
471 				ptr2->Number = ptr1.Number % 1000;
472 				ptr2->Type = ptr1.Number / 1000;
473 				ptr2->ArgCount = ptr1.ArgCount;
474 				ptr2->Address = ptr1.Address;
475 			}
476 		}
477 	}
478 	else
479 	{
480 		Chunks = object + ((DWORD *)object)[1];
481 	}
482 	if (Format != ACS_Old)
483 	{
484 		Scripts = FindChunk (MAKE_ID('S','P','T','R'));
485 		if (object[3] != 0)
486 		{
487 			NumScripts = ((DWORD *)Scripts)[1] / 12;
488 			Scripts += 8;
489 			for (i = 0; i < NumScripts; ++i)
490 			{
491 				ScriptPtr1 ptr1 = *(ScriptPtr1 *)(Scripts + 12*i);
492 				ScriptPtr *ptr2 =  (ScriptPtr  *)(Scripts +  8*i);
493 				ptr2->Number = ptr1.Number;
494 				ptr2->Type = ptr1.Type;
495 				ptr2->ArgCount = ptr1.ArgCount;
496 				ptr2->Address = ptr1.Address;
497 			}
498 		}
499 		else
500 		{
501 			NumScripts = ((DWORD *)Scripts)[1] / 8;
502 			Scripts += 8;
503 		}
504 	}
505 
506 	// Sort scripts, so we can use a binary search to find them
507 	if (NumScripts > 0)
508 	{
509 		qsort (Scripts, NumScripts, 8, SortScripts);
510 	}
511 
512 	if (Format == ACS_Old)
513 	{
514 		LanguageNeutral = ((DWORD *)Data)[1];
515 		LanguageNeutral += ((DWORD *)(Data + LanguageNeutral))[0] * 12 + 4;
516 	}
517 	else
518 	{
519 		LanguageNeutral = FindLanguage (0, false);
520 		PrepLocale (LanguageIDs[0], LanguageIDs[1], LanguageIDs[2], LanguageIDs[3]);
521 	}
522 
523 	if (Format != ACS_Old)
524 	{
525 		DWORD *chunk;
526 
527 		Functions = FindChunk(MAKE_ID('F','U','N','C'));
528 		if (Functions != NULL)
529 		{
530 			NumFunctions = LELONG(((DWORD *)Functions)[1]);
531 			Functions += 8;
532 		}
533 
534 		chunk = (DWORD *)FindChunk(MAKE_ID('M','I','N','I'));
535 		if (chunk != NULL)
536 		{
537 			int numvars = LELONG(chunk[1])/4;
538 			int firstvar = LELONG(chunk[2]);
539 			for (i = 0; i < numvars; ++i)
540 			{
541 				level.vars[i+firstvar] = LELONG(chunk[3+i]);
542 			}
543 		}
544 
545 		chunk = (DWORD *)FindChunk(MAKE_ID('A','R','A','Y'));
546 		if (chunk != NULL)
547 		{
548 			NumArrays = LELONG(chunk[1])/8;
549 			Arrays = new ArrayInfo[NumArrays];
550 			memset (Arrays, 0, sizeof(*Arrays)*NumArrays);
551 			for (i = 0; i < NumArrays; ++i)
552 			{
553 				level.vars[LELONG(chunk[2+i*2])] = i;
554 				Arrays[i].ArraySize = LELONG(chunk[3+i*2]);
555 				Arrays[i].Elements = new SDWORD[Arrays[i].ArraySize];
556 				memset(Arrays[i].Elements, 0, Arrays[i].ArraySize*sizeof(DWORD));
557 			}
558 		}
559 
560 		chunk = (DWORD *)FindChunk(MAKE_ID('A','I','N','I'));
561 		while (chunk != NULL)
562 		{
563 			int arraynum = level.vars[LELONG(chunk[2])];
564 			if ((unsigned)arraynum < (unsigned)NumArrays)
565 			{
566 				int initsize = MIN<int> (Arrays[arraynum].ArraySize, (LELONG(chunk[1])-4)/4);
567 				SDWORD *elems = Arrays[arraynum].Elements;
568 				for (i = 0; i < initsize; ++i)
569 				{
570 					elems[i] = LELONG(chunk[3+i]);
571 				}
572 			}
573 			chunk = (DWORD *)NextChunk((BYTE *)chunk);
574 		}
575 	}
576 
577 	DPrintf ("Loaded %d scripts, %d Functions\n", NumScripts, NumFunctions);
578 }
579 
~FBehavior()580 FBehavior::~FBehavior ()
581 {
582 	// Object file is freed by the zone heap
583 	if(Arrays != NULL)
584 	{
585 		for (int i = 0; i < NumArrays; ++i)
586 		{
587 			if (Arrays[i].Elements != NULL)
588 			{
589 				delete[] Arrays[i].Elements;
590 				Arrays[i].Elements = NULL;
591 			}
592 		}
593 		delete[] Arrays;
594 		Arrays = NULL;
595 	}
596 }
597 
SortScripts(const void * a,const void * b)598 int STACK_ARGS FBehavior::SortScripts (const void *a, const void *b)
599 {
600 	ScriptPtr *ptr1 = (ScriptPtr *)a;
601 	ScriptPtr *ptr2 = (ScriptPtr *)b;
602 	return ptr1->Number - ptr2->Number;
603 }
604 
IsGood()605 bool FBehavior::IsGood ()
606 {
607 	return Format != ACS_Unknown;
608 }
609 
FindScript(int script) const610 int *FBehavior::FindScript (int script) const
611 {
612 	const ScriptPtr *ptr = BinarySearch<ScriptPtr, WORD>
613 		((ScriptPtr *)Scripts, NumScripts, &ScriptPtr::Number, (WORD)script);
614 
615 	return ptr ? (int *)(ptr->Address + Data) : NULL;
616 }
617 
GetFunction(int funcnum) const618 ScriptFunction *FBehavior::GetFunction (int funcnum) const
619 {
620 	if ((unsigned)funcnum >= (unsigned)NumFunctions)
621 	{
622 		return NULL;
623 	}
624 	return (ScriptFunction *)Functions + funcnum;
625 }
626 
GetArrayVal(int arraynum,int index) const627 int FBehavior::GetArrayVal (int arraynum, int index) const
628 {
629 	if ((unsigned)arraynum >= (unsigned)NumArrays)
630 		return 0;
631 	const ArrayInfo *array = &Arrays[arraynum];
632 	if ((unsigned)index >= (unsigned)array->ArraySize)
633 		return 0;
634 	return array->Elements[index];
635 }
636 
SetArrayVal(int arraynum,int index,int value)637 void FBehavior::SetArrayVal (int arraynum, int index, int value)
638 {
639 	if ((unsigned)arraynum >= (unsigned)NumArrays)
640 		return;
641 	const ArrayInfo *array = &Arrays[arraynum];
642 	if ((unsigned)index >= (unsigned)array->ArraySize)
643 		return;
644 	array->Elements[index] = value;
645 }
646 
FindChunk(DWORD id) const647 BYTE *FBehavior::FindChunk (DWORD id) const
648 {
649 	BYTE *chunk = Chunks;
650 
651 	while (chunk != NULL && chunk < Data + DataSize)
652 	{
653 		if (((DWORD *)chunk)[0] == id)
654 		{
655 			return chunk;
656 		}
657 		chunk += ((DWORD *)chunk)[1] + 8;
658 	}
659 	return NULL;
660 }
661 
NextChunk(BYTE * chunk) const662 BYTE *FBehavior::NextChunk (BYTE *chunk) const
663 {
664 	DWORD id = *(DWORD *)chunk;
665 	chunk += ((DWORD *)chunk)[1] + 8;
666 	while (chunk != NULL && chunk < Data + DataSize)
667 	{
668 		if (((DWORD *)chunk)[0] == id)
669 		{
670 			return chunk;
671 		}
672 		chunk += ((DWORD *)chunk)[1] + 8;
673 	}
674 	return NULL;
675 }
676 
LookupString(DWORD index,DWORD ofs) const677 const char *FBehavior::LookupString (DWORD index, DWORD ofs) const
678 {
679 	if (Format == ACS_Old)
680 	{
681 		DWORD *list = (DWORD *)(Data + LanguageNeutral);
682 
683 		if (index >= list[0])
684 			return NULL;	// Out of range for this list;
685 		return (const char *)(Data + list[1+index]);
686 	}
687 	else
688 	{
689 		if (ofs == 0)
690 		{
691 			ofs = LanguageNeutral;
692 			if (ofs == 0)
693 			{
694 				return NULL;
695 			}
696 		}
697 		DWORD *list = (DWORD *)(Data + ofs);
698 
699 		if (index >= list[1])
700 			return NULL;	// Out of range for this list
701 		if (list[3+index] == 0)
702 			return NULL;	// Not defined in this list
703 		return (const char *)(Data + ofs + list[3+index]);
704 	}
705 }
706 
LocalizeString(DWORD index) const707 const char *FBehavior::LocalizeString (DWORD index) const
708 {
709 	if (Format != ACS_Old)
710 	{
711 		DWORD ofs = Localized;
712 		const char *str = NULL;
713 
714 		while (ofs != 0 && (str = LookupString (index, ofs)) == NULL)
715 		{
716 			ofs = ((DWORD *)(Data + ofs))[2];
717 		}
718 		return str;
719 	}
720 	else
721 	{
722 		return LookupString (index);
723 	}
724 }
725 
PrepLocale(DWORD userpref,DWORD userdef,DWORD syspref,DWORD sysdef)726 void FBehavior::PrepLocale (DWORD userpref, DWORD userdef, DWORD syspref, DWORD sysdef)
727 {
728 	BYTE *chunk;
729 	DWORD *list;
730 
731 	// Clear away any existing links
732 	for (chunk = Chunks; chunk < Data + DataSize; chunk += ((DWORD *)chunk)[1] + 8)
733 	{
734 		list = (DWORD *)chunk;
735 		if (list[0] == MAKE_ID('S','T','R','L'))
736 		{
737 			list[4] = 0;
738 		}
739 	}
740 	Localized = 0;
741 
742 	if (userpref)
743 		AddLanguage (userpref);
744 	if (userpref & LANGREGIONMASK)
745 		AddLanguage (userpref & ~LANGREGIONMASK);
746 	if (userdef)
747 		AddLanguage (userdef);
748 	if (userdef & LANGREGIONMASK)
749 		AddLanguage (userdef & ~LANGREGIONMASK);
750 	if (syspref)
751 		AddLanguage (syspref);
752 	if (syspref & LANGREGIONMASK)
753 		AddLanguage (syspref & ~LANGREGIONMASK);
754 	if (sysdef)
755 		AddLanguage (sysdef);
756 	if (sysdef & LANGREGIONMASK)
757 		AddLanguage (sysdef & ~LANGREGIONMASK);
758 	AddLanguage (MAKE_ID('e','n',0,0));		// Use English as a fallback
759 	AddLanguage (0);			// Failing that, use language independent strings
760 }
761 
AddLanguage(DWORD langid)762 void FBehavior::AddLanguage (DWORD langid)
763 {
764 	DWORD ofs, *ofsput;
765 	DWORD *list;
766 	BYTE *chunk;
767 
768 	// First, make sure language is not already inserted
769 	ofsput = CheckIfInList (langid);
770 	if (ofsput == NULL)
771 	{ // Already in list
772 		return;
773 	}
774 
775 	// Try to find an exact match first
776 	ofs = FindLanguage (langid, false);
777 	if (ofs != 0)
778 	{
779 		*ofsput = ofs;
780 		return;
781 	}
782 
783 	// If langid has no sublanguage, add all languages that match the major
784 	// type, if not in list already
785 	if ((langid & LANGREGIONMASK) == 0)
786 	{
787 		for (chunk = Chunks; chunk < Data + DataSize; chunk += ((DWORD *)chunk)[1] + 8)
788 		{
789 			list = (DWORD *)chunk;
790 			if (list[0] != MAKE_ID('S','T','R','L'))
791 				continue;	// not a string list
792 			if ((list[2] & ~LANGREGIONMASK) != langid)
793 				continue;	// wrong language
794 			if (list[4] != 0)
795 				continue;	// definitely in language list
796 			ofsput = CheckIfInList (list[2]);
797 			if (ofsput != NULL)
798 				*ofsput = chunk - Data + 8;	// add to language list
799 		}
800 	}
801 }
802 
CheckIfInList(DWORD langid)803 DWORD *FBehavior::CheckIfInList (DWORD langid)
804 {
805 	DWORD ofs, *ofsput;
806 	DWORD *list;
807 
808 	ofs = Localized;
809 	ofsput = &Localized;
810 	while (ofs != 0)
811 	{
812 		list = (DWORD *)(Data + ofs);
813 		if (list[0] == langid)
814 			return NULL;
815 		ofsput = &list[2];
816 		ofs = list[2];
817 	}
818 	return ofsput;
819 }
820 
FindLanguage(DWORD langid,bool ignoreregion) const821 DWORD FBehavior::FindLanguage (DWORD langid, bool ignoreregion) const
822 {
823 	BYTE *chunk;
824 	DWORD *list;
825 	DWORD langmask;
826 
827 	langmask = ignoreregion ? ~LANGREGIONMASK : ~0;
828 
829 	for (chunk = Chunks; chunk < Data + DataSize; chunk += ((DWORD *)chunk)[1] + 8)
830 	{
831 		list = (DWORD *)chunk;
832 		if (list[0] == MAKE_ID('S','T','R','L') && (list[2] & langmask) == langid)
833 		{
834 			return chunk - Data + 8;
835 		}
836 	}
837 	return 0;
838 }
839 
StartTypedScripts(WORD type,AActor * activator) const840 void FBehavior::StartTypedScripts (WORD type, AActor *activator) const
841 {
842 	ScriptPtr *ptr;
843 	int i;
844 
845 	for (i = 0; i < NumScripts; ++i)
846 	{
847 		ptr = (ScriptPtr *)(Scripts + 8*i);
848 		if (ptr->Type == type)
849 		{
850 			P_GetScriptGoing (activator, NULL, ptr->Number,
851 				(int *)(ptr->Address + Data), 0, 0, 0, 0, 0, true);
852 		}
853 	}
854 }
855 
856 //---- The ACS Interpreter ----//
857 
858 
859 
860 #define NEXTWORD	(LELONG(*pc++))
861 #define NEXTBYTE	(fmt==ACS_LittleEnhanced?getbyte(pc):NEXTWORD)
862 #define STACK(a)	(Stack[sp - (a)])
863 #define PushToStack(a)	(Stack[sp++] = (a))
864 
865 void strbin (char *str);
866 
867 IMPLEMENT_SERIAL (DACSThinker, DThinker)
868 
869 DACSThinker *DACSThinker::ActiveThinker = NULL;
870 
DACSThinker()871 DACSThinker::DACSThinker ()
872 {
873 	if (ActiveThinker)
874 	{
875 		I_Error ("Only one ACSThinker is allowed to exist at a time.\nCheck your code.");
876 	}
877 	else
878 	{
879 		ActiveThinker = this;
880 		Scripts = NULL;
881 		LastScript = NULL;
882 		for (int i = 0; i < 1000; i++)
883 			RunningScripts[i] = NULL;
884 	}
885 }
886 
~DACSThinker()887 DACSThinker::~DACSThinker ()
888 {
889 	DLevelScript *script = Scripts;
890 	while (script)
891 	{
892 		DLevelScript *next = script->next;
893 		script->Destroy ();
894 		script = next;
895 	}
896 	Scripts = NULL;
897 	ActiveThinker = NULL;
898 }
899 
Serialize(FArchive & arc)900 void DACSThinker::Serialize (FArchive &arc)
901 {
902 	if (arc.IsStoring ())
903 	{
904 		arc << Scripts << LastScript;
905 		for (int i = 0; i < 1000; i++)
906 		{
907 			if (RunningScripts[i])
908 				arc << RunningScripts[i] << (WORD)i;
909 		}
910 		arc << (DLevelScript *)NULL;
911 	}
912 	else
913 	{
914 		arc >> Scripts >> LastScript;
915 
916 		WORD scriptnum;
917 		DLevelScript *script;
918 		arc >> script;
919 		while (script)
920 		{
921 			arc >> scriptnum;
922 			RunningScripts[scriptnum] = script;
923 			arc >> script;
924 		}
925 	}
926 }
927 
RunThink()928 void DACSThinker::RunThink ()
929 {
930 	DLevelScript *script = Scripts;
931 
932 	while (script)
933 	{
934 		DLevelScript *next = script->next;
935 		script->RunScript ();
936 		script = next;
937 	}
938 }
939 
940 // FlashFader class - not sure where to put this so it goes here for now...
941 class DFlashFader : public DThinker
942 {
943 	DECLARE_SERIAL (DFlashFader, DThinker)
944 public:
945 	DFlashFader (float r1, float g1, float b1, float a1,
946 				 float r2, float g2, float b2, float a2,
947 				 float time, AActor *who);
948 	~DFlashFader ();
949 	virtual void RunThink ();
950 	virtual void DestroyedPointer(DObject *obj);
WhoFor()951 	AActor *WhoFor() { return ForWho; }
952 	void Cancel ();
953 
954 protected:
955 	float Blends[2][4];
956 	int TotalTics;
957 	int StartTic;
958 	AActor *ForWho;
959 
960 	void SetBlend (float time);
961 	DFlashFader ();
962 };
963 
IMPLEMENT_SERIAL(DFlashFader,DThinker)964 IMPLEMENT_SERIAL(DFlashFader, DThinker)
965 
966 DFlashFader::DFlashFader ()
967 {
968 }
969 
DestroyedPointer(DObject * obj)970 void DFlashFader::DestroyedPointer(DObject *obj)
971 {
972 	if(obj == ForWho)
973 		ForWho = NULL;
974 }
975 
DFlashFader(float r1,float g1,float b1,float a1,float r2,float g2,float b2,float a2,float time,AActor * who)976 DFlashFader::DFlashFader (float r1, float g1, float b1, float a1,
977 						  float r2, float g2, float b2, float a2,
978 						  float time, AActor *who)
979 	: TotalTics ((int)(time*TICRATE)), StartTic (level.time), ForWho (who)
980 {
981 	Blends[0][0]=r1; Blends[0][1]=g1; Blends[0][2]=b1; Blends[0][3]=a1;
982 	Blends[1][0]=r2; Blends[1][1]=g2; Blends[1][2]=b2; Blends[1][3]=a2;
983 }
984 
~DFlashFader()985 DFlashFader::~DFlashFader ()
986 {
987 	SetBlend (1.f);
988 }
989 
Serialize(FArchive & arc)990 void DFlashFader::Serialize (FArchive &arc)
991 {
992 	Super::Serialize (arc);
993 
994 	if (arc.IsStoring ())
995 	{
996 		arc << TotalTics << StartTic << ForWho;
997 
998 		for (int i = 1; i >= 0; --i)
999 			for (int j = 3; j >= 0; --j)
1000 				arc << Blends[i][j];
1001 	}
1002 	else
1003 	{
1004 		arc >> TotalTics >> StartTic >> ForWho;
1005 
1006 		for (int i = 1; i >= 0; --i)
1007 			for (int j = 3; j >= 0; --j)
1008 				arc >> Blends[i][j];
1009 	}
1010 }
1011 
RunThink()1012 void DFlashFader::RunThink ()
1013 {
1014 	if (ForWho == NULL || ForWho->player == NULL)
1015 	{
1016 		Destroy ();
1017 		return;
1018 	}
1019 	if (level.time >= StartTic+TotalTics)
1020 	{
1021 		SetBlend (1.f);
1022 		Destroy ();
1023 		return;
1024 	}
1025 	SetBlend ((float)(level.time - StartTic) / (float)TotalTics);
1026 }
1027 
SetBlend(float time)1028 void DFlashFader::SetBlend (float time)
1029 {
1030 	if (ForWho == NULL || ForWho->player == NULL)
1031 	{
1032 		return;
1033 	}
1034 	player_t *player = ForWho->player;
1035 	float iT = 1.f - time;
1036 	player->BlendR = Blends[0][0]*iT + Blends[1][0]*time;
1037 	player->BlendG = Blends[0][1]*iT + Blends[1][1]*time;
1038 	player->BlendB = Blends[0][2]*iT + Blends[1][2]*time;
1039 	player->BlendA = Blends[0][3]*iT + Blends[1][3]*time;
1040 }
1041 
Cancel()1042 void DFlashFader::Cancel ()
1043 {
1044 	TotalTics = level.time - StartTic;
1045 	Blends[1][3] = 0.f;
1046 }
1047 
1048 //---- Plane watchers ----//
1049 
1050 class DPlaneWatcher : public DThinker
1051 {
1052 	DECLARE_SERIAL (DPlaneWatcher, DThinker)
1053 public:
1054 	DPlaneWatcher (AActor *it, line_t *line, int lineSide, bool ceiling,
1055 		int tag, int height, int special,
1056 		int arg0, int arg1, int arg2, int arg3, int arg4);
1057 	virtual void RunThink ();
1058 	virtual void DestroyedPointer(DObject *obj);
1059 private:
1060 	sector_t *Sector;
1061 	fixed_t WatchD, LastD;
1062 	int Special, Arg0, Arg1, Arg2, Arg3, Arg4;
1063 	AActor *Activator;
1064 	line_t *Line;
1065 	int LineSide;
1066 	bool bCeiling;
1067 
DPlaneWatcher()1068 	DPlaneWatcher() {}
1069 };
1070 
IMPLEMENT_SERIAL(DPlaneWatcher,DThinker)1071 IMPLEMENT_SERIAL(DPlaneWatcher, DThinker)
1072 
1073 void DPlaneWatcher::DestroyedPointer(DObject *obj)
1074 {
1075 	if(obj == Activator)
1076 		Activator = NULL;
1077 }
1078 
DPlaneWatcher(AActor * it,line_t * line,int lineSide,bool ceiling,int tag,int height,int special,int arg0,int arg1,int arg2,int arg3,int arg4)1079 DPlaneWatcher::DPlaneWatcher (AActor *it, line_t *line, int lineSide, bool ceiling,
1080 	int tag, int height, int special,
1081 	int arg0, int arg1, int arg2, int arg3, int arg4)
1082 	: Special (special), Arg0 (arg0), Arg1 (arg1), Arg2 (arg2), Arg3 (arg3), Arg4 (arg4),
1083 	  Activator (it), Line (line), LineSide (lineSide), bCeiling (ceiling)
1084 {
1085 	int secnum;
1086 
1087 	secnum = P_FindSectorFromTag (tag, -1);
1088 	if (secnum >= 0)
1089 	{
1090 		Sector = &sectors[secnum];
1091 		if (bCeiling)
1092 		{
1093 			LastD = Sector->ceilingplane.d;
1094 			P_ChangeCeilingHeight(Sector, height << FRACBITS);
1095 			WatchD = Sector->ceilingplane.d;
1096 		}
1097 		else
1098 		{
1099 			LastD = Sector->floorplane.d;
1100 			P_ChangeFloorHeight(Sector, height << FRACBITS);
1101 			WatchD = Sector->floorplane.d;
1102 		}
1103 	}
1104 	else
1105 	{
1106 		Sector = NULL;
1107 		WatchD = LastD = 0;
1108 	}
1109 }
1110 
Serialize(FArchive & arc)1111 void DPlaneWatcher::Serialize (FArchive &arc)
1112 {
1113 	Super::Serialize (arc);
1114 
1115 	if (arc.IsStoring ())
1116 	{
1117 		arc << Special << Arg0 << Arg1 << Arg2 << Arg3 << Arg4
1118 			<< Sector << bCeiling << WatchD << LastD << Activator
1119 			<< Line << LineSide << bCeiling;
1120 	}
1121 	else
1122 	{
1123 		arc >> Special >> Arg0 >> Arg1 >> Arg2 >> Arg3 >> Arg4
1124 			>> Sector >> bCeiling >> WatchD >> LastD >> Activator
1125 			>> Line >> LineSide >> bCeiling;
1126 	}
1127 }
1128 
RunThink()1129 void DPlaneWatcher::RunThink ()
1130 {
1131 	if (Sector == NULL)
1132 	{
1133 		Destroy ();
1134 		return;
1135 	}
1136 
1137 	fixed_t newd;
1138 
1139 	if (bCeiling)
1140 	{
1141 		newd = Sector->ceilingplane.d;
1142 	}
1143 	else
1144 	{
1145 		newd = Sector->floorplane.d;
1146 	}
1147 
1148 	if ((LastD < WatchD && newd >= WatchD) ||
1149 		(LastD > WatchD && newd <= WatchD))
1150 	{
1151 		TeleportSide = LineSide;
1152 		LineSpecials[Special] (Line, Activator, Arg0, Arg1, Arg2, Arg3, Arg4);
1153 		Destroy ();
1154 	}
1155 }
1156 
1157 
IMPLEMENT_SERIAL(DLevelScript,DObject)1158 IMPLEMENT_SERIAL (DLevelScript, DObject)
1159 
1160 void *DLevelScript::operator new (size_t size)
1161 {
1162 	return Z_Malloc (sizeof(DLevelScript), PU_LEVACS, 0);
1163 }
1164 
operator delete(void * block)1165 void DLevelScript::operator delete (void *block)
1166 {
1167 	Z_Free (block);
1168 }
1169 
Serialize(FArchive & arc)1170 void DLevelScript::Serialize (FArchive &arc)
1171 {
1172 	DWORD i;
1173 
1174 	Super::Serialize (arc);
1175 
1176 	if (arc.IsStoring ())
1177 	{
1178 		arc << next << prev
1179 			<< script
1180 			<< sp
1181 			<< state
1182 			<< statedata
1183 			<< activator
1184 			<< activationline
1185 			<< lineSide;
1186 
1187 		for (i = 0; i < LOCAL_SIZE; i++)
1188 			arc << localvars[i];
1189 
1190 		i = level.behavior->PC2Ofs(pc);
1191 		arc << i;
1192 	}
1193 	else
1194 	{
1195 		arc >> next >> prev
1196 			>> script
1197 			>> sp
1198 			>> state
1199 			>> statedata
1200 			>> activator
1201 			>> activationline
1202 			>> lineSide;
1203 
1204 		for (i = 0; i < LOCAL_SIZE; i++)
1205 			arc >> localvars[i];
1206 
1207 		arc >> i;
1208 		pc = level.behavior->Ofs2PC (i);
1209 	}
1210 }
1211 
DLevelScript()1212 DLevelScript::DLevelScript ()
1213 {
1214 	next = prev = NULL;
1215 	if (DACSThinker::ActiveThinker == NULL)
1216 		new DACSThinker;
1217 }
1218 
1219 
Unlink()1220 void DLevelScript::Unlink ()
1221 {
1222 	DACSThinker *controller = DACSThinker::ActiveThinker;
1223 	if (!controller)
1224 		return;
1225 
1226 	if (controller->LastScript == this)
1227 		controller->LastScript = prev;
1228 	if (controller->Scripts == this)
1229 		controller->Scripts = next;
1230 	if (prev)
1231 		prev->next = next;
1232 	if (next)
1233 		next->prev = prev;
1234 }
1235 
Link()1236 void DLevelScript::Link ()
1237 {
1238 	DACSThinker *controller = DACSThinker::ActiveThinker;
1239 	if (!controller)
1240 		return;
1241 
1242 	next = controller->Scripts;
1243 	if (controller->Scripts)
1244 		controller->Scripts->prev = this;
1245 	prev = NULL;
1246 	controller->Scripts = this;
1247 	if (controller->LastScript == NULL)
1248 		controller->LastScript = this;
1249 }
1250 
PutLast()1251 void DLevelScript::PutLast ()
1252 {
1253 	DACSThinker *controller = DACSThinker::ActiveThinker;
1254 	if (!controller)
1255 		return;
1256 
1257 	if (controller->LastScript == this)
1258 		return;
1259 
1260 	Unlink ();
1261 	if (controller->Scripts == NULL)
1262 	{
1263 		Link ();
1264 	}
1265 	else
1266 	{
1267 		if (controller->LastScript)
1268 			controller->LastScript->next = this;
1269 		prev = controller->LastScript;
1270 		next = NULL;
1271 		controller->LastScript = this;
1272 	}
1273 }
1274 
PutFirst()1275 void DLevelScript::PutFirst ()
1276 {
1277 	DACSThinker *controller = DACSThinker::ActiveThinker;
1278 	if (!controller)
1279 		return;
1280 
1281 	if (controller->Scripts == this)
1282 		return;
1283 
1284 	Unlink ();
1285 	Link ();
1286 }
1287 
Random(int min,int max)1288 int DLevelScript::Random (int min, int max)
1289 {
1290 	int num1, num2, num3, num4;
1291 	unsigned int num;
1292 
1293 	num1 = P_Random ();
1294 	num2 = P_Random ();
1295 	num3 = P_Random ();
1296 	num4 = P_Random ();
1297 
1298 	num = ((num1 << 24) | (num2 << 16) | (num3 << 8) | num4);
1299 	num %= (max - min + 1);
1300 	num += min;
1301 	return (int)num;
1302 }
1303 
ThingCount(int type,int tid)1304 int DLevelScript::ThingCount (int type, int tid)
1305 {
1306 	AActor *mobj = NULL;
1307 	int count = 0;
1308 
1309 	if (type >= NumSpawnableThings)
1310 	{
1311 		return 0;
1312 	}
1313 	else if (type > 0)
1314 	{
1315 		type = SpawnableThings[type];
1316 		if (type == 0)
1317 			return 0;
1318 	}
1319 
1320 	if (tid)
1321 	{
1322 		mobj = AActor::FindByTID (NULL, tid);
1323 		while (mobj)
1324 		{
1325 			if ((type == 0) || (mobj->type == type && mobj->health > 0))
1326 				count++;
1327 			mobj = mobj->FindByTID (tid);
1328 		}
1329 	}
1330 	else
1331 	{
1332 		AActor *actor;
1333 		TThinkerIterator<AActor> iterator;
1334 
1335 		while ( (actor = iterator.Next ()) )
1336 		{
1337 			if (type == 0)
1338 			{
1339 				count++;
1340 			}
1341 			else if (actor->type == type && actor->health > 0)
1342 			{
1343 				count++;
1344 			}
1345 		}
1346 	}
1347 	return count;
1348 }
1349 
ChangeFlat(int tag,int name,bool floorOrCeiling)1350 void DLevelScript::ChangeFlat (int tag, int name, bool floorOrCeiling)
1351 {
1352 	int flat, secnum = -1;
1353 	const char *flatname = level.behavior->LookupString (name);
1354 
1355 	if (flatname == NULL)
1356 		return;
1357 
1358 	flat = R_FlatNumForName (flatname);
1359 
1360 	while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0)
1361 	{
1362 		if (floorOrCeiling == false)
1363 			sectors[secnum].floorpic = flat;
1364 		else
1365 			sectors[secnum].ceilingpic = flat;
1366 	}
1367 }
1368 
1369 extern size_t P_NumPlayersInGame();
1370 
CountPlayers()1371 int DLevelScript::CountPlayers()
1372 {
1373 	return static_cast<int>(P_NumPlayersInGame());
1374 }
1375 
SetLineTexture(int lineid,int side,int position,int name)1376 void DLevelScript::SetLineTexture (int lineid, int side, int position, int name)
1377 {
1378 	int texture, linenum = -1;
1379 	const char *texname = level.behavior->LookupString (name);
1380 
1381 	if (texname == NULL)
1382 		return;
1383 
1384 	side = (side) ? 1 : 0;
1385 
1386 	texture = R_TextureNumForName (texname);
1387 
1388 	while ((linenum = P_FindLineFromID (lineid, linenum)) >= 0) {
1389 		side_t *sidedef;
1390 
1391 		if (lines[linenum].sidenum[side] == R_NOSIDE)
1392 			continue;
1393 		sidedef = sides + lines[linenum].sidenum[side];
1394 
1395 		switch (position) {
1396 			case TEXTURE_TOP:
1397 				sidedef->toptexture = texture;
1398 				break;
1399 			case TEXTURE_MIDDLE:
1400 				sidedef->midtexture = texture;
1401 				break;
1402 			case TEXTURE_BOTTOM:
1403 				sidedef->bottomtexture = texture;
1404 				break;
1405 			default:
1406 				break;
1407 		}
1408 
1409 	}
1410 }
1411 
1412 /*int DLevelScript::DoSpawn(int type, fixed_t x, fixed_t y, fixed_t z, int tid, int angle)
1413 {
1414 	const char* typestr = level.behavior->LookupString(type);
1415 	if (typestr == NULL)
1416 		return 0;
1417 	char name[64];
1418 	name[0] = 'A';
1419 	name[63] = 0;
1420 	strncpy(name+1, typestr, 62);
1421 
1422 	const TypeInfo* info = TypeInfo::FindType(name);
1423 	AActor* actor = NULL;
1424 
1425 	if (info != NULL)
1426 	{
1427 		actor = Spawn(info, x, y, z);
1428 		if (actor != NULL)
1429 		{
1430 			if (P_TestMobjLocation(actor))
1431 			{
1432 				actor->angle = angle << 24;
1433 				actor->tid = tid;
1434 				actor->AddToHash();
1435 				actor->flags |= MF_DROPPED;  // Don't respawn
1436 			}
1437 			else
1438 			{
1439 				actor->Destroy();
1440 				actor = NULL;
1441 			}
1442 		}
1443 	}
1444 	return (int)actor;
1445 }
1446 
1447 int DLevelScript::DoSpawnSpot(int type, int spot, int tid, int angle)
1448 {
1449 	FActorIterator iterator(tid);
1450 	AActor* aspot;
1451 	int spawned = 0;
1452 
1453 	while ((aspot = iterator.Next()))
1454 	{
1455 		spawned = DoSpawn(type, aspot->x, aspot->y, aspot->z, tid, angle);
1456 	}
1457 	return spawned;
1458 }*/
1459 
DoFadeTo(int r,int g,int b,int a,fixed_t time)1460 void DLevelScript::DoFadeTo (int r, int g, int b, int a, fixed_t time)
1461 {
1462     Printf(PRINT_HIGH,"DoFadeRange now... \n");
1463 	DoFadeRange (0, 0, 0, -1, r, g, b, a, time);
1464 }
1465 
DoActualFadeRange(player_s * viewer,float ftime,bool fadingFrom,float fr1,float fg1,float fb1,float fa1,float fr2,float fg2,float fb2,float fa2)1466 static void DoActualFadeRange(player_s* viewer, float ftime, bool fadingFrom,
1467                               float fr1, float fg1, float fb1, float fa1,
1468                               float fr2, float fg2, float fb2, float fa2)
1469 {
1470 	if (ftime <= 0.f)
1471 	{
1472 		viewer->BlendR = fr2;
1473 		viewer->BlendG = fg2;
1474 		viewer->BlendB = fb2;
1475 		viewer->BlendA = fa2;
1476 	}
1477 	else
1478 	{
1479 		if (!fadingFrom)
1480 		{
1481 			if (viewer->BlendA <= 0.f)
1482 			{
1483 				fr1 = fr2;
1484 				fg1 = fg2;
1485 				fb1 = fb2;
1486 				fa1 = 0.f;
1487 			}
1488 			else
1489 			{
1490 				fr1 = viewer->BlendR;
1491 				fg1 = viewer->BlendG;
1492 				fb1 = viewer->BlendB;
1493 				fa1 = viewer->BlendA;
1494 			}
1495 		}
1496 		new DFlashFader (fr1, fg1, fb1, fa1, fr2, fg2, fb2, fa2, ftime, viewer->mo);
1497 	}
1498 }
1499 
DoFadeRange(int r1,int g1,int b1,int a1,int r2,int g2,int b2,int a2,fixed_t time)1500 void DLevelScript::DoFadeRange(int r1, int g1, int b1, int a1,
1501                                int r2, int g2, int b2, int a2, fixed_t time)
1502 {
1503 	player_t *viewer;
1504 	float ftime = (float)time / 65536.f;
1505 	bool fadingFrom = a1 >= 0;
1506 	float fr1 = 0.f, fg1 = 0.f, fb1 = 0.f, fa1 = 0.f;
1507 	float fr2, fg2, fb2, fa2;
1508 
1509 	fr2 = (float)r2 / 255.f;
1510 	fg2 = (float)g2 / 255.f;
1511 	fb2 = (float)b2 / 255.f;
1512 	fa2 = (float)a2 / 65536.f;
1513 
1514 	if (fadingFrom)
1515 	{
1516 		fr1 = (float)r1 / 255.f;
1517 		fg1 = (float)g1 / 255.f;
1518 		fb1 = (float)b1 / 255.f;
1519 		fa1 = (float)a1 / 65536.f;
1520 	}
1521 
1522 	if (activator != NULL)
1523 	{
1524 		viewer = activator->player;
1525 		if (viewer == NULL)
1526 			return;
1527 		DoActualFadeRange(viewer, ftime, fadingFrom, fr1, fg1, fb1, fa1, fr2, fg2, fb2, fa2);
1528 	}
1529 	else
1530 	{
1531 		for (Players::iterator it = players.begin();it != players.end();++it)
1532 		{
1533 			if (it->ingame())
1534 				DoActualFadeRange(&*it, ftime, fadingFrom, fr1, fg1, fb1, fa1, fr2, fg2, fb2, fa2);
1535 		}
1536 	}
1537 }
1538 
1539 
getbyte(int * & pc)1540 inline int getbyte (int *&pc)
1541 {
1542 	int res = *(BYTE *)pc;
1543 	pc = (int *)((BYTE *)pc+1);
1544 	return res;
1545 }
1546 
RunScript()1547 void DLevelScript::RunScript ()
1548 {
1549 	DACSThinker *controller = DACSThinker::ActiveThinker;
1550 	if (!controller)
1551 		return;
1552 
1553     TeleportSide = lineSide;
1554     int *locals = localvars;
1555     ScriptFunction *activeFunction = NULL;
1556 
1557 	switch (state)
1558 	{
1559 	case SCRIPT_Delayed:
1560 		// Decrement the delay counter and enter state running
1561 		// if it hits 0
1562 		if (--statedata == 0)
1563 			state = SCRIPT_Running;
1564 		break;
1565 
1566 	case SCRIPT_TagWait:
1567 		// Wait for tagged sector(s) to go inactive, then enter
1568 		// state running
1569 	{
1570 		int secnum = -1;
1571 
1572 		while ((secnum = P_FindSectorFromTag (statedata, secnum)) >= 0)
1573 			if (sectors[secnum].floordata || sectors[secnum].ceilingdata)
1574 				return;
1575 
1576 		// If we got here, none of the tagged sectors were busy
1577 		state = SCRIPT_Running;
1578 	}
1579 	break;
1580 
1581 	case SCRIPT_PolyWait:
1582 		// Wait for polyobj(s) to stop moving, then enter state running
1583 		if (!PO_Busy (statedata))
1584 		{
1585 			state = SCRIPT_Running;
1586 		}
1587 		break;
1588 
1589 	case SCRIPT_ScriptWaitPre:
1590 		// Wait for a script to start running, then enter state scriptwait
1591 		if (controller->RunningScripts[statedata])
1592 			state = SCRIPT_ScriptWait;
1593 		break;
1594 
1595 	case SCRIPT_ScriptWait:
1596 		// Wait for a script to stop running, then enter state running
1597 		if (controller->RunningScripts[statedata])
1598 			return;
1599 
1600 		state = SCRIPT_Running;
1601 		PutFirst ();
1602 		break;
1603 
1604 	default:
1605 		break;
1606 	}
1607 
1608 	int *pc = this->pc;
1609 	int sp = this->sp;
1610 	const ACSFormat fmt = level.behavior->GetFormat();
1611 	int runaway = 0;	// used to prevent infinite loops
1612 	int pcd;
1613 	char work[4096], *workwhere = work;
1614 	const char *lookup;
1615 	int optstart = -1;
1616 	int temp;
1617 
1618 	while (state == SCRIPT_Running)
1619 	{
1620 		if (++runaway > 500000)
1621 		{
1622 			Printf (PRINT_HIGH,"Runaway script %d terminated\n", script);
1623 			state = SCRIPT_PleaseRemove;
1624 			break;
1625 		}
1626 
1627 		pcd = NEXTBYTE;
1628 		switch (pcd)
1629 		{
1630 		default:
1631 			Printf (PRINT_HIGH,"Unknown P-Code %d in script %d\n", pcd, script);
1632 			// fall through
1633 		case PCD_TERMINATE:
1634 			state = SCRIPT_PleaseRemove;
1635 			break;
1636 
1637 		case PCD_NOP:
1638 			break;
1639 
1640 		case PCD_SUSPEND:
1641 			state = SCRIPT_Suspended;
1642 			break;
1643 
1644 		case PCD_PUSHNUMBER:
1645 			PushToStack (NEXTWORD);
1646 			break;
1647 
1648 		case PCD_PUSHBYTE:
1649 			PushToStack (*(BYTE *)pc);
1650 			pc = (int *)((BYTE *)pc + 1);
1651 			break;
1652 
1653 		case PCD_PUSH2BYTES:
1654 			Stack[sp] = ((BYTE *)pc)[0];
1655 			Stack[sp+1] = ((BYTE *)pc)[1];
1656 			sp += 2;
1657 			pc = (int *)((BYTE *)pc + 2);
1658 			break;
1659 
1660 		case PCD_PUSH3BYTES:
1661 			Stack[sp] = ((BYTE *)pc)[0];
1662 			Stack[sp+1] = ((BYTE *)pc)[1];
1663 			Stack[sp+2] = ((BYTE *)pc)[2];
1664 			sp += 3;
1665 			pc = (int *)((BYTE *)pc + 3);
1666 			break;
1667 
1668 		case PCD_PUSH4BYTES:
1669 			Stack[sp] = ((BYTE *)pc)[0];
1670 			Stack[sp+1] = ((BYTE *)pc)[1];
1671 			Stack[sp+2] = ((BYTE *)pc)[2];
1672 			Stack[sp+3] = ((BYTE *)pc)[3];
1673 			sp += 4;
1674 			pc = (int *)((BYTE *)pc + 4);
1675 			break;
1676 
1677 		case PCD_PUSH5BYTES:
1678 			Stack[sp] = ((BYTE *)pc)[0];
1679 			Stack[sp+1] = ((BYTE *)pc)[1];
1680 			Stack[sp+2] = ((BYTE *)pc)[2];
1681 			Stack[sp+3] = ((BYTE *)pc)[3];
1682 			Stack[sp+4] = ((BYTE *)pc)[4];
1683 			sp += 5;
1684 			pc = (int *)((BYTE *)pc + 5);
1685 			break;
1686 
1687 		case PCD_PUSHBYTES:
1688 			temp = *(BYTE *)pc;
1689 			pc = (int *)((BYTE *)pc + temp + 1);
1690 			for (temp = -temp; temp; temp++)
1691 			{
1692 				PushToStack (*((BYTE *)pc + temp));
1693 			}
1694 			break;
1695 
1696 		case PCD_DUP:
1697 			Stack[sp] = Stack[sp-1];
1698 			sp++;
1699 			break;
1700 
1701 		case PCD_SWAP:
1702 			std::swap(Stack[sp-2], Stack[sp-1]);
1703 			break;
1704 
1705 		case PCD_LSPEC1:
1706 			LineSpecials[NEXTBYTE] (activationline, activator,
1707 									STACK(1), 0, 0, 0, 0);
1708 			sp -= 1;
1709 			break;
1710 
1711 		case PCD_LSPEC2:
1712 			LineSpecials[NEXTBYTE] (activationline, activator,
1713 									STACK(2), STACK(1), 0, 0, 0);
1714 			sp -= 2;
1715 			break;
1716 
1717 		case PCD_LSPEC3:
1718 			LineSpecials[NEXTBYTE] (activationline, activator,
1719 									STACK(3), STACK(2), STACK(1), 0, 0);
1720 			sp -= 3;
1721 			break;
1722 
1723 		case PCD_LSPEC4:
1724 			LineSpecials[NEXTBYTE] (activationline, activator,
1725 									STACK(4), STACK(3), STACK(2),
1726 									STACK(1), 0);
1727 			sp -= 4;
1728 			break;
1729 
1730 		case PCD_LSPEC5:
1731 			LineSpecials[NEXTBYTE] (activationline, activator,
1732 									STACK(5), STACK(4), STACK(3),
1733 									STACK(2), STACK(1));
1734 			sp -= 5;
1735 			break;
1736 
1737 		case PCD_LSPEC1DIRECT:
1738 			temp = NEXTBYTE;
1739 			LineSpecials[temp] (activationline, activator,
1740 								pc[0], 0, 0, 0, 0);
1741 			pc += 1;
1742 			break;
1743 
1744 		case PCD_LSPEC2DIRECT:
1745 			temp = NEXTBYTE;
1746 			LineSpecials[temp] (activationline, activator,
1747 								pc[0], pc[1], 0, 0, 0);
1748 			pc += 2;
1749 			break;
1750 
1751 		case PCD_LSPEC3DIRECT:
1752 			temp = NEXTBYTE;
1753 			LineSpecials[temp] (activationline, activator,
1754 								pc[0], pc[1], pc[2], 0, 0);
1755 			pc += 3;
1756 			break;
1757 
1758 		case PCD_LSPEC4DIRECT:
1759 			temp = NEXTBYTE;
1760 			LineSpecials[temp] (activationline, activator,
1761 								pc[0], pc[1], pc[2], pc[3], 0);
1762 			pc += 4;
1763 			break;
1764 
1765 		case PCD_LSPEC5DIRECT:
1766 			temp = NEXTBYTE;
1767 			LineSpecials[temp] (activationline, activator,
1768 								pc[0], pc[1], pc[2], pc[3], pc[4]);
1769 			pc += 5;
1770 			break;
1771 
1772 		case PCD_LSPEC1DIRECTB:
1773 			LineSpecials[((BYTE *)pc)[0]] (activationline, activator,
1774 				((BYTE *)pc)[1], 0, 0, 0, 0);
1775 			pc = (int *)((BYTE *)pc + 2);
1776 			break;
1777 
1778 		case PCD_LSPEC2DIRECTB:
1779 			LineSpecials[((BYTE *)pc)[0]] (activationline, activator,
1780 				((BYTE *)pc)[1], ((BYTE *)pc)[2], 0, 0, 0);
1781 			pc = (int *)((BYTE *)pc + 3);
1782 			break;
1783 
1784 		case PCD_LSPEC3DIRECTB:
1785 			LineSpecials[((BYTE *)pc)[0]] (activationline, activator,
1786 				((BYTE *)pc)[1], ((BYTE *)pc)[2], ((BYTE *)pc)[3], 0, 0);
1787 			pc = (int *)((BYTE *)pc + 4);
1788 			break;
1789 
1790 		case PCD_LSPEC4DIRECTB:
1791 			LineSpecials[((BYTE *)pc)[0]] (activationline, activator,
1792 				((BYTE *)pc)[1], ((BYTE *)pc)[2], ((BYTE *)pc)[3],
1793 				((BYTE *)pc)[4], 0);
1794 			pc = (int *)((BYTE *)pc + 5);
1795 			break;
1796 
1797 		case PCD_LSPEC5DIRECTB:
1798 			LineSpecials[((BYTE *)pc)[0]] (activationline, activator,
1799 				((BYTE *)pc)[1], ((BYTE *)pc)[2], ((BYTE *)pc)[3],
1800 				((BYTE *)pc)[4], ((BYTE *)pc)[5]);
1801 			pc = (int *)((BYTE *)pc + 6);
1802 			break;
1803 
1804 		case PCD_CALL:
1805 		case PCD_CALLDISCARD:
1806 			{
1807 				int funcnum;
1808 				int i;
1809 				ScriptFunction *func;
1810 
1811 				funcnum = NEXTBYTE;
1812 				func = level.behavior->GetFunction (funcnum);
1813 				if (func == NULL)
1814 				{
1815 					Printf (PRINT_HIGH,"Function %d in script %d out of range\n", funcnum, script);
1816 					state = SCRIPT_PleaseRemove;
1817 					break;
1818 				}
1819 				if (sp + func->LocalCount + 32 > STACK_SIZE)
1820 				{ // 32 is the margin for the function's working space
1821 					Printf (PRINT_HIGH,"Out of stack space in script %d\n", script);
1822 					state = SCRIPT_PleaseRemove;
1823 					break;
1824 				}
1825 				// The function's first argument is also its first local variable.
1826 				locals = &Stack[sp - func->ArgCount];
1827 				// Make space on the stack for any other variables the function uses.
1828 				for (i = 0; i < func->LocalCount; ++i)
1829 				{
1830 					Stack[sp+i] = 0;
1831 				}
1832 				sp += i;
1833 				((CallReturn *)&Stack[sp])->ReturnAddress = level.behavior->PC2Ofs (pc);
1834 				((CallReturn *)&Stack[sp])->ReturnFunction = activeFunction;
1835 				((CallReturn *)&Stack[sp])->bDiscardResult = (pcd == PCD_CALLDISCARD);
1836 				sp += sizeof(CallReturn)/sizeof(int);
1837 				pc = level.behavior->Ofs2PC (func->Address);
1838 				activeFunction = func;
1839 			}
1840 			break;
1841 
1842 		case PCD_RETURNVOID:
1843 		case PCD_RETURNVAL:
1844 			{
1845 				int value;
1846 				CallReturn *retState;
1847 
1848 				if (pcd == PCD_RETURNVAL)
1849 				{
1850 					value = Stack[--sp];
1851 				}
1852 				else
1853 				{
1854 					value = 0;
1855 				}
1856 				sp -= sizeof(CallReturn)/sizeof(int);
1857 				retState = (CallReturn *)&Stack[sp];
1858 				pc = level.behavior->Ofs2PC (retState->ReturnAddress);
1859 				sp -= activeFunction->ArgCount + activeFunction->LocalCount;
1860 				activeFunction = retState->ReturnFunction;
1861 				if (activeFunction == NULL)
1862 				{
1863 					locals = localvars;
1864 				}
1865 				else
1866 				{
1867 					locals = &Stack[sp - activeFunction->ArgCount - activeFunction->LocalCount];
1868 				}
1869 				if (!retState->bDiscardResult)
1870 				{
1871 					Stack[sp++] = value;
1872 				}
1873 			}
1874 			break;
1875 
1876 		case PCD_ADD:
1877 			STACK(2) = STACK(2) + STACK(1);
1878 			sp--;
1879 			break;
1880 
1881 		case PCD_SUBTRACT:
1882 			STACK(2) = STACK(2) - STACK(1);
1883 			sp--;
1884 			break;
1885 
1886 		case PCD_MULTIPLY:
1887 			STACK(2) = STACK(2) * STACK(1);
1888 			sp--;
1889 			break;
1890 
1891 		case PCD_DIVIDE:
1892 			STACK(2) = STACK(2) / STACK(1);
1893 			sp--;
1894 			break;
1895 
1896 		case PCD_MODULUS:
1897 			STACK(2) = STACK(2) % STACK(1);
1898 			sp--;
1899 			break;
1900 
1901 		case PCD_EQ:
1902 			STACK(2) = (STACK(2) == STACK(1));
1903 			sp--;
1904 			break;
1905 
1906 		case PCD_NE:
1907 			STACK(2) = (STACK(2) != STACK(1));
1908 			sp--;
1909 			break;
1910 
1911 		case PCD_LT:
1912 			STACK(2) = (STACK(2) < STACK(1));
1913 			sp--;
1914 			break;
1915 
1916 		case PCD_GT:
1917 			STACK(2) = (STACK(2) > STACK(1));
1918 			sp--;
1919 			break;
1920 
1921 		case PCD_LE:
1922 			STACK(2) = (STACK(2) <= STACK(1));
1923 			sp--;
1924 			break;
1925 
1926 		case PCD_GE:
1927 			STACK(2) = (STACK(2) >= STACK(1));
1928 			sp--;
1929 			break;
1930 
1931 		case PCD_ASSIGNSCRIPTVAR:
1932 			locals[NEXTBYTE] = STACK(1);
1933 			sp--;
1934 			break;
1935 
1936 
1937 		case PCD_ASSIGNMAPVAR:
1938 			level.vars[NEXTBYTE] = STACK(1);
1939 			sp--;
1940 			break;
1941 
1942 		case PCD_ASSIGNWORLDVAR:
1943 			ACS_WorldVars[NEXTBYTE] = STACK(1);
1944 			sp--;
1945 			break;
1946 
1947 		case PCD_ASSIGNGLOBALVAR:
1948 			ACS_GlobalVars[NEXTBYTE] = STACK(1);
1949 			sp--;
1950 			break;
1951 
1952 		case PCD_ASSIGNMAPARRAY:
1953 			level.behavior->SetArrayVal (ACS_WorldVars[NEXTBYTE], STACK(2), STACK(1));
1954 			sp -= 2;
1955 			break;
1956 
1957 		case PCD_PUSHSCRIPTVAR:
1958 			PushToStack (locals[NEXTBYTE]);
1959 			break;
1960 
1961 		case PCD_PUSHMAPVAR:
1962 			PushToStack (level.vars[NEXTBYTE]);
1963 			break;
1964 
1965 		case PCD_PUSHWORLDVAR:
1966 			PushToStack (ACS_WorldVars[NEXTBYTE]);
1967 			break;
1968 
1969 		case PCD_PUSHGLOBALVAR:
1970 			PushToStack (ACS_GlobalVars[NEXTBYTE]);
1971 			break;
1972 
1973 		case PCD_PUSHMAPARRAY:
1974 			STACK(1) = level.behavior->GetArrayVal (level.vars[NEXTBYTE], STACK(1));
1975 			break;
1976 
1977 		case PCD_ADDSCRIPTVAR:
1978 			locals[NEXTBYTE] += STACK(1);
1979 			sp--;
1980 			break;
1981 
1982 		case PCD_ADDMAPVAR:
1983 			level.vars[NEXTBYTE] += STACK(1);
1984 			sp--;
1985 			break;
1986 
1987 		case PCD_ADDWORLDVAR:
1988 			ACS_WorldVars[NEXTBYTE] += STACK(1);
1989 			sp--;
1990 			break;
1991 
1992 		case PCD_ADDGLOBALVAR:
1993 			ACS_GlobalVars[NEXTBYTE] += STACK(1);
1994 			sp--;
1995 			break;
1996 
1997 		case PCD_ADDMAPARRAY:
1998 			{
1999 				int a = ACS_WorldVars[NEXTBYTE];
2000 				int i = STACK(2);
2001 				level.behavior->SetArrayVal (a, i,
2002 					level.behavior->GetArrayVal (a, i) + STACK(1));
2003 				sp -= 2;
2004 			}
2005 			break;
2006 
2007 		case PCD_SUBSCRIPTVAR:
2008 			locals[NEXTBYTE] -= STACK(1);
2009 			sp--;
2010 			break;
2011 
2012 		case PCD_SUBMAPVAR:
2013 			level.vars[NEXTBYTE] -= STACK(1);
2014 			sp--;
2015 			break;
2016 
2017 		case PCD_SUBWORLDVAR:
2018 			ACS_WorldVars[NEXTBYTE] -= STACK(1);
2019 			sp--;
2020 			break;
2021 
2022 		case PCD_SUBGLOBALVAR:
2023 			ACS_GlobalVars[NEXTBYTE] -= STACK(1);
2024 			sp--;
2025 			break;
2026 
2027 		case PCD_SUBMAPARRAY:
2028 			{
2029 				int a = ACS_WorldVars[NEXTBYTE];
2030 				int i = STACK(2);
2031 				level.behavior->SetArrayVal (a, i,
2032 					level.behavior->GetArrayVal (a, i) - STACK(1));
2033 				sp -= 2;
2034 			}
2035 			break;
2036 
2037 		case PCD_MULSCRIPTVAR:
2038 			locals[NEXTBYTE] *= STACK(1);
2039 			sp--;
2040 			break;
2041 
2042 		case PCD_MULMAPVAR:
2043 			level.vars[NEXTBYTE] *= STACK(1);
2044 			sp--;
2045 			break;
2046 
2047 		case PCD_MULWORLDVAR:
2048 			ACS_WorldVars[NEXTBYTE] *= STACK(1);
2049 			sp--;
2050 			break;
2051 
2052 		case PCD_MULGLOBALVAR:
2053 			ACS_GlobalVars[NEXTBYTE] *= STACK(1);
2054 			sp--;
2055 			break;
2056 
2057 		case PCD_MULMAPARRAY:
2058 			{
2059 				int a = ACS_WorldVars[NEXTBYTE];
2060 				int i = STACK(2);
2061 				level.behavior->SetArrayVal (a, i,
2062 					level.behavior->GetArrayVal (a, i) * STACK(1));
2063 				sp -= 2;
2064 			}
2065 			break;
2066 
2067 		case PCD_DIVSCRIPTVAR:
2068 			locals[NEXTBYTE] /= STACK(1);
2069 			sp--;
2070 			break;
2071 
2072 		case PCD_DIVMAPVAR:
2073 			level.vars[NEXTBYTE] /= STACK(1);
2074 			sp--;
2075 			break;
2076 
2077 		case PCD_DIVWORLDVAR:
2078 			ACS_WorldVars[NEXTBYTE] /= STACK(1);
2079 			sp--;
2080 			break;
2081 
2082 		case PCD_DIVGLOBALVAR:
2083 			ACS_GlobalVars[NEXTBYTE] /= STACK(1);
2084 			sp--;
2085 			break;
2086 
2087 		case PCD_DIVMAPARRAY:
2088 			{
2089 				int a = ACS_WorldVars[NEXTBYTE];
2090 				int i = STACK(2);
2091 				level.behavior->SetArrayVal (a, i,
2092 					level.behavior->GetArrayVal (a, i) / STACK(1));
2093 				sp -= 2;
2094 			}
2095 			break;
2096 
2097 		case PCD_MODSCRIPTVAR:
2098 			locals[NEXTBYTE] %= STACK(1);
2099 			sp--;
2100 			break;
2101 
2102 		case PCD_MODMAPVAR:
2103 			level.vars[NEXTBYTE] %= STACK(1);
2104 			sp--;
2105 			break;
2106 
2107 		case PCD_MODWORLDVAR:
2108 			ACS_WorldVars[NEXTBYTE] %= STACK(1);
2109 			sp--;
2110 			break;
2111 
2112 		case PCD_MODGLOBALVAR:
2113 			ACS_GlobalVars[NEXTBYTE] %= STACK(1);
2114 			sp--;
2115 			break;
2116 
2117 		case PCD_MODMAPARRAY:
2118 			{
2119 				int a = ACS_WorldVars[NEXTBYTE];
2120 				int i = STACK(2);
2121 				level.behavior->SetArrayVal (a, i,
2122 					level.behavior->GetArrayVal (a, i) % STACK(1));
2123 				sp -= 2;
2124 			}
2125 			break;
2126 
2127 		case PCD_INCSCRIPTVAR:
2128 			++locals[NEXTBYTE];
2129 			break;
2130 
2131 		case PCD_INCMAPVAR:
2132 			++level.vars[NEXTBYTE];
2133 			break;
2134 
2135 		case PCD_INCWORLDVAR:
2136 			++ACS_WorldVars[NEXTBYTE];
2137 			break;
2138 
2139 		case PCD_INCGLOBALVAR:
2140 			++ACS_GlobalVars[NEXTBYTE];
2141 			break;
2142 
2143 		case PCD_INCMAPARRAY:
2144 			{
2145 				int a = ACS_WorldVars[NEXTBYTE];
2146 				int i = STACK(2);
2147 				level.behavior->SetArrayVal (a, i,
2148 					level.behavior->GetArrayVal (a, i) + 1);
2149 				sp--;
2150 			}
2151 			break;
2152 
2153 		case PCD_DECSCRIPTVAR:
2154 			--locals[NEXTBYTE];
2155 			break;
2156 
2157 		case PCD_DECMAPVAR:
2158 			--level.vars[NEXTBYTE];
2159 			break;
2160 
2161 		case PCD_DECWORLDVAR:
2162 			--ACS_WorldVars[NEXTBYTE];
2163 			break;
2164 
2165 		case PCD_DECGLOBALVAR:
2166 			--ACS_GlobalVars[NEXTBYTE];
2167 			break;
2168 
2169 		case PCD_DECMAPARRAY:
2170 			{
2171 				int a = ACS_WorldVars[NEXTBYTE];
2172 				int i = STACK(2);
2173 				level.behavior->SetArrayVal (a, i,
2174 					level.behavior->GetArrayVal (a, i) - 1);
2175 				sp--;
2176 			}
2177 			break;
2178 
2179 		case PCD_GOTO:
2180 			pc = level.behavior->Ofs2PC (*pc);
2181 			break;
2182 
2183 		case PCD_IFGOTO:
2184 			if (STACK(1))
2185 				pc = level.behavior->Ofs2PC (*pc);
2186 			else
2187 				pc++;
2188 			sp--;
2189 			break;
2190 
2191 		case PCD_DROP:
2192 			sp--;
2193 			break;
2194 
2195 		case PCD_DELAY:
2196 			state = SCRIPT_Delayed;
2197 			statedata = STACK(1);
2198 			sp--;
2199 			break;
2200 
2201 		case PCD_DELAYDIRECT:
2202 			state = SCRIPT_Delayed;
2203 			statedata = NEXTWORD;
2204 			break;
2205 
2206 		case PCD_DELAYDIRECTB:
2207 			state = SCRIPT_Delayed;
2208 			statedata = *(BYTE *)pc;
2209 			pc = (int *)((BYTE *)pc + 1);
2210 			break;
2211 
2212 		case PCD_RANDOM:
2213 			STACK(2) = Random (STACK(2), STACK(1));
2214 			sp--;
2215 			break;
2216 
2217 		case PCD_RANDOMDIRECT:
2218 			PushToStack (Random (pc[0], pc[1]));
2219 			pc += 2;
2220 			break;
2221 
2222 		case PCD_RANDOMDIRECTB:
2223 			PushToStack (Random (((BYTE *)pc)[0], ((BYTE *)pc)[1]));
2224 			pc = (int *)((BYTE *)pc + 2);
2225 			break;
2226 
2227 		case PCD_THINGCOUNT:
2228 			STACK(2) = ThingCount (STACK(2), STACK(1));
2229 			sp--;
2230 			break;
2231 
2232 		case PCD_THINGCOUNTDIRECT:
2233 			PushToStack (ThingCount (pc[0], pc[1]));
2234 			pc += 2;
2235 			break;
2236 
2237 		case PCD_TAGWAIT:
2238 			state = SCRIPT_TagWait;
2239 			statedata = STACK(1);
2240 			sp--;
2241 			break;
2242 
2243 		case PCD_TAGWAITDIRECT:
2244 			state = SCRIPT_TagWait;
2245 			statedata = NEXTWORD;
2246 			break;
2247 
2248 		case PCD_POLYWAIT:
2249 			state = SCRIPT_PolyWait;
2250 			statedata = STACK(1);
2251 			sp--;
2252 			break;
2253 
2254 		case PCD_POLYWAITDIRECT:
2255 			state = SCRIPT_PolyWait;
2256 			statedata = NEXTWORD;
2257 			break;
2258 
2259 		case PCD_CHANGEFLOOR:
2260 			ChangeFlat (STACK(2), STACK(1), 0);
2261 			sp -= 2;
2262 			break;
2263 
2264 		case PCD_CHANGEFLOORDIRECT:
2265 			ChangeFlat (pc[0], pc[1], 0);
2266 			pc += 2;
2267 			break;
2268 
2269 		case PCD_CHANGECEILING:
2270 			ChangeFlat (STACK(2), STACK(1), 1);
2271 			sp -= 2;
2272 			break;
2273 
2274 		case PCD_CHANGECEILINGDIRECT:
2275 			ChangeFlat (pc[0], pc[1], 1);
2276 			pc += 2;
2277 			break;
2278 
2279 		case PCD_RESTART:
2280 			pc = level.behavior->FindScript (script);
2281 			break;
2282 
2283 		case PCD_ANDLOGICAL:
2284 			STACK(2) = (STACK(2) && STACK(1));
2285 			sp--;
2286 			break;
2287 
2288 		case PCD_ORLOGICAL:
2289 			STACK(2) = (STACK(2) || STACK(1));
2290 			sp--;
2291 			break;
2292 
2293 		case PCD_ANDBITWISE:
2294 			STACK(2) = (STACK(2) & STACK(1));
2295 			sp--;
2296 			break;
2297 
2298 		case PCD_ORBITWISE:
2299 			STACK(2) = (STACK(2) | STACK(1));
2300 			sp--;
2301 			break;
2302 
2303 		case PCD_EORBITWISE:
2304 			STACK(2) = (STACK(2) ^ STACK(1));
2305 			sp--;
2306 			break;
2307 
2308 		case PCD_NEGATELOGICAL:
2309 			STACK(1) = !STACK(1);
2310 			break;
2311 
2312 		case PCD_LSHIFT:
2313 			STACK(2) = (STACK(2) << STACK(1));
2314 			sp--;
2315 			break;
2316 
2317 		case PCD_RSHIFT:
2318 			STACK(2) = (STACK(2) >> STACK(1));
2319 			sp--;
2320 			break;
2321 
2322 		case PCD_UNARYMINUS:
2323 			STACK(1) = -STACK(1);
2324 			break;
2325 
2326 		case PCD_IFNOTGOTO:
2327 			if (!STACK(1))
2328 				pc = level.behavior->Ofs2PC (*pc);
2329 			else
2330 				pc++;
2331 			sp--;
2332 			break;
2333 
2334 		case PCD_LINESIDE:
2335 			PushToStack (lineSide);
2336 			break;
2337 
2338 		case PCD_SCRIPTWAIT:
2339 			statedata = STACK(1);
2340 			if (controller->RunningScripts[statedata])
2341 				state = SCRIPT_ScriptWait;
2342 			else
2343 				state = SCRIPT_ScriptWaitPre;
2344 			sp--;
2345 			PutLast ();
2346 			break;
2347 
2348 		case PCD_SCRIPTWAITDIRECT:
2349 			state = SCRIPT_ScriptWait;
2350 			statedata = NEXTWORD;
2351 			PutLast ();
2352 			break;
2353 
2354 		case PCD_CLEARLINESPECIAL:
2355 			if (activationline)
2356 				activationline->special = 0;
2357 			break;
2358 
2359 		case PCD_CASEGOTO:
2360 			if (STACK(1) == NEXTWORD)
2361 			{
2362 				pc = level.behavior->Ofs2PC (*pc);
2363 				sp--;
2364 			}
2365 			else
2366 			{
2367 				pc++;
2368 			}
2369 			break;
2370 
2371 		case PCD_BEGINPRINT:
2372 			workwhere = work;
2373 			work[0] = 0;
2374 			break;
2375 
2376 		case PCD_PRINTSTRING:
2377 		case PCD_PRINTLOCALIZED:
2378 			lookup = (pcd == PCD_PRINTSTRING ?
2379 				level.behavior->LookupString (STACK(1)) :
2380 				level.behavior->LocalizeString (STACK(1)));
2381 			if (lookup != NULL)
2382 			{
2383 				workwhere += sprintf (workwhere, "%s", lookup);
2384 			}
2385 			--sp;
2386 			break;
2387 
2388 		case PCD_PRINTNUMBER:
2389 			workwhere += sprintf (workwhere, "%d", STACK(1));
2390 			--sp;
2391 			break;
2392 
2393 		case PCD_PRINTCHARACTER:
2394 			workwhere[0] = STACK(1);
2395 			workwhere[1] = 0;
2396 			workwhere++;
2397 			--sp;
2398 			break;
2399 
2400 		case PCD_PRINTFIXED:
2401 			workwhere += sprintf (workwhere, "%g", FIXED2FLOAT(STACK(1)));
2402 			--sp;
2403 			break;
2404 
2405 		// [BC] Print activator's name
2406 		// [RH] Fancied up a bit
2407 		case PCD_PRINTNAME:
2408 			{
2409 				player_t *player = NULL;
2410 
2411 				if (STACK(1) == 0 || (unsigned)STACK(1) > MAXPLAYERS)
2412 				{
2413 					if (activator)
2414 					{
2415 						player = activator->player;
2416 					}
2417 				}
2418 				else if (idplayer(STACK(1)).ingame())
2419 				{
2420 					player = &idplayer(STACK(1));
2421 				}
2422 				else
2423 				{
2424 					workwhere += sprintf (workwhere, "Player %d\n",
2425 						STACK(1));
2426 					sp--;
2427 					break;
2428 				}
2429 				if (player)
2430 				{
2431 					workwhere += sprintf (workwhere, "%s",
2432 						activator->player->userinfo.netname.c_str());
2433 				}
2434 				else if (activator)
2435 				{
2436 					workwhere += sprintf (workwhere, "%s",
2437 						RUNTIME_TYPE(activator)->Name+1);
2438 				}
2439 				else
2440 				{
2441 					workwhere += sprintf (workwhere, " ");
2442 				}
2443 				sp--;
2444 			}
2445 			break;
2446 
2447 		case PCD_ENDPRINT:
2448 		case PCD_ENDPRINTBOLD:
2449 		//case PCD_MOREHUDMESSAGE:
2450 			strbin (work);
2451 			if (pcd != PCD_MOREHUDMESSAGE)
2452 			{
2453 				if (pcd == PCD_ENDPRINTBOLD || activator == NULL ||
2454 					(activator->player->mo == consoleplayer().camera))
2455 				{
2456 					strbin (work);
2457 					C_MidPrint (work);
2458 				}
2459 			}
2460 			else
2461 			{
2462 				optstart = -1;
2463 			}
2464 			break;
2465 
2466 		/*case PCD_OPTHUDMESSAGE:
2467 			optstart = sp;
2468 			break;
2469 
2470 		case PCD_ENDHUDMESSAGE:
2471 		case PCD_ENDHUDMESSAGEBOLD:
2472 			if (optstart == -1)
2473 			{
2474 				optstart = sp;
2475 			}
2476 			if (pcd == PCD_ENDHUDMESSAGEBOLD || activator == NULL ||
2477 				(activator->player->mo == consoleplayer().camera))
2478 			{
2479 				int type = Stack[optstart-6];
2480 				int id = Stack[optstart-5];
2481 				EColorRange color = CLAMPCOLOR(Stack[optstart-4]);
2482 				float x = FIXED2FLOAT(Stack[optstart-3]);
2483 				float y = FIXED2FLOAT(Stack[optstart-2]);
2484 				float holdTime = FIXED2FLOAT(Stack[optstart-1]);
2485 				DHUDMessage *msg;
2486 
2487 				switch (type)
2488 				{
2489 				default:	// normal
2490 					msg = new DHUDMessage (work, x, y, color, holdTime);
2491 					break;
2492 				case 1:		// fade out
2493 					{
2494 						float fadeTime = (optstart < sp) ?
2495 							FIXED2FLOAT(Stack[optstart]) : 0.5f;
2496 						msg = new DHUDMessageFadeOut (work, x, y, color, holdTime, fadeTime);
2497 					}
2498 					break;
2499 				case 2:		// type on, then fade out
2500 					{
2501 						float typeTime = (optstart < sp) ?
2502 							FIXED2FLOAT(Stack[optstart]) : 0.05f;
2503 						float fadeTime = (optstart < sp-1) ?
2504 							FIXED2FLOAT(Stack[optstart+1]) : 0.5f;
2505 						msg = new DHUDMessageTypeOnFadeOut (work, x, y, color, typeTime, holdTime, fadeTime);
2506 					}
2507 					break;
2508 				}
2509 				StatusBar->AttachMessage (msg, id ? 0xff000000|id : 0);
2510 			}
2511 			sp = optstart-6;
2512 			break;
2513         */
2514 		/*case PCD_SETFONT:
2515 			DoSetFont (STACK(1));
2516 			sp--;
2517 			break;
2518 
2519 		case PCD_SETFONTDIRECT:
2520 			DoSetFont (pc[0]);
2521 			pc++;
2522 			break;
2523         */
2524 		case PCD_PLAYERCOUNT:
2525 			PushToStack (CountPlayers ());
2526 			break;
2527 
2528 		case PCD_GAMETYPE:
2529 		    if (sv_gametype == 3)
2530                 PushToStack (GAME_NET_CTF);
2531             else if (sv_gametype == 2)
2532                 PushToStack (GAME_NET_TEAMDEATHMATCH);
2533 			else if (sv_gametype == 1)
2534 				PushToStack (GAME_NET_DEATHMATCH);
2535 			else if (multiplayer)
2536 				PushToStack (GAME_NET_COOPERATIVE);
2537 			else
2538 				PushToStack (GAME_SINGLE_PLAYER);
2539 			break;
2540 
2541 		case PCD_GAMESKILL:
2542 			PushToStack (sv_skill);
2543 			break;
2544 
2545 // [BC] Start ST PCD's
2546 		case PCD_PLAYERHEALTH:
2547 			if (activator)
2548 				PushToStack (activator->health);
2549 			break;
2550 
2551 		case PCD_PLAYERARMORPOINTS:
2552 			if (activator && activator->player)
2553 				PushToStack (activator->player->armorpoints);
2554 			break;
2555 
2556 		case PCD_PLAYERFRAGS:
2557 			if (activator && activator->player)
2558 				PushToStack (activator->player->fragcount);
2559 			break;
2560 
2561 		case PCD_MUSICCHANGE:
2562 			lookup = level.behavior->LookupString (STACK(2));
2563 			if (lookup != NULL)
2564 			{
2565 				S_ChangeMusic (lookup, STACK(1));
2566 			}
2567 			sp -= 2;
2568 			break;
2569 
2570 		case PCD_SINGLEPLAYER:
2571 			PushToStack (!netgame);
2572 			break;
2573 // [BC] End ST PCD's
2574 
2575 		case PCD_TIMER:
2576 			PushToStack (level.time);
2577 			break;
2578 
2579 		case PCD_SECTORSOUND:
2580 			lookup = level.behavior->LookupString (STACK(2));
2581 			if (lookup != NULL)
2582 			{
2583 				if (activationline)
2584 				{
2585 					S_Sound (
2586 						activationline->frontsector->soundorg,
2587 						CHAN_BODY,
2588 						lookup,
2589 						(float)(STACK(1)) / 127.f,
2590 						ATTN_NORM);
2591 				}
2592 				else
2593 				{
2594 					S_Sound (
2595 						CHAN_BODY,
2596 						lookup,
2597 						(float)(STACK(1)) / 127.f,
2598 						ATTN_NORM);
2599 				}
2600 			}
2601 			sp -= 2;
2602 			break;
2603 
2604 		case PCD_AMBIENTSOUND:
2605 			lookup = level.behavior->LookupString (STACK(2));
2606 			if (lookup != NULL)
2607 			{
2608 				S_Sound (CHAN_AUTO,
2609 						 lookup,
2610 						 (float)(STACK(1)) / 127.f, ATTN_NONE);
2611 			}
2612 			sp -= 2;
2613 			break;
2614 
2615 		case PCD_LOCALAMBIENTSOUND:
2616 			lookup = level.behavior->LookupString (STACK(2));
2617 			if (lookup != NULL && consoleplayer().camera == activator)
2618 			{
2619 				S_Sound (CHAN_AUTO,
2620 						 lookup,
2621 						 (float)(STACK(1)) / 127.f, ATTN_NONE);
2622 			}
2623 			sp -= 2;
2624 			break;
2625 
2626 		case PCD_ACTIVATORSOUND:
2627 			lookup = level.behavior->LookupString (STACK(2));
2628 			if (lookup != NULL)
2629 			{
2630 				S_Sound (activator, CHAN_AUTO,
2631 						 lookup,
2632 						 (float)(STACK(1)) / 127.f, ATTN_NORM);
2633 			}
2634 			sp -= 2;
2635 			break;
2636 
2637 		case PCD_SOUNDSEQUENCE:
2638 			lookup = level.behavior->LookupString (STACK(1));
2639 			if (lookup != NULL)
2640 			{
2641 				if (activationline)
2642 				{
2643 					SN_StartSequence (
2644 						activationline->frontsector,
2645 						lookup);
2646 				}
2647 			}
2648 			sp--;
2649 			break;
2650 
2651 		case PCD_SETLINETEXTURE:
2652 			SetLineTexture (STACK(4), STACK(3), STACK(2), STACK(1));
2653 			sp -= 4;
2654 			break;
2655 
2656 		case PCD_SETLINEBLOCKING:
2657 			{
2658 				int line = -1;
2659 
2660 				while ((line = P_FindLineFromID (STACK(2), line)) >= 0)
2661 				{
2662 					switch (STACK(1))
2663 					{
2664 					case BLOCK_NOTHING:
2665 						lines[line].flags &= ~(ML_BLOCKING|ML_BLOCKEVERYTHING);
2666 						break;
2667 					case BLOCK_CREATURES:
2668 					default:
2669 						lines[line].flags &= ~ML_BLOCKEVERYTHING;
2670 						lines[line].flags |= ML_BLOCKING;
2671 						break;
2672 					case BLOCK_EVERYTHING:
2673 						lines[line].flags |= ML_BLOCKING|ML_BLOCKEVERYTHING;
2674 						break;
2675 					}
2676 				}
2677 
2678 				sp -= 2;
2679 			}
2680 			break;
2681 
2682 		case PCD_SETLINEMONSTERBLOCKING:
2683 			{
2684 				int line = -1;
2685 
2686 				while ((line = P_FindLineFromID (STACK(2), line)) >= 0)
2687 				{
2688 					if (STACK(1))
2689 						lines[line].flags |= ML_BLOCKMONSTERS;
2690 					else
2691 						lines[line].flags &= ~ML_BLOCKMONSTERS;
2692 				}
2693 
2694 				sp -= 2;
2695 			}
2696 			break;
2697 
2698 		case PCD_SETLINESPECIAL:
2699 			{
2700 				int linenum = -1;
2701 
2702 				while ((linenum = P_FindLineFromID (STACK(7), linenum)) >= 0) {
2703 					line_t *line = &lines[linenum];
2704 
2705 					line->special = STACK(6);
2706 					line->args[0] = STACK(5);
2707 					line->args[1] = STACK(4);
2708 					line->args[2] = STACK(3);
2709 					line->args[3] = STACK(2);
2710 					line->args[4] = STACK(1);
2711 				}
2712 				sp -= 7;
2713 			}
2714 			break;
2715 
2716 		case PCD_SETTHINGSPECIAL:
2717 			{
2718 				FActorIterator iterator (STACK(7));
2719 				AActor *actor;
2720 
2721 				while ( (actor = iterator.Next ()) )
2722 				{
2723 					actor->special = STACK(6);
2724 					actor->args[0] = STACK(5);
2725 					actor->args[1] = STACK(4);
2726 					actor->args[2] = STACK(3);
2727 					actor->args[3] = STACK(2);
2728 					actor->args[4] = STACK(1);
2729 				}
2730 				sp -= 7;
2731 			}
2732 			break;
2733 
2734 		case PCD_THINGSOUND:
2735 			lookup = level.behavior->LookupString (STACK(2));
2736 			if (lookup != NULL)
2737 			{
2738 				FActorIterator iterator (STACK(3));
2739 				AActor *spot;
2740 
2741 				while ( (spot = iterator.Next ()) )
2742 				{
2743 					S_Sound (spot, CHAN_BODY,
2744 							 lookup,
2745 							 (float)(STACK(1))/127.f, ATTN_NORM);
2746 				}
2747 			}
2748 			sp -= 3;
2749 			break;
2750 
2751 
2752 		case PCD_FIXEDMUL:
2753 			STACK(2) = FixedMul (STACK(2), STACK(1));
2754 			sp--;
2755 			break;
2756 
2757 		case PCD_FIXEDDIV:
2758 			STACK(2) = FixedDiv (STACK(2), STACK(1));
2759 			sp--;
2760 			break;
2761 
2762 		case PCD_SETGRAVITY:
2763 			level.gravity = (float)STACK(1) / 65536.f;
2764 			sp--;
2765 			break;
2766 
2767 		case PCD_SETGRAVITYDIRECT:
2768 			level.gravity = (float)pc[0] / 65536.f;
2769 			pc++;
2770 			break;
2771 
2772 		case PCD_SETAIRCONTROL:
2773 			level.aircontrol = STACK(1);
2774 			sp--;
2775 			G_AirControlChanged ();
2776 			break;
2777 
2778 		case PCD_SETAIRCONTROLDIRECT:
2779 			level.aircontrol = pc[0];
2780 			pc++;
2781 			G_AirControlChanged ();
2782 			break;
2783 
2784 		/*case PCD_SPAWN:
2785 			STACK(6) = DoSpawn (STACK(6), STACK(5), STACK(4), STACK(3), STACK(2), STACK(1));
2786 			sp -= 5;
2787 			break;
2788 
2789 		case PCD_SPAWNDIRECT:
2790 			PushToStack (DoSpawn (pc[0], pc[1], pc[2], pc[3], pc[4], pc[5]));
2791 			pc += 6;
2792 			break;
2793 
2794 		case PCD_SPAWNSPOT:
2795 			STACK(4) = DoSpawnSpot (STACK(4), STACK(3), STACK(2), STACK(1));
2796 			sp -= 3;
2797 			break;
2798 
2799 		case PCD_SPAWNSPOTDIRECT:
2800 			PushToStack (DoSpawnSpot (pc[0], pc[1], pc[2], pc[3]));
2801 			pc += 4;
2802 			break;*/
2803 
2804 		case PCD_CLEARINVENTORY:
2805 			ClearInventory (activator);
2806 			break;
2807 
2808 		case PCD_GIVEINVENTORY:
2809 			GiveInventory (activator, level.behavior->LookupString (STACK(2)), STACK(1));
2810 			sp -= 2;
2811 			break;
2812 
2813 		case PCD_GIVEINVENTORYDIRECT:
2814 			GiveInventory (activator, level.behavior->LookupString (pc[0]), pc[1]);
2815 			pc += 2;
2816 			break;
2817 
2818 		case PCD_TAKEINVENTORY:
2819 			TakeInventory (activator, level.behavior->LookupString (STACK(2)), STACK(1));
2820 			sp -= 2;
2821 			break;
2822 
2823 		case PCD_TAKEINVENTORYDIRECT:
2824 			TakeInventory (activator, level.behavior->LookupString (pc[0]), pc[1]);
2825 			pc += 2;
2826 			break;
2827 
2828 		case PCD_CHECKINVENTORY:
2829 			STACK(1) = CheckInventory (activator, level.behavior->LookupString (STACK(1)));
2830 			break;
2831 
2832 		case PCD_CHECKINVENTORYDIRECT:
2833 			PushToStack (CheckInventory (activator, level.behavior->LookupString (pc[0])));
2834 			pc += 1;
2835 			break;
2836 
2837 		case PCD_SETMUSIC:
2838 			S_ChangeMusic (level.behavior->LookupString (STACK(3)), STACK(2));
2839 			sp -= 3;
2840 			break;
2841 
2842 		case PCD_SETMUSICDIRECT:
2843 			S_ChangeMusic (level.behavior->LookupString (pc[0]), pc[1]);
2844 			pc += 3;
2845 			break;
2846 
2847 		case PCD_LOCALSETMUSIC:
2848 			if (activator == consoleplayer().mo)
2849 			{
2850 				S_ChangeMusic (level.behavior->LookupString (STACK(3)), STACK(2));
2851 			}
2852 			sp -= 3;
2853 			break;
2854 
2855 		case PCD_LOCALSETMUSICDIRECT:
2856 			if (activator == consoleplayer().mo)
2857 			{
2858 				S_ChangeMusic (level.behavior->LookupString (pc[0]), pc[1]);
2859 			}
2860 			pc += 3;
2861 			break;
2862 
2863 		case PCD_FADETO:
2864 			DoFadeTo (STACK(5), STACK(4), STACK(3), STACK(2), STACK(1));
2865 			sp -= 5;
2866 			break;
2867 
2868 		case PCD_FADERANGE:
2869 			DoFadeRange (STACK(9), STACK(8), STACK(7), STACK(6),
2870 						 STACK(5), STACK(4), STACK(3), STACK(2), STACK(1));
2871 			sp -= 9;
2872 			break;
2873 
2874 		case PCD_CANCELFADE:
2875 			{
2876 				TThinkerIterator<DFlashFader> iterator;
2877 				DFlashFader *fader;
2878 
2879 				while ( (fader = iterator.Next()) )
2880 				{
2881 					if (activator == NULL || fader->WhoFor() == activator)
2882 					{
2883 						fader->Cancel ();
2884 					}
2885 				}
2886 			}
2887 			break;
2888 
2889 		/*case PCD_PLAYMOVIE:
2890 			STACK(1) = I_PlayMovie (level.behavior->LookupString (STACK(1)));
2891 			break;
2892         */
2893 		case PCD_GETACTORX:
2894 		case PCD_GETACTORY:
2895 		case PCD_GETACTORZ:
2896 			{
2897 				AActor *actor;
2898 
2899 				if (STACK(1) == 0)
2900 				{
2901 					actor = activator;
2902 				}
2903 				else
2904 				{
2905 					FActorIterator iterator (STACK(1));
2906 					actor = iterator.Next ();
2907 				}
2908 				if (actor == NULL)
2909 				{
2910 					STACK(1) = 0;
2911 				}
2912 				else
2913 				{
2914 					STACK(1) = (&actor->x)[pcd - PCD_GETACTORX];
2915 				}
2916 			}
2917 			break;
2918 
2919 		case PCD_SETFLOORTRIGGER:
2920 			new DPlaneWatcher (activator, activationline, lineSide, false, STACK(8),
2921 				STACK(7), STACK(6), STACK(5), STACK(4), STACK(3), STACK(2), STACK(1));
2922 			sp -= 8;
2923 			break;
2924 
2925 		case PCD_SETCEILINGTRIGGER:
2926 			new DPlaneWatcher (activator, activationline, lineSide, true, STACK(8),
2927 				STACK(7), STACK(6), STACK(5), STACK(4), STACK(3), STACK(2), STACK(1));
2928 			sp -= 8;
2929 			break;
2930 
2931 		/*case PCD_STARTTRANSLATION:
2932 			{
2933 				int i = STACK(1);
2934 				sp--;
2935 				if (i >= 1 && i <= MAX_ACS_TRANSLATIONS)
2936 				{
2937 					translation = &translationtables[TRANSLATION_LevelScripted][i*256-256];
2938 					for (i = 0; i < 256; ++i)
2939 					{
2940 						translation[i] = i;
2941 					}
2942 				}
2943 			}
2944 			break;
2945 
2946 		case PCD_TRANSLATIONRANGE1:
2947 			{ // translation using palette shifting
2948 				int start = STACK(4);
2949 				int end = STACK(3);
2950 				int pal1 = STACK(2);
2951 				int pal2 = STACK(1);
2952 				fixed_t palcol, palstep;
2953 				sp -= 4;
2954 
2955 				if (translation == NULL)
2956 				{
2957 					break;
2958 				}
2959 				if (start > end)
2960 				{
2961 					swap (start, end);
2962 					swap (pal1, pal2);
2963 				}
2964 				else if (start == end)
2965 				{
2966 					translation[start] = pal1;
2967 					break;
2968 				}
2969 				palcol = pal1 << FRACBITS;
2970 				palstep = ((pal2 << FRACBITS) - palcol) / (end - start);
2971 				for (int i = start; i <= end; palcol += palstep, ++i)
2972 				{
2973 					translation[i] = palcol >> FRACBITS;
2974 				}
2975 			}
2976 			break;
2977 
2978 		case PCD_TRANSLATIONRANGE2:
2979 			{ // translation using RGB values
2980 			  // (would HSV be a good idea too?)
2981 				int start = STACK(8);
2982 				int end = STACK(7);
2983 				fixed_t r1 = STACK(6) << FRACBITS;
2984 				fixed_t g1 = STACK(5) << FRACBITS;
2985 				fixed_t b1 = STACK(4) << FRACBITS;
2986 				fixed_t r2 = STACK(3) << FRACBITS;
2987 				fixed_t g2 = STACK(2) << FRACBITS;
2988 				fixed_t b2 = STACK(1) << FRACBITS;
2989 				fixed_t r, g, b;
2990 				fixed_t rs, gs, bs;
2991 				sp -= 8;
2992 
2993 				if (translation == NULL)
2994 				{
2995 					break;
2996 				}
2997 				if (start > end)
2998 				{
2999 					swap (start, end);
3000 					r = r2;
3001 					g = g2;
3002 					b = b2;
3003 					rs = r1 - r2;
3004 					gs = g1 - g2;
3005 					bs = b1 - b2;
3006 				}
3007 				else
3008 				{
3009 					r = r1;
3010 					g = g1;
3011 					b = b1;
3012 					rs = r2 - r1;
3013 					gs = g2 - g1;
3014 					bs = b2 - b1;
3015 				}
3016 				if (start == end)
3017 				{
3018 					translation[start] = ColorMatcher.Pick
3019 						(r >> FRACBITS, g >> FRACBITS, b >> FRACBITS);
3020 					break;
3021 				}
3022 				rs /= (end - start);
3023 				gs /= (end - start);
3024 				bs /= (end - start);
3025 				for (int i = start; i <= end; ++i)
3026 				{
3027 					translation[i] = ColorMatcher.Pick
3028 						(r >> FRACBITS, g >> FRACBITS, b >> FRACBITS);
3029 					r += rs;
3030 					g += gs;
3031 					b += bs;
3032 				}
3033 			}
3034 			break;
3035 
3036 		case PCD_ENDTRANSLATION:
3037 			// This might be useful for hardware rendering, but
3038 			// for software it is superfluous.
3039 			translation = NULL;
3040 			break;
3041         */
3042 
3043 		case PCD_SIN:
3044 			STACK(1) = finesine[(STACK(1)<<16)>>ANGLETOFINESHIFT];
3045 			break;
3046 
3047 		case PCD_COS:
3048 			STACK(1) = finecosine[(STACK(1)<<16)>>ANGLETOFINESHIFT];
3049 			break;
3050 
3051 		case PCD_VECTORANGLE:
3052 			STACK(2) = R_PointToAngle2 (0, 0, STACK(2), STACK(1)) >> 16;
3053 			sp--;
3054 			break;
3055 
3056 		/*case PCD_CHECKWEAPON:
3057 			if (activator == NULL || activator->player == NULL)
3058 			{ // Non-players do not have ready weapons
3059 				STACK(1) = 0;
3060 			}
3061 			else
3062 			{
3063 				STACK(1) = 0 == strcmp (level.behavior->LookupString (STACK(1)),
3064 					wpnlev1info[activator->player->readyweapon]->type->Name+1);
3065 			}
3066 			break;
3067 
3068 		case PCD_SETWEAPON:
3069 			if (activator == NULL || activator->player == NULL)
3070 			{
3071 				STACK(1) = 0;
3072 			}
3073 			else
3074 			{
3075 				int i;
3076 
3077 				for (i = 0; i < NUMWEAPONS; ++i)
3078 				{
3079 					if (0 == strcmp (level.behavior->LookupString (STACK(1)),
3080 						wpnlev1info[i]->type->Name+1))
3081 					{
3082 						break;
3083 					}
3084 				}
3085 				if (i >= NUMWEAPONS || !activator->player->weaponowned[i])
3086 				{
3087 					STACK(1) = 0;
3088 				}
3089 				else
3090 				{
3091 					STACK(1) = 1;
3092 					if (activator->player->readyweapon != i)
3093 					{
3094 						activator->player->pendingweapon = (weapontype_t)i;
3095 					}
3096 				}
3097 			}
3098 			break;
3099         */
3100 		}
3101 	}
3102 
3103 	this->pc = pc;
3104 	this->sp = sp;
3105 
3106 	if (state == SCRIPT_PleaseRemove)
3107 	{
3108 		Unlink ();
3109 		if (!controller)
3110 			return;
3111 
3112 		if (controller->RunningScripts[script] == this)
3113 			controller->RunningScripts[script] = NULL;
3114 		this->Destroy ();
3115 	}
3116 }
3117 
P_GetScriptGoing(AActor * who,line_t * where,int num,int * code,int lineSide,int arg0,int arg1,int arg2,int always,bool delay)3118 static bool P_GetScriptGoing (AActor *who, line_t *where, int num, int *code,
3119 	int lineSide, int arg0, int arg1, int arg2, int always, bool delay)
3120 {
3121 	DACSThinker *controller = DACSThinker::ActiveThinker;
3122 
3123 	if (controller && !always && controller->RunningScripts[num])
3124 	{
3125 		if (controller->RunningScripts[num]->GetState () == DLevelScript::SCRIPT_Suspended)
3126 		{
3127 			controller->RunningScripts[num]->SetState (DLevelScript::SCRIPT_Running);
3128 			return true;
3129 		}
3130 		return false;
3131 	}
3132 
3133 	new DLevelScript (who, where, num, code, lineSide, arg0, arg1, arg2, always, delay);
3134 
3135 	return true;
3136 }
3137 
DLevelScript(AActor * who,line_t * where,int num,int * code,int lineside,int arg0,int arg1,int arg2,int always,bool delay)3138 DLevelScript::DLevelScript (AActor *who, line_t *where, int num, int *code, int lineside,
3139 							int arg0, int arg1, int arg2, int always, bool delay)
3140 {
3141 	if (DACSThinker::ActiveThinker == NULL)
3142 		new DACSThinker;
3143 
3144 	script = num;
3145 	sp = 0;
3146 	localvars[0] = arg0;
3147 	localvars[1] = arg1;
3148 	localvars[2] = arg2;
3149 	memset (localvars+3, 0, sizeof(localvars)-3*sizeof(int));
3150 	pc = code;
3151 	activator = who;
3152 	activationline = where;
3153 	lineSide = lineside;
3154 	if (delay) {
3155 		// From Hexen: Give the world some time to set itself up before
3156 		// running open scripts.
3157 		//script->state = SCRIPT_Delayed;
3158 		//script->statedata = TICRATE;
3159 		state = SCRIPT_Running;
3160 	} else {
3161 		state = SCRIPT_Running;
3162 	}
3163 
3164 	if (!always)
3165 		DACSThinker::ActiveThinker->RunningScripts[num] = this;
3166 
3167 	Link ();
3168 
3169 	DPrintf ("Script %d started.\n", num);
3170 }
3171 
SetScriptState(int script,DLevelScript::EScriptState state)3172 static void SetScriptState (int script, DLevelScript::EScriptState state)
3173 {
3174 	DACSThinker *controller = DACSThinker::ActiveThinker;
3175 	if (!controller)
3176 		return;
3177 
3178 	if (controller->RunningScripts[script])
3179 		controller->RunningScripts[script]->SetState (state);
3180 }
3181 
P_DoDeferedScripts(void)3182 void P_DoDeferedScripts (void)
3183 {
3184 	acsdefered_t *def;
3185 	int *scriptdata;
3186 	AActor *gomo = NULL;
3187 
3188 	// Handle defered scripts in this step, too
3189 	def = level.info->defered;
3190 	while (def)
3191 	{
3192 		acsdefered_t *next = def->next;
3193 		switch (def->type)
3194 		{
3195 		case acsdefered_t::defexecute:
3196 		case acsdefered_t::defexealways:
3197 			scriptdata = level.behavior->FindScript (def->script);
3198 			if (scriptdata)
3199 			{
3200 				if ((unsigned)def->playernum < MAXPLAYERS && idplayer(def->playernum).ingame())
3201 					gomo = idplayer(def->playernum).mo;
3202 
3203 				P_GetScriptGoing (gomo, NULL, def->script, scriptdata, 0, def->arg0, def->arg1, def->arg2, def->type == acsdefered_t::defexealways, true);
3204 
3205 			} else
3206 				Printf (PRINT_HIGH,"P_DoDeferredScripts: Unknown script %d\n", def->script);
3207 			break;
3208 
3209 		case acsdefered_t::defsuspend:
3210 			SetScriptState (def->script, DLevelScript::SCRIPT_Suspended);
3211 			DPrintf ("Defered suspend of script %d\n", def->script);
3212 			break;
3213 
3214 		case acsdefered_t::defterminate:
3215 			SetScriptState (def->script, DLevelScript::SCRIPT_PleaseRemove);
3216 			DPrintf ("Defered terminate of script %d\n", def->script);
3217 			break;
3218 		}
3219 		delete def;
3220 		def = next;
3221 	}
3222 	level.info->defered = NULL;
3223 }
3224 
addDefered(level_info_t * i,acsdefered_t::EType type,int script,int arg0,int arg1,int arg2,AActor * who)3225 static void addDefered (level_info_t *i, acsdefered_t::EType type, int script, int arg0, int arg1, int arg2, AActor *who)
3226 {
3227 	if (i)
3228 	{
3229 		acsdefered_t *def = new acsdefered_s;
3230 
3231 		def->next = i->defered;
3232 		def->type = type;
3233 		def->script = script;
3234 		def->arg0 = arg0;
3235 		def->arg1 = arg1;
3236 		def->arg2 = arg2;
3237 		if (who != NULL && who->player != NULL)
3238 		{
3239 			def->playernum = who->player->id;
3240 		}
3241 		else
3242 		{
3243 			def->playernum = -1;
3244 		}
3245 		i->defered = def;
3246 		DPrintf ("Script %d on map %s defered\n", script, i->mapname);
3247 	}
3248 }
3249 
P_StartScript(AActor * who,line_t * where,int script,char * map,int lineSide,int arg0,int arg1,int arg2,int always)3250 bool P_StartScript (AActor *who, line_t *where, int script, char *map, int lineSide,
3251 					int arg0, int arg1, int arg2, int always)
3252 {
3253 	if (!strnicmp (level.mapname, map, 8))
3254 	{
3255 		int *scriptdata;
3256 
3257 		if (level.behavior != NULL &&
3258 			(scriptdata = level.behavior->FindScript (script)) != NULL)
3259 		{
3260 			return P_GetScriptGoing (who, where, script,
3261 									 scriptdata,
3262 									 lineSide, arg0, arg1, arg2, always, false);
3263 		}
3264 		else
3265 		{
3266 			Printf (PRINT_HIGH,"P_StartScript: Unknown script %d\n", script);
3267 		}
3268 	}
3269 	else
3270 	{
3271 		addDefered (FindLevelInfo (map),
3272 					always ? acsdefered_t::defexealways : acsdefered_t::defexecute,
3273 					script, arg0, arg1, arg2, who);
3274 	}
3275 	return false;
3276 }
3277 
P_SuspendScript(int script,char * map)3278 void P_SuspendScript (int script, char *map)
3279 {
3280 	if (strnicmp (level.mapname, map, 8))
3281 		addDefered (FindLevelInfo (map), acsdefered_t::defsuspend, script, 0, 0, 0, NULL);
3282 	else
3283 		SetScriptState (script, DLevelScript::SCRIPT_Suspended);
3284 }
3285 
P_TerminateScript(int script,char * map)3286 void P_TerminateScript (int script, char *map)
3287 {
3288 	if (strnicmp (level.mapname, map, 8))
3289 		addDefered (FindLevelInfo (map), acsdefered_t::defterminate, script, 0, 0, 0, NULL);
3290 	else
3291 		SetScriptState (script, DLevelScript::SCRIPT_PleaseRemove);
3292 }
3293 
strbin(char * str)3294 void strbin (char *str)
3295 {
3296 	char *p = str, c;
3297 	int i;
3298 
3299 	while ( (c = *p++) ) {
3300 		if (c != '\\') {
3301 			*str++ = c;
3302 		} else {
3303 			switch (*p) {
3304 				case 'c':
3305 					*str++ = '\x8a';
3306 					break;
3307 				case 'n':
3308 					*str++ = '\n';
3309 					break;
3310 				case 't':
3311 					*str++ = '\t';
3312 					break;
3313 				case 'r':
3314 					*str++ = '\r';
3315 					break;
3316 				case '\n':
3317 					break;
3318 				case 'x':
3319 				case 'X':
3320 					c = 0;
3321 					p++;
3322 					for (i = 0; i < 2; i++) {
3323 						c <<= 4;
3324 						if (*p >= '0' && *p <= '9')
3325 							c += *p-'0';
3326 						else if (*p >= 'a' && *p <= 'f')
3327 							c += 10 + *p-'a';
3328 						else if (*p >= 'A' && *p <= 'F')
3329 							c += 10 + *p-'A';
3330 						else
3331 							break;
3332 						p++;
3333 					}
3334 					*str++ = c;
3335 					break;
3336 				case '0':
3337 				case '1':
3338 				case '2':
3339 				case '3':
3340 				case '4':
3341 				case '5':
3342 				case '6':
3343 				case '7':
3344 					c = 0;
3345 					for (i = 0; i < 3; i++) {
3346 						c <<= 3;
3347 						if (*p >= '0' && *p <= '7')
3348 							c += *p-'0';
3349 						else
3350 							break;
3351 						p++;
3352 					}
3353 					*str++ = c;
3354 					break;
3355 				default:
3356 					*str++ = *p;
3357 					break;
3358 			}
3359 			p++;
3360 		}
3361 	}
3362 	*str = 0;
3363 }
3364 
operator <<(FArchive & arc,acsdefered_s * defer)3365 FArchive &operator<< (FArchive &arc, acsdefered_s *defer)
3366 {
3367 	while (defer)
3368 	{
3369 		arc << (BYTE)1;
3370 		arc << (BYTE)defer->type << defer->script
3371 			<< defer->arg0 << defer->arg1 << defer->arg2;
3372 		defer = defer->next;
3373 	}
3374 	arc << (BYTE)0;
3375 	return arc;
3376 }
3377 
operator >>(FArchive & arc,acsdefered_s * & defertop)3378 FArchive &operator>> (FArchive &arc, acsdefered_s* &defertop)
3379 {
3380 	acsdefered_s **defer = &defertop;
3381 	BYTE inbyte;
3382 
3383 	arc >> inbyte;
3384 	while (inbyte)
3385 	{
3386 		*defer = new acsdefered_s;
3387 		arc >> inbyte;
3388 		(*defer)->type = (acsdefered_s::EType)inbyte;
3389 		arc >> (*defer)->script
3390 			>> (*defer)->arg0 >> (*defer)->arg1 >> (*defer)->arg2;
3391 		defer = &((*defer)->next);
3392 		arc >> inbyte;
3393 	}
3394 	*defer = NULL;
3395 	return arc;
3396 }
3397 
3398 
BEGIN_COMMAND(scriptstat)3399 BEGIN_COMMAND (scriptstat)
3400 {
3401 	if (DACSThinker::ActiveThinker == NULL)
3402 	{
3403 		Printf (PRINT_HIGH,"No scripts are running.\n");
3404 	}
3405 	else
3406 	{
3407 		DACSThinker::ActiveThinker->DumpScriptStatus ();
3408 	}
3409 }
END_COMMAND(scriptstat)3410 END_COMMAND (scriptstat)
3411 
3412 void DACSThinker::DumpScriptStatus ()
3413 {
3414 	static const char *stateNames[] =
3415 	{
3416 		"Running",
3417 		"Suspended",
3418 		"Delayed",
3419 		"TagWait",
3420 		"PolyWait",
3421 		"ScriptWaitPre",
3422 		"ScriptWait",
3423 		"PleaseRemove"
3424 	};
3425 	DLevelScript *script = Scripts;
3426 
3427 	while (script != NULL)
3428 	{
3429 		Printf (PRINT_HIGH,"%d: %s\n", script->script, stateNames[script->state]);
3430 		script = script->next;
3431 	}
3432 }
3433 
3434 
3435 VERSION_CONTROL (p_acs_cpp, "$Id: p_acs.cpp 4542 2014-02-09 17:39:42Z dr_sean $")
3436 
3437