1 //----------------------------------------------------------------------------
2 // EDGE Data Definition File Code (States)
3 //----------------------------------------------------------------------------
4 //
5 // Copyright (c) 1999-2008 The EDGE Team.
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (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 //----------------------------------------------------------------------------
18
19 #include "local.h"
20
21 #include "states.h"
22
23 #include "src/p_action.h"
24 #include "src/z_zone.h"
25
26
27 // FIXME: unwanted link to engine code (switch to epi::angle_c)
28 extern float M_Tan(angle_t ang) GCCATTR((const));
29
30
31 static const state_t template_state =
32 {
33 0, // sprite ref
34 0, // frame ref
35 0, // bright
36 0, // flags
37 -1, // tics
38
39 NULL, // model_frame
40 NULL, // label
41 NULL, // routine
42 NULL, // parameter
43
44 0, // next state ref
45 -1 // jump state ref
46 };
47
48 // -KM- 1998/11/25 All weapon related states are out
49 state_t *states = NULL;
50 int num_states;
51
52 std::vector<std::string> ddf_sprite_names;
53 std::vector<std::string> ddf_model_names;
54
55
56 // Until the DDF_StateFinishState() routine is called, the `nextstate'
57 // field of each state contains a special value. 0 for normal (no
58 // redirector). -1 for the #REMOVE redirector. Otherwise the top 16
59 // bits is a redirector, and the bottom 16 bits is a positive offset
60 // from that redirector (usually 0).
61 //
62 // Every time a new redirector is used, it is added to this list. The
63 // top 16 bits (minus 1) will be an index into this list of redirector
64 // names. These labels will be looked for in the states when the
65 // fixup routine is called.
66 epi::strlist_c redirs;
67
68 #define NUM_SPLIT 10 // Max Number of sections a state is split info
69
70 static std::string stateinfo[NUM_SPLIT + 1];
71
72
73 // a little caching makes a big difference here
74 // (because DDF entries are usually limited to a single sprite)
75 static int last_sprite = -1;
76 static int last_model = -1;
77
78
AddSpriteName(const char * name)79 static int AddSpriteName(const char *name)
80 {
81 if (stricmp(name, "NULL") == 0)
82 return SPR_NULL;
83
84 if (last_sprite >= 0 &&
85 stricmp(ddf_sprite_names[last_sprite].c_str(), name) == 0)
86 return last_sprite;
87
88 // look backwards, assuming a recent sprite is more likely
89 for (int i = (int)ddf_sprite_names.size() - 1; i > SPR_NULL; i--)
90 if (stricmp(ddf_sprite_names[i].c_str(), name) == 0)
91 return ((last_sprite = i));
92
93 last_sprite = (int)ddf_sprite_names.size();
94
95 // not found, so insert it
96 ddf_sprite_names.push_back(std::string(name));
97
98 return last_sprite;
99 }
100
AddModelName(const char * name)101 static int AddModelName(const char *name)
102 {
103 if (stricmp(name, "NULL") == 0)
104 return SPR_NULL;
105
106 if (last_model >= 0 &&
107 stricmp(ddf_model_names[last_model].c_str(), name) == 0)
108 return last_model;
109
110 // look backwards, assuming a recent model is more likely
111 for (int i = (int)ddf_model_names.size() - 1; i > SPR_NULL; i--)
112 if (stricmp(ddf_model_names[i].c_str(), name) == 0)
113 return ((last_model = i));
114
115 last_model = (int)ddf_model_names.size();
116
117 // not found, so insert it
118 ddf_model_names.push_back(std::string(name));
119
120 return last_model;
121 }
122
123
DDF_StateInit(void)124 void DDF_StateInit(void)
125 {
126 // setup the 'S_NULL' state
127 states = Z_New(state_t, 1);
128 states[0] = template_state;
129 num_states = 1;
130
131 // setup the 'SPR_NULL' sprite
132 // (Not strictly needed, but means we can access the arrays
133 // without subtracting 1)
134 #if 1
135 AddSpriteName("!NULL!");
136 AddModelName ("!NULL!");
137 #endif
138 }
139
DDF_StateCleanUp(void)140 void DDF_StateCleanUp(void)
141 {
142 /* nothing to do */
143 }
144
145
146 //
147 // DDF_MainSplitIntoState
148 //
149 // Small procedure that takes the info and splits it into relevant stuff
150 //
151 // -KM- 1998/12/21 Rewrote procedure, much cleaner now.
152 //
153 // -AJA- 2000/09/03: Rewrote _again_ damn it, in order to handle `:'
154 // appearing inside brackets.
155 //
DDF_MainSplitIntoState(const char * info)156 static int DDF_MainSplitIntoState(const char *info)
157 {
158 char *temp;
159 char *first;
160
161 int cur;
162 int brackets=0;
163 bool done=false;
164
165 // use a buffer, since we modify the string
166 char infobuf[512];
167
168 strcpy(infobuf, info);
169
170 for (cur=0; cur < NUM_SPLIT+1; cur++)
171 stateinfo[cur] = std::string();
172
173 first = temp = infobuf;
174
175 for (cur=0; !done && cur < NUM_SPLIT; temp++)
176 {
177 if (*temp == '(')
178 {
179 brackets++;
180 continue;
181 }
182
183 if (*temp == ')')
184 {
185 if (brackets == 0)
186 DDF_Error("Mismatched ) bracket in states: %s\n", info);
187
188 brackets--;
189 continue;
190 }
191
192 if (*temp && *temp != ':')
193 continue;
194
195 if (brackets > 0)
196 continue;
197
198 if (*temp == 0)
199 done = true;
200
201 *temp = 0;
202
203 if (first[0] == '#')
204 {
205 // signify that we have found redirector
206 stateinfo[0] = std::string(first + 1);
207 stateinfo[1] = std::string();
208 stateinfo[2] = std::string();
209
210 if (! done)
211 stateinfo[1] = std::string(temp + 1);
212
213 return -1;
214 }
215
216 stateinfo[cur++] = std::string(first);
217
218 first = temp + 1;
219 }
220
221 if (brackets > 0)
222 DDF_Error("Unclosed ( bracket in states: %s\n", info);
223
224 return cur;
225 }
226
227
228 //
229 // DDF_MainSplitActionArg
230 //
231 // Small procedure that takes an action like "FOO(BAR)", and splits it
232 // into two strings "FOO" and "BAR".
233 //
234 // -AJA- 1999/08/10: written.
235 //
DDF_MainSplitActionArg(const char * info,char * actname,char * actarg)236 static void DDF_MainSplitActionArg(const char *info, char *actname, char *actarg)
237 {
238 int len = strlen(info);
239
240 const char *mid = strchr(info, '(');
241
242 if (mid && len >= 4 && info[len - 1] == ')')
243 {
244 int len2 = (mid - info);
245
246 Z_StrNCpy(actname, info, len2);
247
248 len -= len2 + 2;
249 Z_StrNCpy(actarg, mid + 1, len);
250 }
251 else
252 {
253 strcpy(actname, info);
254 actarg[0] = 0;
255 }
256 }
257
258 //
259 // StateGetRedirector
260 //
StateGetRedirector(const char * redir)261 static int StateGetRedirector(const char *redir)
262 {
263 epi::array_iterator_c it;
264 const char *s;
265
266 for (it=redirs.GetBaseIterator(); it.IsValid(); it++)
267 {
268 s = ITERATOR_TO_TYPE(it, const char*);
269 if (DDF_CompareName(s, redir) == 0)
270 return it.GetPos();
271 }
272
273 redirs.Insert(redir);
274 return redirs.GetSize()-1;
275 }
276
277 //
278 // DDF_StateFindLabel
279 //
DDF_StateFindLabel(const state_group_t & group,const char * label,bool quiet)280 statenum_t DDF_StateFindLabel(const state_group_t& group,
281 const char *label, bool quiet)
282 {
283 for (int g = (int)group.size()-1; g >= 0; g--)
284 {
285 for (statenum_t i = group[g].last; i >= group[g].first; i--)
286 {
287 if (! states[i].label)
288 continue;
289
290 if (DDF_CompareName(states[i].label, label) == 0)
291 return i;
292 }
293 }
294
295 // compatibility hack:
296 if (DDF_CompareName(label, "IDLE") == 0)
297 {
298 return DDF_StateFindLabel(group, "SPAWN");
299 }
300
301 if (! quiet)
302 DDF_Error("Unknown label '%s' (object has no such frames).\n", label);
303
304 return S_NULL;
305 }
306
307 //
308 // DDF_StateReadState
309 //
DDF_StateReadState(const char * info,const char * label,state_group_t & group,int * state_num,int index,const char * redir,const actioncode_t * action_list,bool is_weapon)310 void DDF_StateReadState(const char *info, const char *label,
311 state_group_t& group, int *state_num, int index,
312 const char *redir, const actioncode_t *action_list,
313 bool is_weapon)
314 {
315 SYS_ASSERT(group.size() > 0);
316
317 state_range_t& range = group.back();
318
319 int i, j;
320
321 char action_name[128];
322 char action_arg[128];
323
324 state_t *cur;
325
326 // Split the state info into component parts
327 // -ACB- 1998/07/26 New Procedure, for cleaner code.
328
329 i = DDF_MainSplitIntoState(info);
330 if (i < 5 && i >= 0)
331 {
332 if (strchr(info, '['))
333 {
334 // -ES- 2000/02/02 Probably unterminated state.
335 DDF_Error("DDF_MainLoadStates: Bad state '%s', possibly missing ';'\n", info);
336 }
337 DDF_Error("Bad state '%s'\n", info);
338 }
339
340 if (stateinfo[0].empty())
341 DDF_Error("Missing sprite in state frames: `%s'\n", info);
342
343 //--------------------------------------------------
344 //----------------REDIRECTOR HANDLING---------------
345 //--------------------------------------------------
346
347 if (stateinfo[2].empty())
348 {
349 if (! range.first)
350 DDF_Error("Redirector used without any states (`%s')\n", info);
351
352 cur = &states[range.last];
353
354 SYS_ASSERT(! stateinfo[0].empty());
355
356 if (DDF_CompareName(stateinfo[0].c_str(), "REMOVE") == 0)
357 {
358 cur->nextstate = -1;
359 return;
360 }
361
362 cur->nextstate = (StateGetRedirector(stateinfo[0].c_str()) + 1) << 16;
363
364 if (! stateinfo[1].empty())
365 cur->nextstate += MAX(0, atoi(stateinfo[1].c_str()) - 1);
366
367 return;
368 }
369
370 //--------------------------------------------------
371 //---------------- ALLOCATE NEW STATE --------------
372 //--------------------------------------------------
373
374 Z_Resize(states, state_t, ++num_states);
375
376 cur = &states[num_states-1];
377
378 // initialise with defaults
379 cur[0] = template_state;
380
381 if (range.first == 0)
382 {
383 // very first state for thing/weapon
384 range.first = num_states-1;
385 }
386
387 range.last = num_states-1;
388
389 if (index == 0)
390 {
391 // first state in this set of states
392 if (state_num)
393 state_num[0] = num_states-1;
394
395 // ...therefore copy the label
396 cur->label = strdup(label);
397 }
398
399 if (redir && cur->nextstate == 0)
400 {
401 if (DDF_CompareName("REMOVE", redir) == 0)
402 cur->nextstate = -1;
403 else
404 cur->nextstate = (StateGetRedirector(redir) + 1) << 16;
405 }
406
407 //--------------------------------------------------
408 //----------------SPRITE NAME HANDLING--------------
409 //--------------------------------------------------
410
411 if (stateinfo[1].empty() || stateinfo[2].empty() || stateinfo[3].empty())
412 DDF_Error("Bad state frame, missing fields: %s\n", info);
413
414 if (strlen(stateinfo[0].c_str()) != 4)
415 DDF_Error("DDF_MainLoadStates: Sprite names must be 4 "
416 "characters long '%s'.\n", stateinfo[0].c_str());
417
418 //--------------------------------------------------
419 //--------------SPRITE INDEX HANDLING---------------
420 //--------------------------------------------------
421
422 cur->flags = 0;
423
424 // look at the first character
425 const char *sprite_x = stateinfo[1].c_str();
426
427 j = sprite_x[0];
428
429 if ('A' <= j && j <= ']')
430 {
431 cur->frame = j - (int)'A';
432 }
433 else if (j == '@')
434 {
435 cur->frame = -1;
436
437 char first_ch = sprite_x[1];
438
439 if (isdigit(first_ch))
440 {
441 cur->flags = SFF_Model;
442 cur->frame = atol(sprite_x+1) - 1;
443 }
444 else if (isalpha(first_ch) || (first_ch == '_'))
445 {
446 cur->flags = SFF_Model | SFF_Unmapped;
447 cur->frame = 0;
448 cur->model_frame = strdup(sprite_x+1);
449 }
450
451 if (cur->frame < 0)
452 DDF_Error("DDF_MainLoadStates: Illegal model frame: %s\n", sprite_x);
453 }
454 else
455 DDF_Error("DDF_MainLoadStates: Illegal sprite frame: %s\n", sprite_x);
456
457 if (is_weapon)
458 cur->flags |= SFF_Weapon;
459
460 if (cur->flags & SFF_Model)
461 cur->sprite = AddModelName(stateinfo[0].c_str());
462 else
463 cur->sprite = AddSpriteName(stateinfo[0].c_str());
464
465 //--------------------------------------------------
466 //------------STATE TIC COUNT HANDLING--------------
467 //--------------------------------------------------
468
469 cur->tics = atol(stateinfo[2].c_str());
470
471 //--------------------------------------------------
472 //------------STATE BRIGHTNESS LEVEL----------------
473 //--------------------------------------------------
474
475 if (strcmp(stateinfo[3].c_str(), "NORMAL") == 0)
476 cur->bright = 0;
477 else if (strcmp(stateinfo[3].c_str(), "BRIGHT") == 0)
478 cur->bright = 255;
479 else if (strncmp(stateinfo[3].c_str(), "LIT", 3) == 0)
480 {
481 cur->bright = strtol(stateinfo[3].c_str()+3, NULL, 10);
482 cur->bright = CLAMP(0, cur->bright * 255 / 99, 255);
483 }
484 else
485 DDF_WarnError("DDF_MainLoadStates: Lighting is not BRIGHT or NORMAL\n");
486
487 //--------------------------------------------------
488 //------------STATE ACTION CODE HANDLING------------
489 //--------------------------------------------------
490
491 if (! stateinfo[4].empty())
492 {
493 // Get Action Code Ref (Using remainder of the string).
494 // Go through all the actions, end if terminator or action found
495 //
496 // -AJA- 1999/08/10: Updated to handle a special argument.
497
498 DDF_MainSplitActionArg(stateinfo[4].c_str(), action_name, action_arg);
499
500 for (i=0; action_list[i].actionname; i++)
501 {
502 const char *current = action_list[i].actionname;
503
504 if (current[0] == '!')
505 current++;
506
507 if (DDF_CompareName(current, action_name) == 0)
508 break;
509 }
510
511 if (!action_list[i].actionname)
512 {
513 DDF_WarnError("Unknown code pointer: %s\n", stateinfo[4].c_str());
514 }
515 else
516 {
517 cur->action = action_list[i].action;
518 cur->action_par = NULL;
519
520 if (action_list[i].handle_arg)
521 (* action_list[i].handle_arg)(action_arg, cur);
522 }
523 }
524 }
525
526
DDF_MainParseState(byte * object,state_group_t & group,const char * field,const char * contents,int index,bool is_last,bool is_weapon,const state_starter_t * starters,const actioncode_t * actions)527 bool DDF_MainParseState(byte *object, state_group_t& group,
528 const char *field, const char *contents,
529 int index, bool is_last, bool is_weapon,
530 const state_starter_t *starters,
531 const actioncode_t *actions)
532 {
533 if (strnicmp(field, "STATES(", 7) != 0)
534 return false;
535
536 // extract label name
537 field += 7;
538
539 const char *pos = strchr(field, ')');
540
541 if (pos == NULL || pos == field || (pos - field) > 64)
542 return false;
543
544 std::string labname(field, pos - field);
545
546 // check for the "standard" states
547 int i;
548 for (i=0; starters[i].label; i++)
549 if (DDF_CompareName(starters[i].label, labname.c_str()) == 0)
550 break;
551
552 const state_starter_t *starter = NULL;
553 if (starters[i].label)
554 starter = &starters[i];
555
556 int * var = NULL;
557 if (starter)
558 var = (int *)(object + starter->offset);
559
560 const char *redir = NULL;
561 if (is_last)
562 redir = starter ? starter->last_redir : (is_weapon ? "READY" : "IDLE");
563
564 DDF_StateReadState(contents, labname.c_str(), group, var, index,
565 redir, actions, is_weapon);
566 return true;
567 }
568
569
DDF_StateBeginRange(state_group_t & group)570 void DDF_StateBeginRange(state_group_t& group)
571 {
572 state_range_t range;
573
574 range.first = S_NULL;
575 range.last = S_NULL;
576
577 group.push_back(range);
578 }
579
580
581 //
582 // DDF_StateFinishRange
583 //
584 // Check through the states on an mobj and attempts to dereference any
585 // encoded state redirectors.
586 //
DDF_StateFinishRange(state_group_t & group)587 void DDF_StateFinishRange(state_group_t& group)
588 {
589 SYS_ASSERT(! group.empty());
590
591 state_range_t& range = group.back();
592
593 // if no states were added, remove the unused range
594 if (range.first == S_NULL)
595 {
596 group.pop_back();
597
598 redirs.Clear();
599 return;
600 }
601
602 for (int i = range.first; i <= range.last; i++)
603 {
604 // handle next state ref
605 if (states[i].nextstate == -1)
606 {
607 states[i].nextstate = S_NULL;
608 }
609 else if ((states[i].nextstate >> 16) == 0)
610 {
611 states[i].nextstate = (i == range.last) ? S_NULL : i+1;
612 }
613 else
614 {
615 states[i].nextstate = DDF_StateFindLabel(group,
616 redirs[(states[i].nextstate >> 16) - 1]) +
617 (states[i].nextstate & 0xFFFF);
618 }
619
620 // handle jump state ref
621 if (states[i].jumpstate == -1)
622 {
623 states[i].jumpstate = S_NULL;
624 }
625 else if ((states[i].jumpstate >> 16) == 0)
626 {
627 states[i].jumpstate = (i == range.last) ? S_NULL : i+1;
628 }
629 else
630 {
631 states[i].jumpstate = DDF_StateFindLabel(group,
632 redirs[(states[i].jumpstate >> 16) - 1]) +
633 (states[i].jumpstate & 0xFFFF);
634 }
635 }
636
637 redirs.Clear();
638 }
639
640
DDF_StateGroupHasState(const state_group_t & group,statenum_t st)641 bool DDF_StateGroupHasState(const state_group_t& group, statenum_t st)
642 {
643 for (int g = 0; g < (int)group.size(); g++)
644 {
645 const state_range_t& range = group[g];
646
647 if (range.first <= st && st <= range.last)
648 return true;
649 }
650
651 return false;
652 }
653
654
655 //----------------------------------------------------------------------------
656
657 //
658 // DDF_StateGetAttack
659 //
660 // Parse the special argument for the state as an attack.
661 //
662 // -AJA- 1999/08/10: written.
663 //
DDF_StateGetAttack(const char * arg,state_t * cur_state)664 void DDF_StateGetAttack(const char *arg, state_t * cur_state)
665 {
666 if (!arg || !arg[0])
667 return;
668
669 cur_state->action_par = (void *)atkdefs.Lookup(arg);
670 if (cur_state->action_par == NULL)
671 DDF_WarnError("Unknown Attack (States): %s\n", arg);
672 }
673
674
DDF_StateGetMobj(const char * arg,state_t * cur_state)675 void DDF_StateGetMobj(const char *arg, state_t * cur_state)
676 {
677 if (!arg || !arg[0])
678 return;
679
680 cur_state->action_par = new mobj_strref_c(arg);
681 }
682
683
DDF_StateGetSound(const char * arg,state_t * cur_state)684 void DDF_StateGetSound(const char *arg, state_t * cur_state)
685 {
686 if (!arg || !arg[0])
687 return;
688
689 cur_state->action_par = (void *)sfxdefs.GetEffect(arg);
690 }
691
692
DDF_StateGetInteger(const char * arg,state_t * cur_state)693 void DDF_StateGetInteger(const char *arg, state_t * cur_state)
694 {
695 if (!arg || !arg[0])
696 return;
697
698 int *val_ptr = new int;
699
700 if (sscanf(arg, " %i ", val_ptr) != 1)
701 DDF_Error("DDF_StateGetInteger: bad value: %s\n", arg);
702
703 cur_state->action_par = val_ptr;
704 }
705
706
DDF_StateGetIntPair(const char * arg,state_t * cur_state)707 void DDF_StateGetIntPair(const char *arg, state_t * cur_state)
708 {
709 // Parses two integers separated by commas.
710 //
711 int *values;
712
713 if (!arg || !arg[0])
714 return;
715
716 values = new int[2];
717
718 if (sscanf(arg, " %i , %i ", &values[0], &values[1]) != 2)
719 DDF_Error("DDF_StateGetIntPair: bad values: %s\n", arg);
720
721 cur_state->action_par = values;
722 }
723
724
DDF_StateGetFloat(const char * arg,state_t * cur_state)725 void DDF_StateGetFloat(const char *arg, state_t * cur_state)
726 {
727 if (!arg || !arg[0])
728 return;
729
730 float *val_ptr = new float;
731
732 if (sscanf(arg, " %f ", val_ptr) != 1)
733 DDF_Error("DDF_StateGetFloat: bad value: %s\n", arg);
734
735 cur_state->action_par = val_ptr;
736 }
737
738
DDF_StateGetPercent(const char * arg,state_t * cur_state)739 void DDF_StateGetPercent(const char *arg, state_t * cur_state)
740 {
741 if (!arg || !arg[0])
742 return;
743
744 percent_t *val_ptr = new percent_t;
745
746 if (sscanf(arg, " %f%% ", val_ptr) != 1 || (*val_ptr) < 0)
747 DDF_Error("DDF_StateGetPercent: Bad percentage: %s\n", arg);
748
749 (* val_ptr) /= 100.0f;
750
751 cur_state->action_par = val_ptr;
752 }
753
754
act_jump_info_s()755 act_jump_info_s::act_jump_info_s() :
756 chance(PERCENT_MAKE(100)) // -ACB- 2001/02/04 tis a precent_t
757 { }
758
~act_jump_info_s()759 act_jump_info_s::~act_jump_info_s()
760 { }
761
DDF_StateGetJump(const char * arg,state_t * cur_state)762 void DDF_StateGetJump(const char *arg, state_t * cur_state)
763 {
764 // JUMP(label)
765 // JUMP(label,chance)
766
767 if (!arg || !arg[0])
768 return;
769
770 act_jump_info_t *jump = new act_jump_info_t;
771
772 int len;
773 int offset = 0;
774
775 const char *s = strchr(arg, ',');
776
777 if (! s)
778 {
779 len = strlen(arg);
780 }
781 else
782 {
783 // convert chance value
784 DDF_MainGetPercent(s+1, &jump->chance);
785
786 len = s - arg;
787 }
788
789 if (len == 0)
790 DDF_Error("DDF_StateGetJump: missing label!\n");
791
792 if (len > 75)
793 DDF_Error("DDF_StateGetJump: label name too long!\n");
794
795 // copy label name
796 char buffer[80];
797
798 for (len=0; *arg && (*arg != ':') && (*arg != ','); len++, arg++)
799 buffer[len] = *arg;
800
801 buffer[len] = 0;
802
803 if (*arg == ':')
804 offset = MAX(0, atoi(arg+1) - 1);
805
806 // set the jump state
807 cur_state->jumpstate = ((StateGetRedirector(buffer) + 1) << 16) + offset;
808 cur_state->action_par = jump;
809 }
810
811
DDF_StateGetFrame(const char * arg,state_t * cur_state)812 void DDF_StateGetFrame(const char *arg, state_t * cur_state)
813 {
814 // Sets the jump_state, like DDF_StateGetJump above.
815 //
816 // ACTION(label)
817
818 if (!arg || !arg[0])
819 return;
820
821 int len;
822 int offset = 0;
823
824 // copy label name
825 char buffer[80];
826
827 for (len = 0; *arg && (*arg != ':'); len++, arg++)
828 buffer[len] = *arg;
829
830 buffer[len] = 0;
831
832 if (*arg == ':')
833 offset = MAX(0, atoi(arg+1) - 1);
834
835 // set the jump state
836 cur_state->jumpstate = ((StateGetRedirector(buffer) + 1) << 16) + offset;
837 }
838
839
act_become_info_s()840 act_become_info_s::act_become_info_s() :
841 info(NULL), info_ref(), start()
842 { }
843
~act_become_info_s()844 act_become_info_s::~act_become_info_s()
845 { }
846
DDF_StateGetBecome(const char * arg,state_t * cur_state)847 void DDF_StateGetBecome(const char *arg, state_t * cur_state)
848 {
849 // BECOME(typename)
850 // BECOME(typename,label)
851
852 if (!arg || !arg[0])
853 return;
854
855 act_become_info_t *become = new act_become_info_t;
856
857 become->start.label.Set("IDLE");
858
859 const char *s = strchr(arg, ',');
860
861 // get type name
862 char buffer[80];
863
864 int len = s ? (s - arg) : strlen(arg);
865
866 if (len == 0)
867 DDF_Error("DDF_StateGetBecome: missing type name!\n");
868
869 if (len > 75)
870 DDF_Error("DDF_StateGetBecome: type name too long!\n");
871
872 for (len=0; *arg && (*arg != ':') && (*arg != ','); len++, arg++)
873 buffer[len] = *arg;
874
875 buffer[len] = 0;
876
877 become->info_ref.Set(buffer);
878
879
880 // get start label (if present)
881 if (s)
882 {
883 s++;
884
885 len = strlen(s);
886
887 if (len == 0)
888 DDF_Error("DDF_StateGetBecome: missing label!\n");
889
890 if (len > 75)
891 DDF_Error("DDF_StateGetBecome: label too long!\n");
892
893 for (len=0; *s && (*s != ':') && (*s != ','); len++, s++)
894 buffer[len] = *s;
895
896 buffer[len] = 0;
897
898 become->start.label.Set(buffer);
899
900 if (*s == ':')
901 become->start.offset = MAX(0, atoi(s+1) - 1);
902
903 }
904
905 cur_state->action_par = become;
906 }
907
908
DDF_StateGetAngle(const char * arg,state_t * cur_state)909 void DDF_StateGetAngle(const char *arg, state_t * cur_state)
910 {
911 angle_t *value;
912 float tmp;
913
914 if (!arg || !arg[0])
915 return;
916
917 value = new angle_t;
918
919 if (sscanf(arg, " %f ", &tmp) != 1)
920 DDF_Error("DDF_StateGetAngle: bad value: %s\n", arg);
921
922 *value = FLOAT_2_ANG(tmp);
923
924 cur_state->action_par = value;
925 }
926
927
DDF_StateGetSlope(const char * arg,state_t * cur_state)928 void DDF_StateGetSlope(const char *arg, state_t * cur_state)
929 {
930 float *value, tmp;
931
932 if (!arg || !arg[0])
933 return;
934
935 value = new float;
936
937 if (sscanf(arg, " %f ", &tmp) != 1)
938 DDF_Error("DDF_StateGetSlope: bad value: %s\n", arg);
939
940 if (tmp > +89.5f)
941 tmp = +89.5f;
942 if (tmp < -89.5f)
943 tmp = -89.5f;
944
945 *value = M_Tan(FLOAT_2_ANG(tmp));
946
947 cur_state->action_par = value;
948 }
949
950
DDF_StateGetRGB(const char * arg,state_t * cur_state)951 void DDF_StateGetRGB(const char *arg, state_t * cur_state)
952 {
953 if (!arg || !arg[0])
954 return;
955
956 cur_state->action_par = new rgbcol_t;
957
958 DDF_MainGetRGB(arg, cur_state->action_par);
959 }
960
961
962 //--- editor settings ---
963 // vi:ts=4:sw=4:noexpandtab
964