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