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