1 //********************************************************************************************
2 //*
3 //* This file is part of Egoboo.
4 //*
5 //* Egoboo is free software: you can redistribute it and/or modify it
6 //* under the terms of the GNU General Public License as published by
7 //* the Free Software Foundation, either version 3 of the License, or
8 //* (at your option) any later version.
9 //*
10 //* Egoboo is distributed in the hope that it will be useful, but
11 //* WITHOUT ANY WARRANTY; without even the implied warranty of
12 //* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 //* General Public License for more details.
14 //*
15 //* You should have received a copy of the GNU General Public License
16 //* along with Egoboo. If not, see <http://www.gnu.org/licenses/>.
17 //*
18 //********************************************************************************************
19
20 /// @file mad.c
21 /// @brief The files for handling Egoboo's internal model definitions
22 /// @details
23
24 #include "mad.h"
25
26 #include "md2.inl"
27
28 #include "cap_file.h"
29 #include "particle.inl"
30
31 #include "log.h"
32 #include "script_compile.h"
33 #include "graphic.h"
34 #include "texture.h"
35 #include "sound.h"
36
37 #include "egoboo_setup.h"
38 #include "egoboo_fileutil.h"
39 #include "egoboo_strutil.h"
40
41 //--------------------------------------------------------------------------------------------
42 //--------------------------------------------------------------------------------------------
43
44 INSTANTIATE_STACK( ACCESS_TYPE_NONE, mad_t, MadStack, MAX_MAD );
45
46 static STRING szModelName = EMPTY_CSTR; ///< MD2 Model name
47 static char cActionName[ACTION_COUNT][2]; ///< Two letter name code
48 static STRING cActionComent[ACTION_COUNT]; ///< Strings explaining the action codes
49
50 static int action_number( const char * cFrameName );
51 static mad_t * action_check_copy_vfs( mad_t * pmad, const char* loadname );
52 static mad_t * action_copy_correct( mad_t * pmad, int actiona, int actionb );
53
54 static mad_t * mad_get_framefx( mad_t * pmad, const char * cFrameName, int frame );
55 static mad_t * mad_get_walk_frame( mad_t * pmad, int lip, int action );
56 static mad_t * mad_make_framelip( mad_t * pmad, int action );
57 static mad_t * mad_rip_actions( mad_t * pmad );
58
59 static mad_t * mad_finalize( mad_t * pmad );
60 static mad_t * mad_heal_actions( mad_t * pmad, const char * loadname );
61 static mad_t * mad_make_equally_lit( mad_t * pmad );
62
63 //--------------------------------------------------------------------------------------------
64 //--------------------------------------------------------------------------------------------
65 //static void md2_fix_normals( const MAD_REF imad );
66 //static void md2_get_transvertices( const MAD_REF imad );
67 // static int vertexconnected( md2_ogl_commandlist_t * pclist, int vertex );
68
69 static mad_t * mad_ctor( mad_t * pmad );
70 static mad_t * mad_dtor( mad_t * pmad );
71 static mad_t * mad_reconstruct( mad_t * pmad );
72 static bool_t mad_free( mad_t * pmad );
73
74 //--------------------------------------------------------------------------------------------
75 //--------------------------------------------------------------------------------------------
MadList_init()76 void MadList_init()
77 {
78 MAD_REF cnt;
79
80 // initialize all mad_t
81 for ( cnt = 0; cnt < MAX_MAD; cnt++ )
82 {
83 mad_t * pmad = MadStack.lst + cnt;
84
85 // blank out all the data, including the obj_base data
86 memset( pmad, 0, sizeof( *pmad ) );
87
88 mad_reconstruct( pmad );
89 }
90 }
91
92 //--------------------------------------------------------------------------------------------
MadList_dtor()93 void MadList_dtor()
94 {
95 MAD_REF cnt;
96
97 for ( cnt = 0; cnt < MAX_MAD; cnt++ )
98 {
99 mad_dtor( MadStack.lst + cnt );
100 }
101 }
102
103 //--------------------------------------------------------------------------------------------
104 //--------------------------------------------------------------------------------------------
action_number(const char * cFrameName)105 int action_number( const char * cFrameName )
106 {
107 /// @details ZZ@> This function returns the number of the action in cFrameName, or
108 /// it returns NOACTION if it could not find a match
109
110 int cnt;
111 char tmp_str[16];
112 char first, second;
113
114 sscanf( cFrameName, " %15s", tmp_str );
115
116 first = tmp_str[0];
117 second = tmp_str[1];
118
119 for ( cnt = 0; cnt < ACTION_COUNT; cnt++ )
120 {
121 if ( first == cActionName[cnt][0] && second == cActionName[cnt][1] )
122 {
123 return cnt;
124 }
125 }
126
127 return NOACTION;
128 }
129
130 //--------------------------------------------------------------------------------------------
action_copy_correct(mad_t * pmad,int actiona,int actionb)131 mad_t * action_copy_correct( mad_t * pmad, int actiona, int actionb )
132 {
133 /// @details ZZ@> This function makes sure both actions are valid if either of them
134 /// are valid. It will copy start and ends to mirror the valid action.
135
136 if ( NULL == pmad ) return pmad;
137
138 if ( actiona < 0 || actiona >= ACTION_COUNT ) return pmad;
139 if ( actionb < 0 || actionb >= ACTION_COUNT ) return pmad;
140
141 // With the new system using the action_map, this is all that is really necessary
142 if ( ACTION_COUNT == pmad->action_map[actiona] )
143 {
144 if ( pmad->action_valid[actionb] )
145 {
146 pmad->action_map[actiona] = actionb;
147 }
148 else if ( ACTION_COUNT != pmad->action_map[actionb] )
149 {
150 pmad->action_map[actiona] = pmad->action_map[actionb];
151 }
152 }
153 else if ( ACTION_COUNT == pmad->action_map[actionb] )
154 {
155 if ( pmad->action_valid[actiona] )
156 {
157 pmad->action_map[actionb] = actiona;
158 }
159 else if ( ACTION_COUNT != pmad->action_map[actiona] )
160 {
161 pmad->action_map[actionb] = pmad->action_map[actiona];
162 }
163 }
164
165 return pmad;
166 }
167
168 //--------------------------------------------------------------------------------------------
mad_get_action(mad_t * pmad,int action)169 int mad_get_action( mad_t * pmad, int action )
170 {
171 /// @detaills BB@> translate the action that was given into a valid action for the model
172 ///
173 /// returns ACTION_COUNT on a complete failure, or the default ACTION_DA if it exists
174
175 int retval;
176
177 if ( NULL == pmad ) return ACTION_COUNT;
178
179 // you are pretty much guaranteed that ACTION_DA will be valid for a model,
180 // I guess it could be invalid if the model had no frames or something
181 retval = ACTION_DA;
182 if ( !pmad->action_valid[ACTION_DA] )
183 {
184 retval = ACTION_COUNT;
185 }
186
187 // check for a valid action range
188 if ( action < 0 || action > ACTION_COUNT ) return retval;
189
190 // track down a valid value
191 if ( pmad->action_valid[action] )
192 {
193 retval = action;
194 }
195 else if ( ACTION_COUNT != pmad->action_map[action] )
196 {
197 int cnt, tnc;
198
199 // do a "recursive" search for a valid action
200 // we should never really have to check more than once if the map is prepared
201 // properly BUT you never can tell. Make sure we do not get a runaway loop by
202 // you never go farther than ACTION_COUNT steps and that you never see the
203 // original action again
204
205 tnc = pmad->action_map[action];
206 for ( cnt = 0; cnt < ACTION_COUNT; cnt++ )
207 {
208 if ( tnc >= ACTION_COUNT || tnc < 0 || tnc == action ) break;
209
210 if ( pmad->action_valid[tnc] )
211 {
212 retval = tnc;
213 break;
214 }
215 }
216 }
217
218 return retval;
219 }
220
221 //--------------------------------------------------------------------------------------------
mad_get_madfx(mad_t * pmad,int action)222 Uint32 mad_get_madfx( mad_t * pmad, int action )
223 {
224 BIT_FIELD retval = EMPTY_BIT_FIELD;
225 int cnt;
226
227 MD2_Model_t * md2;
228 MD2_Frame_t * frame_lst, * pframe;
229
230 if ( NULL == pmad ) return 0;
231
232 md2 = pmad->md2_ptr;
233 if ( NULL == md2 ) return 0;
234
235 if ( action < 0 || action >= ACTION_COUNT ) return 0;
236
237 if ( !pmad->action_valid[action] ) return 0;
238
239 frame_lst = ( MD2_Frame_t * )md2_get_Frames( md2 );
240 for ( cnt = pmad->action_stt[action]; cnt <= pmad->action_end[action]; cnt++ )
241 {
242 pframe = frame_lst + cnt;
243
244 SET_BIT( retval, pframe->framefx );
245 }
246
247 return retval;
248 }
249
250 //--------------------------------------------------------------------------------------------
action_check_copy_vfs(mad_t * pmad,const char * loadname)251 mad_t * action_check_copy_vfs( mad_t * pmad, const char* loadname )
252 {
253 /// @details ZZ@> This function copies a model's actions
254
255 vfs_FILE *fileread;
256 int actiona, actionb;
257 char szOne[16] = EMPTY_CSTR;
258 char szTwo[16] = EMPTY_CSTR;
259
260 if ( NULL == pmad ) return pmad;
261
262 fileread = vfs_openRead( loadname );
263 if ( NULL == fileread ) return pmad;
264
265 while ( goto_colon( NULL, fileread, btrue ) )
266 {
267 fget_string( fileread, szOne, SDL_arraysize( szOne ) );
268 actiona = action_which( szOne[0] );
269
270 fget_string( fileread, szTwo, SDL_arraysize( szTwo ) );
271 actionb = action_which( szTwo[0] );
272
273 action_copy_correct( pmad, actiona + 0, actionb + 0 );
274 action_copy_correct( pmad, actiona + 1, actionb + 1 );
275 action_copy_correct( pmad, actiona + 2, actionb + 2 );
276 action_copy_correct( pmad, actiona + 3, actionb + 3 );
277 }
278
279 vfs_close( fileread );
280
281 return pmad;
282 }
283
284 //--------------------------------------------------------------------------------------------
action_which(char cTmp)285 int action_which( char cTmp )
286 {
287 /// @details ZZ@> This function changes a letter into an action code
288 int action;
289
290 switch ( toupper( cTmp ) )
291 {
292 case 'D': action = ACTION_DA; break;
293 case 'U': action = ACTION_UA; break;
294 case 'T': action = ACTION_TA; break;
295 case 'C': action = ACTION_CA; break;
296 case 'S': action = ACTION_SA; break;
297 case 'B': action = ACTION_BA; break;
298 case 'L': action = ACTION_LA; break;
299 case 'X': action = ACTION_XA; break;
300 case 'F': action = ACTION_FA; break;
301 case 'P': action = ACTION_PA; break;
302 case 'Z': action = ACTION_ZA; break;
303 // case 'W': action = ACTION_WA; break; //ZF> Can't do this, attack animation WALK is used for doing nothing (for example charging spells)
304 case 'H': action = ACTION_HA; break;
305 case 'K': action = ACTION_KA; break;
306 default: action = ACTION_DA; break;
307 }
308
309 return action;
310 }
311
312 //--------------------------------------------------------------------------------------------
mad_get_walk_frame(mad_t * pmad,int lip,int action)313 mad_t * mad_get_walk_frame( mad_t * pmad, int lip, int action )
314 {
315 /// @details ZZ@> This helps make walking look right
316 int frame = 0;
317 int framesinaction, action_stt;
318
319 if ( NULL == pmad ) return pmad;
320
321 action = mad_get_action( pmad, action );
322 if ( ACTION_COUNT == action )
323 {
324 framesinaction = 1;
325 action_stt = pmad->action_stt[ACTION_DA];
326 }
327 else
328 {
329 framesinaction = 1 + ( pmad->action_end[action] - pmad->action_stt[action] );
330 action_stt = pmad->action_stt[action];
331 }
332
333 for ( frame = 0; frame < 16; frame++ )
334 {
335 int framealong = 0;
336
337 if ( framesinaction > 0 )
338 {
339 framealong = (( frame * framesinaction / 16 ) + 2 ) % framesinaction;
340 }
341
342 pmad->frameliptowalkframe[lip][frame] = action_stt + framealong;
343 }
344
345 return pmad;
346 }
347
348 //--------------------------------------------------------------------------------------------
mad_get_framefx(mad_t * pmad,const char * cFrameName,int frame)349 mad_t * mad_get_framefx( mad_t * pmad, const char * cFrameName, int frame )
350 {
351 /// @details ZZ@> This function figures out the IFrame invulnerability, and Attack, Grab, and
352 /// Drop timings
353 ///
354 /// BB@> made a bit more sturdy parser that is not going to confuse strings like "LCRA"
355 /// which would not crop up if the convention of L or R going first was applied universally.
356 /// However, there are existing (and common) models which use the opposite convention, leading
357 /// to the possibility that an fx string "LARC" could be interpreted as ACTLEFT, CHARRIGHT, *and*
358 /// ACTRIGHT.
359
360 BIT_FIELD fx = 0;
361 char name_action[16], name_fx[16];
362 int name_count;
363 int fields;
364 int cnt;
365
366 static int token_count = -1;
367 static const char * tokens[] = { "I", "S", "F", "P", "A", "G", "D", "C", /* the normal command tokens */
368 "LA", "LG", "LD", "LC", "RA", "RG", "RD", "RC", NULL
369 }; /* the "bad" token aliases */
370
371 const char * ptmp, * ptmp_end;
372 char *paction, *paction_end;
373
374 MD2_Model_t * md2;
375 MD2_Frame_t * pframe;
376
377 if ( NULL == pmad ) return pmad;
378
379 md2 = pmad->md2_ptr;
380 if ( NULL == md2 ) return pmad;
381
382 // check for a valid frame number
383 if ( frame >= md2_get_numFrames( md2 ) ) return pmad;
384 pframe = ( MD2_Frame_t * )md2_get_Frames( md2 );
385 pframe = pframe + frame;
386
387 // this should only be initializwd the first time through
388 if ( token_count < 0 )
389 {
390 token_count = 0;
391 for ( cnt = 0; NULL != tokens[token_count] && cnt < 256; cnt++ ) token_count++;
392 }
393
394 // set the default values
395 fx = 0;
396 pframe->framefx = fx;
397
398 // check for a non-trivial frame name
399 if ( !VALID_CSTR( cFrameName ) ) return pmad;
400
401 // skip over whitespace
402 ptmp = cFrameName;
403 ptmp_end = cFrameName + 16;
404 for ( /* nothing */; ptmp < ptmp_end && isspace( *ptmp ); ptmp++ ) {};
405
406 // copy non-numerical text
407 paction = name_action;
408 paction_end = name_action + 16;
409 for ( /* nothing */; ptmp < ptmp_end && paction < paction_end && !isspace( *ptmp ); ptmp++, paction++ )
410 {
411 if ( isdigit( *ptmp ) ) break;
412 *paction = *ptmp;
413 }
414 if ( paction < paction_end ) *paction = CSTR_END;
415
416 name_fx[0] = CSTR_END;
417 fields = sscanf( ptmp, "%d %15s", &name_count, name_fx );
418 name_action[15] = CSTR_END;
419 name_fx[15] = CSTR_END;
420
421 // check for a non-trivial fx command
422 if ( !VALID_CSTR( name_fx ) ) return pmad;
423
424 // scan the fx string for valid commands
425 ptmp = name_fx;
426 ptmp_end = name_fx + 15;
427 while ( CSTR_END != *ptmp && ptmp < ptmp_end )
428 {
429 size_t len;
430 int token_index = -1;
431 for ( cnt = 0; cnt < token_count; cnt++ )
432 {
433 len = strlen( tokens[cnt] );
434 if ( 0 == strncmp( tokens[cnt], ptmp, len ) )
435 {
436 ptmp += len;
437 token_index = cnt;
438 break;
439 }
440 }
441
442 if ( -1 == token_index )
443 {
444 //log_debug( "Model %s, frame %d, frame name \"%s\" has unknown frame effects command \"%s\"\n", szModelName, frame, cFrameName, ptmp );
445 ptmp++;
446 }
447 else
448 {
449 bool_t bad_form = bfalse;
450 switch ( token_index )
451 {
452 case 0: // "I" == invulnerable
453 SET_BIT( fx, MADFX_INVICTUS );
454 break;
455
456 case 1: // "S" == stop
457 SET_BIT( fx, MADFX_STOP );
458 break;
459
460 case 2: // "F" == footfall
461 SET_BIT( fx, MADFX_FOOTFALL );
462 break;
463
464 case 3: // "P" == poof
465 SET_BIT( fx, MADFX_POOF );
466 break;
467
468 case 4: // "A" == action
469
470 // get any modifiers
471 while (( CSTR_END != *ptmp && ptmp < ptmp_end ) && ( 'R' == *ptmp || 'L' == *ptmp ) )
472 {
473 SET_BIT( fx, ( 'L' == *ptmp ) ? MADFX_ACTLEFT : MADFX_ACTRIGHT );
474 ptmp++;
475 }
476 break;
477
478 case 5: // "G" == grab
479
480 // get any modifiers
481 while (( CSTR_END != *ptmp && ptmp < ptmp_end ) && ( 'R' == *ptmp || 'L' == *ptmp ) )
482 {
483 SET_BIT( fx, ( 'L' == *ptmp ) ? MADFX_GRABLEFT : MADFX_GRABRIGHT );
484 ptmp++;
485 }
486 break;
487
488 case 6: // "D" == drop
489
490 // get any modifiers
491 while (( CSTR_END != *ptmp && ptmp < ptmp_end ) && ( 'R' == *ptmp || 'L' == *ptmp ) )
492 {
493 fx |= ( 'L' == *ptmp ) ? MADFX_DROPLEFT : MADFX_DROPRIGHT;
494 ptmp++;
495 }
496 break;
497
498 case 7: // "C" == grab a character
499
500 // get any modifiers
501 while (( CSTR_END != *ptmp && ptmp < ptmp_end ) && ( 'R' == *ptmp || 'L' == *ptmp ) )
502 {
503 SET_BIT( fx, ( 'L' == *ptmp ) ? MADFX_CHARLEFT : MADFX_CHARRIGHT );
504 ptmp++;
505 }
506 break;
507
508 case 8: // "LA"
509 bad_form = btrue;
510 SET_BIT( fx, MADFX_ACTLEFT );
511 break;
512
513 case 9: // "LG"
514 bad_form = btrue;
515 SET_BIT( fx, MADFX_GRABLEFT );
516 break;
517
518 case 10: // "LD"
519 bad_form = btrue;
520 SET_BIT( fx, MADFX_DROPLEFT );
521 break;
522
523 case 11: // "LC"
524 bad_form = btrue;
525 SET_BIT( fx, MADFX_CHARLEFT );
526 break;
527
528 case 12: // "RA"
529 bad_form = btrue;
530 SET_BIT( fx, MADFX_ACTRIGHT );
531 break;
532
533 case 13: // "RG"
534 bad_form = btrue;
535 SET_BIT( fx, MADFX_GRABRIGHT );
536 break;
537
538 case 14: // "RD"
539 bad_form = btrue;
540 SET_BIT( fx, MADFX_DROPRIGHT );
541 break;
542
543 case 15: // "RC"
544 bad_form = btrue;
545 SET_BIT( fx, MADFX_CHARRIGHT );
546 break;
547 }
548
549 if ( bad_form && -1 != token_index )
550 {
551 log_warning( "Model %s, frame %d, frame name \"%s\" has a frame effects command in an improper configuration \"%s\"\n", szModelName, frame, cFrameName, tokens[token_index] );
552 }
553 }
554 }
555
556 pframe->framefx = fx;
557
558 return pmad;
559 }
560
561 //--------------------------------------------------------------------------------------------
mad_make_framelip(mad_t * pmad,int action)562 mad_t * mad_make_framelip( mad_t * pmad, int action )
563 {
564 /// @details ZZ@> This helps make walking look right
565
566 int frame_count, frame, framesinaction;
567
568 MD2_Model_t * md2;
569 MD2_Frame_t * frame_list, * pframe;
570
571 if ( NULL == pmad ) return pmad;
572
573 if ( NULL == pmad->md2_ptr ) return pmad;
574 md2 = pmad->md2_ptr;
575
576 action = mad_get_action( pmad, action );
577 if ( ACTION_COUNT == action || ACTION_DA == action ) return pmad;
578
579 if ( !pmad->action_valid[action] ) return pmad;
580
581 frame_count = md2_get_numFrames( md2 );
582 frame_list = ( MD2_Frame_t * )md2_get_Frames( md2 );
583
584 framesinaction = pmad->action_end[action] - pmad->action_stt[action];
585
586 for ( frame = pmad->action_stt[action]; frame < pmad->action_end[action]; frame++ )
587 {
588 if ( frame > frame_count ) continue;
589 pframe = frame_list + frame;
590
591 pframe->framelip = ( frame - pmad->action_stt[action] ) * 15 / framesinaction;
592 pframe->framelip = ( pframe->framelip ) & 15;
593 }
594
595 return pmad;
596 }
597
598 //--------------------------------------------------------------------------------------------
mad_make_equally_lit(mad_t * pmad)599 mad_t * mad_make_equally_lit( mad_t * pmad )
600 {
601 /// @details ZZ@> This function makes ultra low poly models look better
602
603 int cnt, vert;
604 MD2_Model_t * md2;
605 int frame_count, vert_count;
606
607 if ( NULL == pmad ) return pmad;
608
609 md2 = pmad->md2_ptr;
610 if ( NULL == md2 ) return pmad;
611
612 frame_count = md2_get_numFrames( md2 );
613 vert_count = md2_get_numVertices( md2 );
614
615 for ( cnt = 0; cnt < frame_count; cnt++ )
616 {
617 MD2_Frame_t * pframe = ( MD2_Frame_t * )md2_get_Frames( md2 );
618 for ( vert = 0; vert < vert_count; vert++ )
619 {
620 pframe->vertex_lst[vert].normal = EGO_AMBIENT_INDEX;
621 }
622 }
623
624 return pmad;
625 }
626
627 //--------------------------------------------------------------------------------------------
load_action_names_vfs(const char * loadname)628 void load_action_names_vfs( const char* loadname )
629 {
630 /// @details ZZ@> This function loads all of the 2 letter action names
631
632 vfs_FILE* fileread;
633 int cnt;
634
635 char first = CSTR_END, second = CSTR_END;
636 STRING comment;
637 bool_t found;
638
639 fileread = vfs_openRead( loadname );
640 if ( !fileread ) return;
641
642 for ( cnt = 0; cnt < ACTION_COUNT; cnt++ )
643 {
644 comment[0] = CSTR_END;
645
646 found = bfalse;
647 if ( goto_colon( NULL, fileread, bfalse ) )
648 {
649 if ( vfs_scanf( fileread, " %c%c %s", &first, &second, &comment ) >= 2 )
650 {
651 found = btrue;
652 }
653 }
654
655 if ( found )
656 {
657 cActionName[cnt][0] = first;
658 cActionName[cnt][1] = second;
659 cActionComent[cnt][0] = CSTR_END;
660
661 if ( VALID_CSTR( comment ) )
662 {
663 strncpy( cActionComent[cnt], comment, SDL_arraysize( cActionComent[cnt] ) );
664 cActionComent[cnt][255] = CSTR_END;
665 }
666 }
667 else
668 {
669 cActionName[cnt][0] = CSTR_END;
670 cActionComent[cnt][0] = CSTR_END;
671 }
672 }
673
674 vfs_close( fileread );
675 }
676
677 //--------------------------------------------------------------------------------------------
load_one_model_profile_vfs(const char * tmploadname,const MAD_REF imad)678 MAD_REF load_one_model_profile_vfs( const char* tmploadname, const MAD_REF imad )
679 {
680 mad_t * pmad;
681 STRING newloadname;
682
683 if ( !VALID_MAD_RANGE( imad ) ) return ( MAD_REF )MAX_MAD;
684 pmad = MadStack.lst + imad;
685
686 // clear out the mad
687 mad_reconstruct( pmad );
688
689 // mark it as used
690 pmad->loaded = btrue;
691
692 // Make up a name for the model... IMPORT\TEMP0000.OBJ
693 strncpy( pmad->name, tmploadname, SDL_arraysize( pmad->name ) );
694 pmad->name[ SDL_arraysize( pmad->name ) - 1 ] = CSTR_END;
695
696 // Load the imad model
697 make_newloadname( tmploadname, "/tris.md2", newloadname );
698
699 // do this for now. maybe make it dynamic later...
700 //pmad->md2_ref = imad;
701
702 // load the model from the file
703 pmad->md2_ptr = md2_load( vfs_resolveReadFilename( newloadname ), NULL );
704
705 // set the model's file name
706 szModelName[0] = CSTR_END;
707 if ( NULL != pmad->md2_ptr )
708 {
709 strncpy( szModelName, vfs_resolveReadFilename( newloadname ), SDL_arraysize( szModelName ) );
710
711 /// @details BB@> Egoboo md2 models were designed with 1 tile = 32x32 units, but internally Egoboo uses
712 /// 1 tile = 128x128 units. Previously, this was handled by sprinkling a bunch of
713 /// commands that multiplied various quantities by 4 or by 4.125 throughout the code.
714 /// It was very counterintuitive, and caused me no end of headaches... Of course the
715 /// solution is to scale the model!
716 md2_scale_model( pmad->md2_ptr, -3.5f, 3.5f, 3.5f );
717 }
718
719 // Create the actions table for this imad
720 mad_rip_actions( pmad );
721 mad_heal_actions( pmad, tmploadname );
722 mad_finalize( pmad );
723
724 return imad;
725 }
726
727 //--------------------------------------------------------------------------------------------
mad_heal_actions(mad_t * pmad,const char * tmploadname)728 mad_t * mad_heal_actions( mad_t * pmad, const char * tmploadname )
729 {
730 STRING newloadname;
731
732 if ( NULL == pmad ) return pmad;
733
734 // Make sure actions are made valid if a similar one exists
735 action_copy_correct( pmad, ACTION_DA, ACTION_DB ); // All dances should be safe
736 action_copy_correct( pmad, ACTION_DB, ACTION_DC );
737 action_copy_correct( pmad, ACTION_DC, ACTION_DD );
738 action_copy_correct( pmad, ACTION_DB, ACTION_DC );
739 action_copy_correct( pmad, ACTION_DA, ACTION_DB );
740 action_copy_correct( pmad, ACTION_UA, ACTION_UB );
741 action_copy_correct( pmad, ACTION_UB, ACTION_UC );
742 action_copy_correct( pmad, ACTION_UC, ACTION_UD );
743 action_copy_correct( pmad, ACTION_TA, ACTION_TB );
744 action_copy_correct( pmad, ACTION_TC, ACTION_TD );
745 action_copy_correct( pmad, ACTION_CA, ACTION_CB );
746 action_copy_correct( pmad, ACTION_CC, ACTION_CD );
747 action_copy_correct( pmad, ACTION_SA, ACTION_SB );
748 action_copy_correct( pmad, ACTION_SC, ACTION_SD );
749 action_copy_correct( pmad, ACTION_BA, ACTION_BB );
750 action_copy_correct( pmad, ACTION_BC, ACTION_BD );
751 action_copy_correct( pmad, ACTION_LA, ACTION_LB );
752 action_copy_correct( pmad, ACTION_LC, ACTION_LD );
753 action_copy_correct( pmad, ACTION_XA, ACTION_XB );
754 action_copy_correct( pmad, ACTION_XC, ACTION_XD );
755 action_copy_correct( pmad, ACTION_FA, ACTION_FB );
756 action_copy_correct( pmad, ACTION_FC, ACTION_FD );
757 action_copy_correct( pmad, ACTION_PA, ACTION_PB );
758 action_copy_correct( pmad, ACTION_PC, ACTION_PD );
759 action_copy_correct( pmad, ACTION_ZA, ACTION_ZB );
760 action_copy_correct( pmad, ACTION_ZC, ACTION_ZD );
761 action_copy_correct( pmad, ACTION_WA, ACTION_WB );
762 action_copy_correct( pmad, ACTION_WB, ACTION_WC );
763 action_copy_correct( pmad, ACTION_WC, ACTION_WD );
764 action_copy_correct( pmad, ACTION_DA, ACTION_WD ); // All walks should be safe
765 action_copy_correct( pmad, ACTION_WC, ACTION_WD );
766 action_copy_correct( pmad, ACTION_WB, ACTION_WC );
767 action_copy_correct( pmad, ACTION_WA, ACTION_WB );
768 action_copy_correct( pmad, ACTION_JA, ACTION_JB );
769 action_copy_correct( pmad, ACTION_JB, ACTION_JC );
770 action_copy_correct( pmad, ACTION_DA, ACTION_JC ); // All jumps should be safe
771 action_copy_correct( pmad, ACTION_JB, ACTION_JC );
772 action_copy_correct( pmad, ACTION_JA, ACTION_JB );
773 action_copy_correct( pmad, ACTION_HA, ACTION_HB );
774 action_copy_correct( pmad, ACTION_HB, ACTION_HC );
775 action_copy_correct( pmad, ACTION_HC, ACTION_HD );
776 action_copy_correct( pmad, ACTION_HB, ACTION_HC );
777 action_copy_correct( pmad, ACTION_HA, ACTION_HB );
778 action_copy_correct( pmad, ACTION_KA, ACTION_KB );
779 action_copy_correct( pmad, ACTION_KB, ACTION_KC );
780 action_copy_correct( pmad, ACTION_KC, ACTION_KD );
781 action_copy_correct( pmad, ACTION_KB, ACTION_KC );
782 action_copy_correct( pmad, ACTION_KA, ACTION_KB );
783 action_copy_correct( pmad, ACTION_MH, ACTION_MI );
784 action_copy_correct( pmad, ACTION_DA, ACTION_MM );
785 action_copy_correct( pmad, ACTION_MM, ACTION_MN );
786
787 // Copy entire actions to save frame space COPY.TXT
788 make_newloadname( tmploadname, "/copy.txt", newloadname );
789 action_check_copy_vfs( pmad, newloadname );
790
791 return pmad;
792 }
793
794 //--------------------------------------------------------------------------------------------
mad_finalize(mad_t * pmad)795 mad_t * mad_finalize( mad_t * pmad )
796 {
797 int frame, frame_count;
798
799 MD2_Model_t * pmd2;
800 MD2_Frame_t * frame_list;
801
802 if ( NULL == pmad ) return pmad;
803
804 if ( NULL == pmad->md2_ptr ) return pmad;
805 pmd2 = pmad->md2_ptr;
806
807 frame_count = md2_get_numFrames( pmd2 );
808 frame_list = ( MD2_Frame_t * )md2_get_Frames( pmd2 );
809
810 // Create table for doing transition from one type of walk to another...
811 // Clear 'em all to start
812 for ( frame = 0; frame < frame_count; frame++ )
813 {
814 frame_list[frame].framelip = 0;
815 }
816
817 // Need to figure out how far into action each frame is
818 mad_make_framelip( pmad, ACTION_WA );
819 mad_make_framelip( pmad, ACTION_WB );
820 mad_make_framelip( pmad, ACTION_WC );
821
822 // Now do the same, in reverse, for walking animations
823 mad_get_walk_frame( pmad, LIPDA, ACTION_DA );
824 mad_get_walk_frame( pmad, LIPWA, ACTION_WA );
825 mad_get_walk_frame( pmad, LIPWB, ACTION_WB );
826 mad_get_walk_frame( pmad, LIPWC, ACTION_WC );
827
828 return pmad;
829 }
830
831 //--------------------------------------------------------------------------------------------
mad_rip_actions(mad_t * pmad)832 mad_t * mad_rip_actions( mad_t * pmad )
833 {
834 /// \author ZZ
835 /// \details This function creates the iframe lists for each action_now based on the
836 /// name of each md2 iframe in the model
837
838 int frame_count, iframe;
839 int action_now, last_action;
840
841 MD2_Model_t * pmd2;
842 MD2_Frame_t * frame_list;
843
844 if ( NULL == pmad ) return pmad;
845
846 pmd2 = pmad->md2_ptr;
847 if ( NULL == pmd2 ) return pmad;
848
849 // Clear out all actions and reset to invalid
850 for ( action_now = 0; action_now < ACTION_COUNT; action_now++ )
851 {
852 pmad->action_map[action_now] = ACTION_COUNT;
853 pmad->action_stt[action_now] = -1;
854 pmad->action_end[action_now] = -1;
855 pmad->action_valid[action_now] = bfalse;
856 }
857
858 // grab the frame info from the md2
859 frame_count = md2_get_numFrames( pmd2 );
860 frame_list = ( MD2_Frame_t * )md2_get_Frames( pmd2 );
861
862 // is there anything to do?
863 if ( 0 == frame_count ) return pmad;
864
865 // Make a default dance action (ACTION_DA) to be the 1st frame of the animation
866 pmad->action_map[ACTION_DA] = ACTION_DA;
867 pmad->action_valid[ACTION_DA] = btrue;
868 pmad->action_stt[ACTION_DA] = 0;
869 pmad->action_end[ACTION_DA] = 0;
870
871 // Now go huntin' to see what each iframe is, look for runs of same action_now
872 last_action = ACTION_COUNT;
873 for ( iframe = 0; iframe < frame_count; iframe++ )
874 {
875 action_now = action_number( frame_list[iframe].name );
876
877 if ( last_action != action_now )
878 {
879 // start a new action
880 pmad->action_map[action_now] = action_now;
881 pmad->action_stt[action_now] = iframe;
882 pmad->action_end[action_now] = iframe;
883 pmad->action_valid[action_now] = btrue;
884
885 last_action = action_now;
886 }
887 else
888 {
889 // keep expanding the action_end until the end of the action
890 pmad->action_end[action_now] = iframe;
891 }
892
893 mad_get_framefx( pmad, frame_list[iframe].name, iframe );
894 }
895
896 return pmad;
897 }
898
899 //--------------------------------------------------------------------------------------------
900 //--------------------------------------------------------------------------------------------
mad_free(mad_t * pmad)901 bool_t mad_free( mad_t * pmad )
902 {
903 /// Free all allocated memory
904
905 if ( NULL == pmad || !pmad->loaded ) return bfalse;
906
907 MD2_Model_destroy( &( pmad->md2_ptr ) );
908
909 return btrue;
910 }
911
912 //--------------------------------------------------------------------------------------------
mad_reconstruct(mad_t * pmad)913 mad_t * mad_reconstruct( mad_t * pmad )
914 {
915 /// @details BB@> initialize the character data to safe values
916 /// since we use memset(..., 0, ...), all = 0, = false, and = 0.0f
917 /// statements are redundant
918
919 int action;
920
921 if ( NULL == pmad ) return NULL;
922
923 mad_free( pmad );
924
925 memset( pmad, 0, sizeof( *pmad ) );
926
927 strncpy( pmad->name, "*NONE*", SDL_arraysize( pmad->name ) );
928
929 // Clear out all actions and reset to invalid
930 for ( action = 0; action < ACTION_COUNT; action++ )
931 {
932 pmad->action_map[action] = ACTION_COUNT;
933 }
934
935 return pmad;
936 }
937
938 //--------------------------------------------------------------------------------------------
mad_ctor(mad_t * pmad)939 mad_t * mad_ctor( mad_t * pmad )
940 {
941 if ( NULL == mad_reconstruct( pmad ) ) return NULL;
942
943 // nothing to do yet
944
945 return pmad;
946 }
947
948 //--------------------------------------------------------------------------------------------
mad_dtor(mad_t * pmad)949 mad_t * mad_dtor( mad_t * pmad )
950 {
951 /// @details BB@> deinitialize the character data
952
953 if ( NULL == pmad || !pmad->loaded ) return NULL;
954
955 // deinitialize the object
956 mad_reconstruct( pmad );
957
958 // "destruct" the base object
959 pmad->loaded = bfalse;
960
961 return pmad;
962 }
963
964 //--------------------------------------------------------------------------------------------
init_all_mad()965 void init_all_mad()
966 {
967 MAD_REF cnt;
968
969 for ( cnt = 0; cnt < MAX_MAD; cnt++ )
970 {
971 mad_reconstruct( MadStack.lst + cnt );
972 }
973 }
974
975 //--------------------------------------------------------------------------------------------
release_all_mad()976 void release_all_mad()
977 {
978 MAD_REF cnt;
979
980 for ( cnt = 0; cnt < MAX_MAD; cnt++ )
981 {
982 release_one_mad( cnt );
983 }
984 }
985
986 //--------------------------------------------------------------------------------------------
release_one_mad(const MAD_REF imad)987 bool_t release_one_mad( const MAD_REF imad )
988 {
989 mad_t * pmad;
990
991 if ( !VALID_MAD_RANGE( imad ) ) return bfalse;
992 pmad = MadStack.lst + imad;
993
994 if ( !pmad->loaded ) return btrue;
995
996 // free any md2 data
997 mad_reconstruct( pmad );
998
999 return btrue;
1000 }
1001
1002 //--------------------------------------------------------------------------------------------
randomize_action(int action,int slot)1003 int randomize_action( int action, int slot )
1004 {
1005 /// @details BB@> this function actually determines whether the action fillows the
1006 /// pattern of ACTION_?A, ACTION_?B, ACTION_?C, ACTION_?D, with
1007 /// A and B being for the left hand, and C and D being for the right hand
1008
1009 int diff = 0;
1010
1011 // a valid slot?
1012 if ( slot < 0 || slot >= SLOT_COUNT ) return action;
1013
1014 // a valid action?
1015 if ( action < 0 || action >= ACTION_COUNT ) return bfalse;
1016
1017 diff = slot * 2;
1018
1019 //---- non-randomizable actions
1020 if ( ACTION_MG == action ) return action; // MG = Open Chest
1021 else if ( ACTION_MH == action ) return action; // MH = Sit
1022 else if ( ACTION_MI == action ) return action; // MI = Ride
1023 else if ( ACTION_MJ == action ) return action; // MJ = Object Activated
1024 else if ( ACTION_MK == action ) return action; // MK = Snoozing
1025 else if ( ACTION_ML == action ) return action; // ML = Unlock
1026 else if ( ACTION_JA == action ) return action; // JA = Jump
1027 else if ( ACTION_RA == action ) return action; // RA = Roll
1028 else if ( ACTION_IS_TYPE( action, W ) ) return action; // WA - WD = Walk
1029
1030 //---- do a couple of special actions that have left/right
1031 else if ( ACTION_EA == action || ACTION_EB == action ) action = ACTION_JB + slot; // EA/EB = Evade left/right
1032 else if ( ACTION_JB == action || ACTION_JC == action ) action = ACTION_JB + slot; // JB/JC = Dropped item left/right
1033 else if ( ACTION_MA == action || ACTION_MB == action ) action = ACTION_MA + slot; // MA/MB = Drop left/right item
1034 else if ( ACTION_MC == action || ACTION_MD == action ) action = ACTION_MC + slot; // MC/MD = Slam left/right
1035 else if ( ACTION_ME == action || ACTION_MF == action ) action = ACTION_ME + slot; // ME/MF = Grab item left/right
1036 else if ( ACTION_MM == action || ACTION_MN == action ) action = ACTION_MM + slot; // MM/MN = Held left/right
1037
1038 //---- actions that can be randomized, but are not left/right sensitive
1039 // D = dance
1040 else if ( ACTION_IS_TYPE( action, D ) ) action = ACTION_TYPE( D ) + generate_randmask( 0, 3 );
1041
1042 //---- handle all the normal attack/defense animations
1043 // U = unarmed
1044 else if ( ACTION_IS_TYPE( action, U ) ) action = ACTION_TYPE( U ) + diff + generate_randmask( 0, 1 );
1045 // T = thrust
1046 else if ( ACTION_IS_TYPE( action, T ) ) action = ACTION_TYPE( T ) + diff + generate_randmask( 0, 1 );
1047 // C = chop
1048 else if ( ACTION_IS_TYPE( action, C ) ) action = ACTION_TYPE( C ) + diff + generate_randmask( 0, 1 );
1049 // S = slice
1050 else if ( ACTION_IS_TYPE( action, S ) ) action = ACTION_TYPE( S ) + diff + generate_randmask( 0, 1 );
1051 // B = bash
1052 else if ( ACTION_IS_TYPE( action, B ) ) action = ACTION_TYPE( B ) + diff + generate_randmask( 0, 1 );
1053 // L = longbow
1054 else if ( ACTION_IS_TYPE( action, L ) ) action = ACTION_TYPE( L ) + diff + generate_randmask( 0, 1 );
1055 // X = crossbow
1056 else if ( ACTION_IS_TYPE( action, X ) ) action = ACTION_TYPE( X ) + diff + generate_randmask( 0, 1 );
1057 // F = fling
1058 else if ( ACTION_IS_TYPE( action, F ) ) action = ACTION_TYPE( F ) + diff + generate_randmask( 0, 1 );
1059 // P = parry/block
1060 else if ( ACTION_IS_TYPE( action, P ) ) action = ACTION_TYPE( P ) + diff + generate_randmask( 0, 1 );
1061 // Z = zap
1062 else if ( ACTION_IS_TYPE( action, Z ) ) action = ACTION_TYPE( Z ) + diff + generate_randmask( 0, 1 );
1063
1064 //---- these are passive actions
1065 // H = hurt
1066 else if ( ACTION_IS_TYPE( action, H ) ) action = ACTION_TYPE( H ) + generate_randmask( 0, 3 );
1067 // K = killed
1068 else if ( ACTION_IS_TYPE( action, K ) ) action = ACTION_TYPE( K ) + generate_randmask( 0, 3 );
1069
1070 return action;
1071 }
1072
1073 //--------------------------------------------------------------------------------------------
1074 //--------------------------------------------------------------------------------------------
mad_get_action_ref(const MAD_REF imad,int action)1075 int mad_get_action_ref( const MAD_REF imad, int action )
1076 {
1077 /// @detaills BB@> translate the action that was given into a valid action for the model
1078 ///
1079 /// returns ACTION_COUNT on a complete failure, or the default ACTION_DA if it exists
1080
1081 if ( !LOADED_MAD( imad ) ) return ACTION_COUNT;
1082
1083 return mad_get_action( MadStack.lst + imad, action );
1084 }
1085
1086 //--------------------------------------------------------------------------------------------
mad_get_madfx_ref(const MAD_REF imad,int action)1087 Uint32 mad_get_madfx_ref( const MAD_REF imad, int action )
1088 {
1089 if ( !LOADED_MAD( imad ) ) return 0;
1090
1091 return mad_get_madfx( MadStack.lst + imad, action );
1092 }
1093
1094 //--------------------------------------------------------------------------------------------
mad_make_equally_lit_ref(const MAD_REF imad)1095 void mad_make_equally_lit_ref( const MAD_REF imad )
1096 {
1097 if ( LOADED_MAD( imad ) )
1098 {
1099 mad_make_equally_lit( MadStack.lst + imad );
1100 }
1101 }
1102
1103 //--------------------------------------------------------------------------------------------
1104 ////--------------------------------------------------------------------------------------------
1105 //Uint16 test_frame_name( char letter )
1106 //{
1107 // /// @details ZZ@> This function returns btrue if the 4th, 5th, 6th, or 7th letters
1108 // /// of the frame name matches the input argument
1109 //
1110 // if ( letter == cFrameName[4] ) return btrue;
1111 // if ( CSTR_END == cFrameName[4] ) return bfalse;
1112 // if ( letter == cFrameName[5] ) return btrue;
1113 // if ( CSTR_END == cFrameName[5] ) return bfalse;
1114 // if ( letter == cFrameName[6] ) return btrue;
1115 // if ( CSTR_END == cFrameName[6] ) return bfalse;
1116 // if ( letter == cFrameName[7] ) return btrue;
1117 //
1118 // return bfalse;
1119 //}
1120
1121 //--------------------------------------------------------------------------------------------
1122 //void md2_fix_normals( const MAD_REF imad )
1123 //{
1124 // /// @details ZZ@> This function helps light not flicker so much
1125 // int cnt, tnc;
1126 // int indexofcurrent, indexofnext, indexofnextnext, indexofnextnextnext;
1127 // int indexofnextnextnextnext;
1128 // int frame;
1129 //
1130 // frame = ego_md2_data[MadStack.lst[imad].md2_ref].framestart;
1131 // cnt = 0;
1132 //
1133 // while ( cnt < ego_md2_data[MadStack.lst[imad].md2_ref].vertex_lst )
1134 // {
1135 // tnc = 0;
1136 //
1137 // while ( tnc < ego_md2_data[MadStack.lst[imad].md2_ref].frames )
1138 // {
1139 // indexofcurrent = pframe->vrta[cnt];
1140 // indexofnext = Md2FrameList[frame+1].vrta[cnt];
1141 // indexofnextnext = Md2FrameList[frame+2].vrta[cnt];
1142 // indexofnextnextnext = Md2FrameList[frame+3].vrta[cnt];
1143 // indexofnextnextnextnext = Md2FrameList[frame+4].vrta[cnt];
1144 // if ( indexofcurrent == indexofnextnext && indexofnext != indexofcurrent )
1145 // {
1146 // Md2FrameList[frame+1].vrta[cnt] = indexofcurrent;
1147 // }
1148 // if ( indexofcurrent == indexofnextnextnext )
1149 // {
1150 // if ( indexofnext != indexofcurrent )
1151 // {
1152 // Md2FrameList[frame+1].vrta[cnt] = indexofcurrent;
1153 // }
1154 // if ( indexofnextnext != indexofcurrent )
1155 // {
1156 // Md2FrameList[frame+2].vrta[cnt] = indexofcurrent;
1157 // }
1158 // }
1159 // if ( indexofcurrent == indexofnextnextnextnext )
1160 // {
1161 // if ( indexofnext != indexofcurrent )
1162 // {
1163 // Md2FrameList[frame+1].vrta[cnt] = indexofcurrent;
1164 // }
1165 // if ( indexofnextnext != indexofcurrent )
1166 // {
1167 // Md2FrameList[frame+2].vrta[cnt] = indexofcurrent;
1168 // }
1169 // if ( indexofnextnextnext != indexofcurrent )
1170 // {
1171 // Md2FrameList[frame+3].vrta[cnt] = indexofcurrent;
1172 // }
1173 // }
1174 //
1175 // tnc++;
1176 // }
1177 //
1178 // cnt++;
1179 // }
1180 //}
1181
1182 //--------------------------------------------------------------------------------------------
1183 //void md2_get_transvertices( const MAD_REF imad )
1184 //{
1185 // /// @details ZZ@> This function gets the number of vertices to transform for a model...
1186 // // That means every one except the grip ( unconnected ) vertices
1187 //
1188 // // if (imad == 0)
1189 // // {
1190 // // for ( cnt = 0; cnt < MadStack.lst[imad].vertex_lst; cnt++ )
1191 // // {
1192 // // printf("%d-%d\n", cnt, vertexconnected( imad, cnt ) );
1193 // // }
1194 // // }
1195 //
1196 // MadStack.lst[imad].transvertices = ego_md2_data[MadStack.lst[imad].md2_ref].vertex_lst;
1197 //}
1198
1199 //--------------------------------------------------------------------------------------------
1200 /*int vertexconnected( md2_ogl_commandlist_t * pclist, int vertex )
1201 {
1202 /// @details ZZ@> This function returns 1 if the model vertex is connected, 0 otherwise
1203 int cnt, tnc, entry;
1204
1205 entry = 0;
1206
1207 for ( cnt = 0; cnt < pclist->count; cnt++ )
1208 {
1209 for ( tnc = 0; tnc < pclist->size[cnt]; tnc++ )
1210 {
1211 if ( pclist->vrt[entry] == vertex )
1212 {
1213 // The vertex is used
1214 return 1;
1215 }
1216
1217 entry++;
1218 }
1219 }
1220
1221 // The vertex is not used
1222 return 0;
1223 }*/
1224
1225 ////--------------------------------------------------------------------------------------------
1226 //int action_frame()
1227 //{
1228 // /// @details ZZ@> This function returns the frame number in the third and fourth characters
1229 // /// of cFrameName
1230 //
1231 // int number;
1232 // char tmp_str[16];
1233 //
1234 // sscanf( cFrameName, " %15s%d", tmp_str, &number );
1235 //
1236 // return number;
1237 //}
1238
1239