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