1 // Emacs style mode select -*- C++ -*-
2 //----------------------------------------------------------------------------
3 //
4 // Copyright(C) 2000 Simon Howard
5 // Copyright(C) 2002-2008 Christoph Oelckers
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 //
21 //---------------------------------------------------------------------------
22 //
23 // FraggleScript is from SMMU which is under the GPL. Technically,
24 // therefore, combining the FraggleScript code with the non-free
25 // ZDoom code is a violation of the GPL.
26 //
27 // As this may be a problem for you, I hereby grant an exception to my
28 // copyright on the SMMU source (including FraggleScript). You may use
29 // any code from SMMU in (G)ZDoom, provided that:
30 //
31 //    * For any binary release of the port, the source code is also made
32 //      available.
33 //    * The copyright notice is kept on any file containing my code.
34 //
35 //
36 
37 #ifndef __T_SCRIPT_H__
38 #define __T_SCRIPT_H__
39 
40 #include "p_setup.h"
41 #include "p_lnspec.h"
42 #include "m_fixed.h"
43 #include "actor.h"
44 
45 #ifdef _MSC_VER
46 // This pragma saves 8kb of wasted code.
47 #pragma pointers_to_members( full_generality, single_inheritance )
48 #endif
49 
50 class DRunningScript;
51 
52 
53 
isop(int c)54 inline bool isop(int c)
55 {
56 	return !( ( (c)<='Z' && (c)>='A') || ( (c)<='z' && (c)>='a') ||
57 		( (c)<='9' && (c)>='0') || ( (c)=='_') );
58 }
59 
60 //==========================================================================
61 //
62 //
63 //
64 //==========================================================================
65 
66 enum
67 {
68   svt_string,
69   svt_int,
70   svt_mobj,         // a map object
71   svt_function,     // functions are stored as variables
72   svt_label,        // labels for goto calls are variables
73   svt_const,        // const
74   svt_fixed,        // haleyjd: fixed-point int - 8-17 std
75   svt_pInt,         // pointer to game int
76   svt_pMobj,        // pointer to game mobj
77   svt_linespec,		// line special (can be used as both function and constant)
78 };
79 
80 //==========================================================================
81 //
82 //
83 //
84 //==========================================================================
85 
86 struct svalue_t
87 {
88 	int type;
89 	FString string;
90 	union
91 	{
92 		int i;
93 		fixed_t f;      // haleyjd: 8-17
94 		AActor *mobj;
95 	} value;
96 
svalue_tsvalue_t97 	svalue_t()
98 	{
99 		type = svt_int;
100 		value.i = 0;
101 	}
102 
svalue_tsvalue_t103 	svalue_t(const svalue_t & other)
104 	{
105 		type = other.type;
106 		string = other.string;
107 		value = other.value;
108 	}
109 };
110 
111 int intvalue(const svalue_t & v);
112 fixed_t fixedvalue(const svalue_t & v);
113 double floatvalue(const svalue_t & v);
114 const char *stringvalue(const svalue_t & v);
115 AActor *actorvalue(const svalue_t &svalue);
116 
117 //==========================================================================
118 //
119 // varoius defines collected in a nicer manner
120 //
121 //==========================================================================
122 
123 enum
124 {
125 	VARIABLESLOTS = 16,
126 	SECTIONSLOTS = 17,
127 	T_MAXTOKENS = 256,
128 	TOKENLENGTH = 128,
129 	MAXARGS = 128,
130 	MAXSCRIPTS = 257,
131 };
132 
133 //==========================================================================
134 //
135 // One variable
136 //
137 //==========================================================================
138 struct FParser;
139 
140 struct DFsVariable : public DObject
141 {
142 	DECLARE_CLASS(DFsVariable, DObject)
143 	HAS_OBJECT_POINTERS
144 
145 public:
146 	FString Name;
147 	TObjPtr<DFsVariable> next;       // for hashing
148 
149 	int type;       // svt_string or svt_int: same as in svalue_t
150 	FString string;
151 	TObjPtr<AActor> actor;
152 
153 	union value_t
154 	{
155 		SDWORD i;
156 		fixed_t fixed;          // haleyjd: fixed-point
157 
158 		// the following are only used in the global script so we don't need to bother with them
159 		// when serializing variables.
160 		int *pI;                // pointer to game int
161 		AActor **pMobj;         // pointer to game obj
162 		void (FParser::*handler)();      // for functions
163 		const FLineSpecial *ls;
164 	} value;
165 
166 public:
167 
168 	DFsVariable(const char *_name = "");
169 
170 	void GetValue(svalue_t &result);
171 	void SetValue(const svalue_t &newvalue);
172 	void Serialize(FArchive &ar);
173 };
174 
175 //==========================================================================
176 //
177 // hash the variables for speed: this is the hashkey
178 //
179 //==========================================================================
180 
variable_hash(const char * n)181 inline int variable_hash(const char *n)
182 {
183 	return
184               (n[0]? (   ( n[0] + n[1] +
185                    (n[1] ? n[2] +
186 				   (n[2] ? n[3]  : 0) : 0) ) % VARIABLESLOTS ) :0);
187 }
188 
189 
190 //==========================================================================
191 //
192 // Sections
193 //
194 //==========================================================================
195 
196 enum    // section types
197 {
198 	st_empty,       // empty {} braces
199 	st_if,
200 	st_elseif,
201 	st_else,
202 	st_loop,
203 };
204 
205 struct DFsSection : public DObject
206 {
207 	DECLARE_CLASS(DFsSection, DObject)
208 	HAS_OBJECT_POINTERS
209 public:
210 	int type;
211 	int start_index;
212 	int end_index;
213 	int loop_index;
214 	TObjPtr<DFsSection> next;        // for hashing
215 
DFsSectionDFsSection216 	DFsSection()
217 	{
218 		next = NULL;
219 	}
220 
221 	void Serialize(FArchive &ar);
222 };
223 
224 
225 
226 //==========================================================================
227 //
228 // Tokens
229 //
230 //==========================================================================
231 
232 enum tokentype_t
233 {
234 	name_,   // a name, eg 'count1' or 'frag'
235 	number,
236 	operator_,
237 	string_,
238 	unset,
239 	function          // function name
240 };
241 
242 enum    // brace types: where current_section is a { or }
243 {
244 	bracket_open,
245 	bracket_close
246 };
247 
248 //==========================================================================
249 //
250 // Errors
251 //
252 //==========================================================================
253 
254 class CFsError
255 {
256 public:
257 	// trying to throw strings crashes VC++ badly so we have to use a static buffer. :(
258 	char msg[2048];
259 
CFsError(const FString & in)260 	CFsError(const FString &in)
261 	{
262 		strncpy(msg, in, 2047);
263 		msg[2047]=0;
264 	}
265 };
266 
267 // throw this object to regularly terminate a script's execution.
268 class CFsTerminator
269 {
270 	int fill;
271 };
272 
273 //==========================================================================
274 //
275 // Scripts
276 //
277 //==========================================================================
278 
279 class DFsScript : public DObject
280 {
281 	DECLARE_CLASS(DFsScript, DObject)
282 	HAS_OBJECT_POINTERS
283 
284 public:
285 	// script data
286 
287 	char *data;
288 	int scriptnum;  // this script's number
289 	int len;
290 
291 	// {} sections
292 
293 	TObjPtr<DFsSection> sections[SECTIONSLOTS];
294 
295 	// variables:
296 
297 	TObjPtr<DFsVariable> variables[VARIABLESLOTS];
298 
299 	// ptr to the parent script
300 	// the parent script is the script above this level
301 	// eg. individual linetrigger scripts are children
302 	// of the levelscript, which is a child of the
303 	// global_script
304 	TObjPtr<DFsScript> parent;
305 
306 	// haleyjd: 8-17
307 	// child scripts.
308 	// levelscript holds ptrs to all of the level's scripts
309 	// here.
310 	TObjPtr<DFsScript> children[MAXSCRIPTS];
311 
312 
313 	TObjPtr<AActor> trigger;        // object which triggered this script
314 
315 	bool lastiftrue;     // haleyjd: whether last "if" statement was
316 	// true or false
317 
318 	DFsScript();
319 	void Destroy();
320 	void Serialize(FArchive &ar);
321 
322 	DFsVariable *NewVariable(const char *name, int vtype);
323 	void NewFunction(const char *name, void (FParser::*handler)());
324 
325 	DFsVariable *VariableForName(const char *name);
326 	DFsVariable *FindVariable(const char *name);
327 	void ClearVariables(bool complete= false);
328 	DFsVariable *NewLabel(char *labelptr);
329 	char *LabelValue(const svalue_t &v);
330 
331 	char *SectionStart(const DFsSection *sec);
332 	char *SectionEnd(const DFsSection *sec);
333 	char *SectionLoop(const DFsSection *sec);
334 	void ClearSections();
335 	void ClearChildren();
336 
MakeIndex(const char * p)337 	int MakeIndex(const char *p) { return int(p-data); }
338 
339 	// preprocessor
section_hash(const char * b)340 	int section_hash(const char *b) { return MakeIndex(b) % SECTIONSLOTS; }
341 	DFsSection *NewSection(const char *brace);
342 	DFsSection *FindSectionStart(const char *brace);
343 	DFsSection *FindSectionEnd(const char *brace);
344 	char *ProcessFindChar(char *data, char find);
345 	void DryRunScript();
346 	void Preprocess();
347 	void ParseInclude(char *lumpname);
348 	void ParseScript(char *rover = NULL);
349 	void ParseData(char *rover, char *data, char *end);
350 };
351 
352 //==========================================================================
353 //
354 // The script parser
355 //
356 //==========================================================================
357 
358 struct FParser
359 {
360 	struct operator_t
361 	{
362 		const char *string;
363 		void (FParser::*handler)(svalue_t &, int, int, int); // left, mid, right
364 		int direction;
365 	};
366 
367 	enum
368 	{
369 		forward,
370 		backward
371 	};
372 
373 	static operator_t operators[];
374 	static int num_operators;
375 
376 
377 	char *LineStart;
378 	char *Rover;
379 
380 	char *Tokens[T_MAXTOKENS];
381 	tokentype_t TokenType[T_MAXTOKENS];
382 	int NumTokens;
383 	DFsScript *Script;       // the current script
384 	DFsSection *Section;
385 	DFsSection *PrevSection;
386 	int BraceType;
387 
388 	int t_argc;                     // number of arguments
389 	svalue_t *t_argv;               // arguments
390 	svalue_t t_return;              // returned value
391 	FString t_func;					// name of current function
392 
FParserFParser393 	FParser(DFsScript *scr)
394 	{
395 		LineStart = NULL;
396 		Rover = NULL;
397 		Tokens[0] = new char[scr->len+32];	// 32 for safety. FS seems to need a few bytes more than the script's actual length.
398 		NumTokens = 0;
399 		Script = scr;
400 		Section = PrevSection = NULL;
401 		BraceType = 0;
402 	}
403 
~FParserFParser404 	~FParser()
405 	{
406 		if (Tokens[0]) delete [] Tokens[0];
407 	}
408 
409 	void NextToken();
410 	char *GetTokens(char *s);
411 	void PrintTokens();
412 	void ErrorMessage(FString msg);
413 
414 	void Run(char *rover, char *data, char *end);
415 	void RunStatement();
416 	int FindOperator(int start, int stop, const char *value);
417 	int FindOperatorBackwards(int start, int stop, const char *value);
418 	void SimpleEvaluate(svalue_t &, int n);
419 	void PointlessBrackets(int *start, int *stop);
420 	void EvaluateExpression(svalue_t &, int start, int stop);
421 	void EvaluateFunction(svalue_t &, int start, int stop);
422 
423 	void OPequals(svalue_t &, int, int, int);           // =
424 
425 	void OPplus(svalue_t &, int, int, int);             // +
426 	void OPminus(svalue_t &, int, int, int);            // -
427 	void OPmultiply(svalue_t &, int, int, int);         // *
428 	void OPdivide(svalue_t &, int, int, int);           // /
429 	void OPremainder(svalue_t &, int, int, int);        // %
430 
431 	void OPor(svalue_t &, int, int, int);               // ||
432 	void OPand(svalue_t &, int, int, int);              // &&
433 	void OPnot(svalue_t &, int, int, int);              // !
434 
435 	void OPor_bin(svalue_t &, int, int, int);           // |
436 	void OPand_bin(svalue_t &, int, int, int);          // &
437 	void OPnot_bin(svalue_t &, int, int, int);          // ~
438 
439 	void OPcmp(svalue_t &, int, int, int);              // ==
440 	void OPnotcmp(svalue_t &, int, int, int);           // !=
441 	void OPlessthan(svalue_t &, int, int, int);         // <
442 	void OPgreaterthan(svalue_t &, int, int, int);      // >
443 
444 	void OPincrement(svalue_t &, int, int, int);        // ++
445 	void OPdecrement(svalue_t &, int, int, int);        // --
446 
447 	void OPstructure(svalue_t &, int, int, int);    // in t_vari.c
448 
449 	void OPlessthanorequal(svalue_t &, int, int, int);     // <=
450 	void OPgreaterthanorequal(svalue_t &, int, int, int);  // >=
451 
452 	void spec_brace();
453 	bool spec_if();
454 	bool spec_elseif(bool lastif);
455 	void spec_else(bool lastif);
456 	void spec_for();
457 	void spec_while();
458 	void CreateVariable(int newvar_type, DFsScript *newvar_script, int start, int stop);
459 	void ParseVarLine(int newvar_type, DFsScript *newvar_script, int start);
460 	bool spec_variable();
461 	void spec_script();
462 
463 	DFsSection *looping_section();
464 	FString GetFormatString(int startarg);
465 	bool CheckArgs(int cnt);
466 
467 	void SF_Print();
468 	void SF_Rnd();
469 	void SF_Continue();
470 	void SF_Break();
471 	void SF_Goto();
472 	void SF_Return();
473 	void SF_Include();
474 	void SF_Input();
475 	void SF_Beep();
476 	void SF_Clock();
477 	void SF_ExitLevel();
478 	void SF_Tip();
479 	void SF_TimedTip();
480 	void SF_PlayerTip();
481 	void SF_Message();
482 	void SF_PlayerMsg();
483 	void SF_PlayerInGame();
484 	void SF_PlayerName();
485 	void SF_PlayerObj();
486 	void SF_StartScript();      // FPUKE needs to access this
487 	void SF_ScriptRunning();
488 	void SF_Wait();
489 	void SF_TagWait();
490 	void SF_ScriptWait();
491 	void SF_ScriptWaitPre();    // haleyjd: new wait types
492 	void SF_Player();
493 	void SF_Spawn();
494 	void SF_RemoveObj();
495 	void SF_KillObj();
496 	void SF_ObjX();
497 	void SF_ObjY();
498 	void SF_ObjZ();
499 	void SF_ObjAngle();
500 	void SF_Teleport();
501 	void SF_SilentTeleport();
502 	void SF_DamageObj();
503 	void SF_ObjSector();
504 	void SF_ObjHealth();
505 	void SF_ObjFlag();
506 	void SF_PushThing();
507 	void SF_ReactionTime();
508 	void SF_MobjTarget();
509 	void SF_MobjMomx();
510 	void SF_MobjMomy();
511 	void SF_MobjMomz();
512 	void SF_PointToAngle();
513 	void SF_PointToDist();
514 	void SF_SetCamera();
515 	void SF_ClearCamera();
516 	void SF_StartSound();
517 	void SF_StartSectorSound();
518 	void SF_FloorHeight();
519 	void SF_MoveFloor();
520 	void SF_CeilingHeight();
521 	void SF_MoveCeiling();
522 	void SF_LightLevel();
523 	void SF_FadeLight();
524 	void SF_FloorTexture();
525 	void SF_SectorColormap();
526 	void SF_CeilingTexture();
527 	void SF_ChangeHubLevel();
528 	void SF_StartSkill();
529 	void SF_OpenDoor();
530 	void SF_CloseDoor();
531 	void SF_RunCommand();
532 	void SF_LineTrigger();
533 	void SF_ChangeMusic();
534 	void SF_SetLineBlocking();
535 	void SF_SetLineMonsterBlocking();
536 	void SF_SetLineTexture();
537 	void SF_Max();
538 	void SF_Min();
539 	void SF_Abs();
540 	void SF_Gameskill();
541 	void SF_Gamemode();
542 	void SF_IsPlayerObj();
543 	void SF_PlayerKeys();
544 	void SF_PlayerAmmo();
545 	void SF_MaxPlayerAmmo();
546 	void SF_PlayerWeapon();
547 	void SF_PlayerSelectedWeapon();
548 	void SF_GiveInventory();
549 	void SF_TakeInventory();
550 	void SF_CheckInventory();
551 	void SF_SetWeapon();
552 	void SF_MoveCamera();
553 	void SF_ObjAwaken();
554 	void SF_AmbientSound();
555 	void SF_ExitSecret();
556 	void SF_MobjValue();
557 	void SF_StringValue();
558 	void SF_IntValue();
559 	void SF_FixedValue();
560 	void SF_SpawnExplosion();
561 	void SF_RadiusAttack();
562 	void SF_SetObjPosition();
563 	void SF_TestLocation();
564 	void SF_HealObj();  //no pain sound
565 	void SF_ObjDead();
566 	void SF_SpawnMissile();
567 	void SF_MapThingNumExist();
568 	void SF_MapThings();
569 	void SF_ObjState();
570 	void SF_LineFlag();
571 	void SF_PlayerAddFrag();
572 	void SF_SkinColor();
573 	void SF_PlayDemo();
574 	void SF_CheckCVar();
575 	void SF_Resurrect();
576 	void SF_LineAttack();
577 	void SF_ObjType();
578 	void SF_Sin();
579 	void SF_ASin();
580 	void SF_Cos();
581 	void SF_ACos();
582 	void SF_Tan();
583 	void SF_ATan();
584 	void SF_Exp();
585 	void SF_Log();
586 	void SF_Sqrt();
587 	void SF_Floor();
588 	void SF_Pow();
589 	void SF_NewHUPic();
590 	void SF_DeleteHUPic();
591 	void SF_ModifyHUPic();
592 	void SF_SetHUPicDisplay();
593 	void SF_SetCorona();
594 	void SF_Ls();
595 	void SF_LevelNum();
596 	void SF_MobjRadius();
597 	void SF_MobjHeight();
598 	void SF_ThingCount();
599 	void SF_SetColor();
600 	void SF_SpawnShot2();
601 	void SF_KillInSector();
602 	void SF_SectorType();
603 	void SF_SetLineTrigger();
604 	void SF_ChangeTag();
605 	void SF_WallGlow();
606 	void RunLineSpecial(const FLineSpecial *);
607 
608 	DRunningScript *SaveCurrentScript();
609 
610 };
611 
612 //==========================================================================
613 //
614 // Running scripts
615 //
616 //==========================================================================
617 
618 enum waittype_e
619 {
620     wt_none,        // not waiting
621 	wt_delay,       // wait for a set amount of time
622 	wt_tagwait,     // wait for sector to stop moving
623 	wt_scriptwait,  // wait for script to finish
624 	wt_scriptwaitpre, // haleyjd - wait for script to start
625 };
626 
627 class DRunningScript : public DObject
628 {
629 	DECLARE_CLASS(DRunningScript, DObject)
630 	HAS_OBJECT_POINTERS
631 
632 public:
633 	DRunningScript(AActor *trigger=NULL, DFsScript *owner = NULL, int index = 0) ;
634 	void Destroy();
635 	void Serialize(FArchive &arc);
636 
637 	TObjPtr<DFsScript> script;
638 
639 	// where we are
640 	int save_point;
641 
642 	int wait_type;
643 	int wait_data;  // data for wait: tagnum, counter, script number etc
644 
645 	// saved variables
646 	TObjPtr<DFsVariable> variables[VARIABLESLOTS];
647 
648 	TObjPtr<DRunningScript> prev, next;  // for chain
649 	TObjPtr<AActor> trigger;
650 };
651 
652 //-----------------------------------------------------------------------------
653 //
654 // This thinker eliminates the need to call the Fragglescript functions from the main code
655 //
656 //-----------------------------------------------------------------------------
657 class DFraggleThinker : public DThinker
658 {
659 	DECLARE_CLASS(DFraggleThinker, DThinker)
660 	HAS_OBJECT_POINTERS
661 public:
662 
663 	TObjPtr<DFsScript> LevelScript;
664 	TObjPtr<DRunningScript> RunningScripts;
665 	TArray<TObjPtr<AActor> > SpawnedThings;
666 	bool nocheckposition;
667 
668 	DFraggleThinker();
669 	void Destroy();
670 
671 
672 	void Serialize(FArchive & arc);
673 	void Tick();
674 	size_t PropagateMark();
675 	size_t PointerSubstitution (DObject *old, DObject *notOld);
676 	bool wait_finished(DRunningScript *script);
677 	void AddRunningScript(DRunningScript *runscr);
678 
679 	static TObjPtr<DFraggleThinker> ActiveThinker;
680 };
681 
682 //-----------------------------------------------------------------------------
683 //
684 // Global stuff
685 //
686 //-----------------------------------------------------------------------------
687 
688 #include "t_fs.h"
689 
690 void script_error(const char *s, ...);
691 void FS_EmulateCmd(char * string);
692 
693 extern AActor *trigger_obj;
694 extern DFsScript *global_script;
695 
696 
697 #endif
698 
699