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 profile.c
21 /// @brief Implementation of functions for controlling and accessing object profiles
22 /// @details
23
24 #include "profile.inl"
25
26 #include "ChrList.h"
27 #include "PrtList.h"
28
29 #include "texture.h"
30 #include "log.h"
31 #include "script_compile.h"
32 #include "game.h"
33
34 #include "egoboo_setup.h"
35 #include "egoboo_strutil.h"
36 #include "egoboo_fileutil.h"
37 #include "egoboo_vfs.h"
38 #include "egoboo_mem.h"
39
40 #include "mesh.inl"
41 #include "bsp.inl"
42 #include "particle.inl"
43
44 //--------------------------------------------------------------------------------------------
45 //--------------------------------------------------------------------------------------------
46 static bool_t _profile_system_initialized = bfalse;
47
48 chop_data_t chop_mem = {0, 0};
49 pro_import_t import_data;
50
51 size_t bookicon_count = 0;
52 TX_REF bookicon_ref[MAX_SKIN]; // The first book icon
53
54 INSTANTIATE_LIST( ACCESS_TYPE_NONE, pro_t, ProList, MAX_PROFILE );
55 INSTANTIATE_STATIC_ARY( MessageOffsetAry, MessageOffset );
56
57 Uint32 message_buffer_carat = 0; // Where to put letter
58 char message_buffer[MESSAGEBUFFERSIZE] = EMPTY_CSTR; // The text buffer
59
60 //--------------------------------------------------------------------------------------------
61 //--------------------------------------------------------------------------------------------
62 static void get_message( vfs_FILE* fileread );
63
64 //--------------------------------------------------------------------------------------------
65 //--------------------------------------------------------------------------------------------
init_all_profiles()66 void init_all_profiles()
67 {
68 /// @details ZZ@> This function initializes all of the model profiles
69
70 int tnc;
71
72 // initialize all the sub-profile lists
73 init_all_pip();
74 init_all_eve();
75 init_all_cap();
76 init_all_mad();
77 init_all_ai_scripts();
78
79 // initialize the profile list
80 ProList_init();
81
82 // fix the book icon list
83 for ( tnc = 0; tnc < MAX_SKIN; tnc++ )
84 {
85 bookicon_ref[tnc] = INVALID_TX_TEXTURE;
86 }
87 bookicon_count = 0;
88 }
89
90 //--------------------------------------------------------------------------------------------
release_all_profiles()91 void release_all_profiles()
92 {
93 /// @details ZZ@> This function clears out all of the model data
94
95 // release the allocated data in all profiles (sounds, textures, etc.)
96 release_all_pro_data();
97
98 // relese every type of sub-profile and re-initalize the lists
99 release_all_pip();
100 release_all_eve();
101 release_all_cap();
102 release_all_mad();
103 release_all_ai_scripts();
104
105 // re-initialize the profile list
106 ProList_init();
107 }
108
109 //--------------------------------------------------------------------------------------------
profile_system_begin()110 void profile_system_begin()
111 {
112 /// @details BB@> initialize the profile list and load up some intialization files
113 /// necessary for the the profile loading code to work
114
115 if ( _profile_system_initialized )
116 {
117 // release all profile data and reinitialize the profile list
118 release_all_profiles();
119
120 _profile_system_initialized = bfalse;
121 }
122
123 // initialize all the profile lists
124 init_all_profiles();
125
126 // initialize the script compiler
127 script_compiler_init();
128
129 // necessary for loading up the copy.txt file
130 load_action_names_vfs( "mp_data/actions.txt" );
131
132 // necessary for properly reading the "message.txt"
133 reset_messages();
134
135 // necessary for reading "naming.txt" properly
136 chop_data_init( &chop_mem );
137
138 // something that is used in the game that is somewhat related to the profile stuff
139 init_slot_idsz();
140
141 // let the code know that everything is initialized
142 _profile_system_initialized = btrue;
143 }
144
145 //--------------------------------------------------------------------------------------------
profile_system_end()146 void profile_system_end()
147 {
148 /// @details BB@> initialize the profile list and load up some intialization files
149 /// necessary for the the profile loading code to work
150
151 if ( _profile_system_initialized )
152 {
153 // release all profile data and reinitialize the profile list
154 release_all_profiles();
155
156 _profile_system_initialized = bfalse;
157 }
158 }
159
160 //--------------------------------------------------------------------------------------------
161 //--------------------------------------------------------------------------------------------
pro_init(pro_t * pobj)162 bool_t pro_init( pro_t * pobj )
163 {
164 int cnt;
165
166 if ( NULL == pobj ) return bfalse;
167
168 if ( pobj->loaded )
169 {
170 log_warning( "pro_init() - trying to init an object in use" );
171 }
172
173 //---- reset everything to safe values
174 memset( pobj, 0, sizeof( *pobj ) );
175
176 pobj->icap = ( CAP_REF ) MAX_CAP;
177 pobj->imad = ( MAD_REF ) MAX_MAD;
178 pobj->ieve = ( EVE_REF ) MAX_EVE;
179
180 for ( cnt = 0; cnt < MAX_PIP_PER_PROFILE; cnt++ )
181 {
182 pobj->prtpip[cnt] = ( PIP_REF ) MAX_PIP;
183 }
184
185 chop_definition_init( &( pobj->chop ) );
186
187 // do the final invalidation
188 pobj->loaded = bfalse;
189 strncpy( pobj->name, "*NONE*", SDL_arraysize( pobj->name ) );
190
191 // clear out the textures
192 for ( cnt = 0; cnt < MAX_SKIN; cnt++ )
193 {
194 pobj->tex_ref[cnt] = INVALID_TX_TEXTURE;
195 pobj->ico_ref[cnt] = INVALID_TX_TEXTURE;
196 }
197
198 return btrue;
199 }
200
201 //--------------------------------------------------------------------------------------------
202 // The "private" ProList management functions
203 //--------------------------------------------------------------------------------------------
ProList_search_free(const PRO_REF iobj)204 int ProList_search_free( const PRO_REF iobj )
205 {
206 /// @details BB@> if an object of index iobj exists on the free list, return the free list index
207 /// otherwise return -1
208
209 int cnt, retval;
210
211 // determine whether this character is already in the list of free textures
212 // that is an error
213 retval = -1;
214 for ( cnt = 0; cnt < ProList.free_count; cnt++ )
215 {
216 if ( iobj == ProList.free_ref[cnt] )
217 {
218 retval = cnt;
219 break;
220 }
221 }
222
223 return retval;
224 }
225
226 //--------------------------------------------------------------------------------------------
ProList_pop_free(int idx)227 size_t ProList_pop_free( int idx )
228 {
229 /// @details BB@> pop off whatever object exists at the free list index idx
230
231 size_t retval;
232
233 if ( idx >= 0 && idx < ProList.free_count )
234 {
235 // move the index idx to the top
236 int idx_top, idx_bottom;
237
238 idx_bottom = idx;
239 idx_top = ProList.free_count - 1;
240
241 // make sure this is a valid case
242 if ( idx_top > idx_bottom && idx_top > 1 )
243 {
244 SWAP( size_t, ProList.free_ref[idx_top], ProList.free_ref[idx_bottom] );
245 }
246 }
247
248 // just pop off the top index
249 retval = MAX_PROFILE;
250 if ( ProList.free_count > 0 )
251 {
252 ProList.free_count--;
253 ProList.update_guid++;
254
255 retval = ProList.free_ref[ProList.free_count];
256 }
257
258 return retval;
259 }
260
261 //--------------------------------------------------------------------------------------------
ProList_push_free(const PRO_REF iobj)262 bool_t ProList_push_free( const PRO_REF iobj )
263 {
264 /// @details BB@> push an object onto the free stack
265
266 bool_t retval;
267
268 #if defined(_DEBUG)
269 // determine whether this character is already in the list of free objects
270 // that is an error
271 if ( -1 != ProList_search_free( iobj ) ) return bfalse;
272 #endif
273
274 // push it on the free stack
275 retval = bfalse;
276 if ( ProList.free_count < MAX_PROFILE )
277 {
278 ProList.free_ref[ProList.free_count] = REF_TO_INT( iobj );
279
280 ProList.free_count++;
281 ProList.update_guid++;
282
283 retval = btrue;
284 }
285
286 return retval;
287 }
288
289 //--------------------------------------------------------------------------------------------
290 // The "public" ProList management functions
291 //--------------------------------------------------------------------------------------------
ProList_init()292 void ProList_init()
293 {
294 /// @details BB@> initialize all the objects and the object free list.
295 /// call before ever using the object list.
296
297 PRO_REF cnt;
298
299 ProList.free_count = 0;
300 for ( cnt = 0; cnt < MAX_PROFILE; cnt++ )
301 {
302 // make sure we don't get a stupid warning
303 ProList.lst[cnt].loaded = bfalse;
304 pro_init( ProList.lst + cnt );
305
306 ProList_push_free( cnt );
307 }
308 }
309
310 //--------------------------------------------------------------------------------------------
ProList_get_free(const PRO_REF override)311 size_t ProList_get_free( const PRO_REF override )
312 {
313 /// @details ZZ@> This function returns the next free character or MAX_PROFILE if there are none
314
315 size_t retval = MAX_PROFILE;
316
317 if ( VALID_PRO_RANGE( override ) )
318 {
319 // grab the object that is specified.
320 int free_idx;
321
322 // if the object is in use, make sure to free everything associated with it
323 if ( LOADED_PRO( override ) )
324 {
325 release_one_pro( override );
326 }
327
328 // grab the specified index
329 free_idx = ProList_search_free( override );
330 retval = ProList_pop_free( free_idx );
331 }
332 else
333 {
334 // grab the next free index
335 retval = ProList_pop_free( -1 );
336 }
337
338 return retval;
339 }
340
341 //--------------------------------------------------------------------------------------------
ProList_free_one(const PRO_REF iobj)342 bool_t ProList_free_one( const PRO_REF iobj )
343 {
344 /// @details ZZ@> This function sticks an object back on the free object stack
345
346 if ( !VALID_PRO_RANGE( iobj ) ) return bfalse;
347
348 // object "destructor"
349 // inilializes an object to safe values
350 pro_init( ProList.lst + iobj );
351
352 return ProList_push_free( iobj );
353 }
354
355 //--------------------------------------------------------------------------------------------
356 // object functions
357 //--------------------------------------------------------------------------------------------
358 //--------------------------------------------------------------------------------------------
release_one_profile_textures(const PRO_REF iobj)359 bool_t release_one_profile_textures( const PRO_REF iobj )
360 {
361 int tnc;
362 pro_t * pobj;
363
364 if ( !LOADED_PRO( iobj ) ) return bfalse;
365 pobj = ProList.lst + iobj;
366
367 for ( tnc = 0; tnc < MAX_SKIN; tnc++ )
368 {
369 TX_REF itex;
370
371 itex = pobj->tex_ref[tnc];
372 if ( itex > TX_LAST )
373 {
374 TxTexture_free_one( itex );
375 }
376 pobj->tex_ref[tnc] = INVALID_TX_TEXTURE;
377
378 itex = pobj->ico_ref[tnc] ;
379 if ( itex > TX_LAST )
380 {
381 TxTexture_free_one( itex );
382 }
383 pobj->ico_ref[tnc] = INVALID_TX_TEXTURE;
384 }
385
386 // reset the bookicon stuff if this object is a book
387 if ( SPELLBOOK == iobj )
388 {
389 for ( tnc = 0; tnc < MAX_SKIN; tnc++ )
390 {
391 bookicon_ref[tnc] = INVALID_TX_TEXTURE;
392 }
393 bookicon_count = 0;
394 }
395
396 return btrue;
397 }
398
399 //--------------------------------------------------------------------------------------------
release_all_profile_textures()400 void release_all_profile_textures()
401 {
402 PRO_REF cnt;
403
404 for ( cnt = 0; cnt < MAX_PROFILE; cnt++ )
405 {
406 release_one_profile_textures( cnt );
407 }
408 }
409
410 //--------------------------------------------------------------------------------------------
release_one_pro_data(const PRO_REF iobj)411 bool_t release_one_pro_data( const PRO_REF iobj )
412 {
413 int cnt;
414 pro_t * pobj;
415
416 if ( !LOADED_PRO( iobj ) ) return bfalse;
417 pobj = ProList.lst + iobj;
418
419 // free all sounds
420 for ( cnt = 0; cnt < MAX_WAVE; cnt++ )
421 {
422 sound_free_chunk( pobj->wavelist[cnt] );
423 pobj->wavelist[cnt] = NULL;
424 }
425
426 // release whatever textures are being used
427 release_one_profile_textures( iobj );
428
429 return btrue;
430 }
431
432 //--------------------------------------------------------------------------------------------
release_one_pro(const PRO_REF iobj)433 bool_t release_one_pro( const PRO_REF iobj )
434 {
435 pro_t * pobj;
436
437 if ( !VALID_PRO_RANGE( iobj ) ) return bfalse;
438
439 if ( !LOADED_PRO( iobj ) ) return btrue;
440 pobj = ProList.lst + iobj;
441
442 // release all of the sub-profiles
443 //release_one_ai ( pobj->iai );
444 release_one_cap( pobj->icap );
445 release_one_mad( pobj->imad );
446 //release_one_eve( pobj->ieve );
447
448 release_one_local_pips( iobj );
449
450 // release the allocated data
451 release_one_pro_data( iobj );
452
453 pro_init( pobj );
454
455 return btrue;
456 }
457
458 //--------------------------------------------------------------------------------------------
release_all_pro()459 void release_all_pro()
460 {
461 /// @details BB@> release the allocated data for all objects
462 PRO_REF cnt;
463
464 for ( cnt = 0; cnt < MAX_PROFILE; cnt++ )
465 {
466 release_one_pro( cnt );
467 }
468 }
469
470 //--------------------------------------------------------------------------------------------
release_all_pro_data()471 void release_all_pro_data()
472 {
473 /// @details BB@> release the allocated data for all objects
474 PRO_REF cnt;
475
476 for ( cnt = 0; cnt < MAX_PROFILE; cnt++ )
477 {
478 release_one_pro_data( cnt );
479 }
480 }
481
482 //--------------------------------------------------------------------------------------------
483 //--------------------------------------------------------------------------------------------
load_profile_skins_vfs(const char * tmploadname,const PRO_REF object)484 int load_profile_skins_vfs( const char * tmploadname, const PRO_REF object )
485 {
486 TX_REF min_skin_tx, min_icon_tx;
487 int max_skin, max_icon, max_tex;
488 TX_REF iskin, iicon;
489 int cnt;
490
491 STRING newloadname;
492
493 pro_t * pobj;
494
495 if ( !VALID_PRO_RANGE( object ) ) return 0;
496 pobj = ProList.lst + object;
497
498 // Load the skins and icons
499 max_skin = max_icon = -1;
500 min_skin_tx = min_icon_tx = INVALID_TX_TEXTURE;
501 for ( cnt = 0; cnt < MAX_SKIN; cnt++ )
502 {
503 snprintf( newloadname, SDL_arraysize( newloadname ), "%s/tris%d", tmploadname, cnt );
504
505 pobj->tex_ref[cnt] = TxTexture_load_one_vfs( newloadname, ( TX_REF )INVALID_TX_TEXTURE, TRANSCOLOR );
506 if ( INVALID_TX_TEXTURE != pobj->tex_ref[cnt] )
507 {
508 max_skin = cnt;
509 if ( INVALID_TX_TEXTURE == min_skin_tx )
510 {
511 min_skin_tx = pobj->tex_ref[cnt];
512 }
513 }
514
515 snprintf( newloadname, SDL_arraysize( newloadname ), "%s/icon%d", tmploadname, cnt );
516 pobj->ico_ref[cnt] = TxTexture_load_one_vfs( newloadname, ( TX_REF )INVALID_TX_TEXTURE, INVALID_KEY );
517
518 if ( INVALID_TX_TEXTURE != pobj->ico_ref[cnt] )
519 {
520 max_icon = cnt;
521
522 if ( INVALID_TX_TEXTURE == min_icon_tx )
523 {
524 min_icon_tx = pobj->ico_ref[cnt];
525 }
526
527 if ( SPELLBOOK == object )
528 {
529 if ( bookicon_count < MAX_SKIN )
530 {
531 bookicon_ref[bookicon_count] = pobj->ico_ref[cnt];
532 bookicon_count++;
533 }
534 }
535 }
536 }
537
538 if ( max_skin < 0 )
539 {
540 // If we didn't get a skin, set it to the water texture
541 max_skin = 0;
542 pobj->tex_ref[cnt] = TX_WATER_TOP;
543
544 log_debug( "Object is missing a skin (%s)!\n", tmploadname );
545 }
546
547 max_tex = MAX( max_skin, max_icon );
548
549 // fill in any missing textures
550 iskin = min_skin_tx;
551 iicon = min_icon_tx;
552 for ( cnt = 0; cnt <= max_tex; cnt++ )
553 {
554 if ( INVALID_TX_TEXTURE != pobj->tex_ref[cnt] && iskin != pobj->tex_ref[cnt] )
555 {
556 iskin = pobj->tex_ref[cnt];
557 }
558
559 if ( INVALID_TX_TEXTURE != pobj->ico_ref[cnt] && iicon != pobj->ico_ref[cnt] )
560 {
561 iicon = pobj->ico_ref[cnt];
562 }
563
564 pobj->tex_ref[cnt] = iskin;
565 pobj->ico_ref[cnt] = iicon;
566 }
567
568 return max_tex + 1;
569 }
570
571 //--------------------------------------------------------------------------------------------
get_message(vfs_FILE * fileread)572 void get_message( vfs_FILE* fileread )
573 {
574 /// @details ZZ@> This function loads a string into the message buffer, making sure it
575 /// is null terminated.
576
577 int cnt;
578 char cTmp;
579 STRING szTmp;
580
581 if ( message_buffer_carat >= MESSAGEBUFFERSIZE )
582 {
583 message_buffer_carat = MESSAGEBUFFERSIZE - 1;
584 message_buffer[message_buffer_carat] = CSTR_END;
585 return;
586 }
587
588 if ( MessageOffset.count >= MAXTOTALMESSAGE )
589 {
590 return;
591 }
592
593 MessageOffset.ary[MessageOffset.count] = message_buffer_carat;
594 fget_string( fileread, szTmp, SDL_arraysize( szTmp ) );
595 szTmp[255] = CSTR_END;
596
597 cTmp = szTmp[0];
598 cnt = 1;
599 while ( CSTR_END != cTmp && message_buffer_carat < MESSAGEBUFFERSIZE - 1 )
600 {
601 if ( '_' == cTmp ) cTmp = ' ';
602
603 message_buffer[message_buffer_carat] = cTmp;
604 message_buffer_carat++;
605 cTmp = szTmp[cnt];
606 cnt++;
607 }
608
609 message_buffer[message_buffer_carat] = CSTR_END;
610 message_buffer_carat++;
611 MessageOffset.count++;
612 }
613
614 //--------------------------------------------------------------------------------------------
load_all_messages_vfs(const char * loadname,const PRO_REF object)615 void load_all_messages_vfs( const char *loadname, const PRO_REF object )
616 {
617 /// @details ZZ@> This function loads all of an objects messages
618 vfs_FILE *fileread;
619
620 ProList.lst[object].message_start = 0;
621 fileread = vfs_openRead( loadname );
622 if ( fileread )
623 {
624 ProList.lst[object].message_start = MessageOffset.count;
625
626 while ( goto_colon( NULL, fileread, btrue ) )
627 {
628 get_message( fileread );
629 }
630
631 vfs_close( fileread );
632 }
633 }
634
635 //--------------------------------------------------------------------------------------------
release_one_local_pips(const PRO_REF iobj)636 bool_t release_one_local_pips( const PRO_REF iobj )
637 {
638 int cnt;
639 pro_t * pobj;
640
641 if ( !VALID_PRO_RANGE( iobj ) ) return bfalse;
642
643 if ( !LOADED_PRO( iobj ) ) return btrue;
644 pobj = ProList.lst + iobj;
645
646 for ( cnt = 0; cnt < MAX_PIP_PER_PROFILE; cnt++ )
647 {
648 release_one_pip( pobj->prtpip[cnt] );
649 pobj->prtpip[cnt] = ( PIP_REF ) MAX_PIP;
650 }
651
652 return btrue;
653 }
654
655 //--------------------------------------------------------------------------------------------
release_all_local_pips()656 void release_all_local_pips()
657 {
658 // clear out the local pips
659
660 PRO_REF object;
661 int cnt;
662
663 for ( object = 0; object < MAX_PROFILE; object++ )
664 {
665 pro_t * pobj;
666
667 if ( !ProList.lst[object].loaded ) continue;
668 pobj = ProList.lst + object;
669
670 for ( cnt = 0; cnt < MAX_PIP_PER_PROFILE; cnt++ )
671 {
672 release_one_pip( pobj->prtpip[cnt] );
673 pobj->prtpip[cnt] = ( PIP_REF ) MAX_PIP;
674 }
675 }
676 }
677
678 //--------------------------------------------------------------------------------------------
obj_read_slot_vfs(const char * tmploadname)679 int obj_read_slot_vfs( const char * tmploadname )
680 {
681 vfs_FILE* fileread;
682 int slot;
683 STRING szLoadName;
684
685 make_newloadname( tmploadname, "/data.txt", szLoadName );
686
687 // Open the file
688 fileread = vfs_openRead( szLoadName );
689 if ( NULL == fileread ) return -1;
690
691 // load the slot's slot no matter what
692 slot = fget_next_int( fileread );
693
694 vfs_close( fileread );
695
696 return slot;
697 }
698
699 //--------------------------------------------------------------------------------------------
obj_verify_file_vfs(const char * tmploadname)700 bool_t obj_verify_file_vfs( const char * tmploadname )
701 {
702 STRING szLoadName;
703
704 make_newloadname( tmploadname, "/data.txt", szLoadName );
705
706 // Open the file
707 return ( 0 != vfs_exists( szLoadName ) );
708 }
709
710 //--------------------------------------------------------------------------------------------
pro_get_slot_vfs(const char * tmploadname,int slot_override)711 int pro_get_slot_vfs( const char * tmploadname, int slot_override )
712 {
713 int slot;
714
715 slot = -1;
716 if ( VALID_PRO_RANGE( slot_override ) )
717 {
718 // just use the slot that was provided
719 slot = slot_override;
720 }
721
722 // grab the slot from the file
723 else
724 {
725 int tmp_slot = obj_read_slot_vfs( tmploadname );
726
727 // set the slot slot
728 if ( tmp_slot >= 0 )
729 {
730 slot = tmp_slot;
731 }
732 else if ( import_data.slot >= 0 )
733 {
734 slot = import_data.slot;
735 }
736 }
737
738 // return an error value if the file does not exist
739 if ( !obj_verify_file_vfs( tmploadname ) )
740 {
741 slot = -1;
742 }
743
744 return slot;
745 }
746
747 //--------------------------------------------------------------------------------------------
load_one_profile_vfs(const char * tmploadname,int slot_override)748 int load_one_profile_vfs( const char* tmploadname, int slot_override )
749 {
750 /// @details ZZ@> This function loads one object and returns the object slot
751
752 int cnt;
753 STRING newloadname;
754 bool_t required;
755
756 int islot; // this has to be a signed value for this function to work properly
757
758 PRO_REF iobj;
759 pro_t * pobj;
760
761 required = !VALID_CAP_RANGE( slot_override );
762
763 // get a slot value
764 islot = pro_get_slot_vfs( tmploadname, slot_override );
765
766 // throw an error code if the slot is invalid of if the file doesn't exist
767 if ( islot < 0 || islot > MAX_PROFILE )
768 {
769 // The data file wasn't found
770 if ( required )
771 {
772 log_debug( "load_one_profile_vfs() - \"%s\" was not found. Overriding a global object?\n", tmploadname );
773 }
774 else if ( VALID_CAP_RANGE( slot_override ) && slot_override > PMod->importamount * MAXIMPORTPERPLAYER )
775 {
776 log_debug( "load_one_profile_vfs() - Not able to open file \"%s\"\n", tmploadname );
777 }
778
779 return MAX_PROFILE;
780 }
781
782 // convert the slot to a profile reference
783 iobj = islot;
784
785 // throw an error code if we are trying to load over an existing profile
786 // without permission
787 if ( LOADED_PRO( iobj ) )
788 {
789 pro_t * pobj = ProList.lst + iobj;
790
791 // Make sure global objects don't load over existing models
792 if ( required && SPELLBOOK == iobj )
793 {
794 log_error( "load_one_profile_vfs() - object slot %i is a special reserved slot number (cannot be used by %s).\n", SPELLBOOK, tmploadname );
795 }
796 else if ( required && overrideslots )
797 {
798 log_error( "load_one_profile_vfs() - object slot %i used twice (%s, %s)\n", REF_TO_INT( iobj ), pobj->name, tmploadname );
799 }
800 else
801 {
802 // Stop, we don't want to override it
803 return MAX_PROFILE;
804 }
805 }
806
807 // allocate/reallocate this slot
808 iobj = ProList_get_free( iobj );
809 if ( !VALID_PRO_RANGE( iobj ) )
810 {
811 log_warning( "load_one_profile_vfs() - Cannot allocate object %d (\"%s\")\n", REF_TO_INT( iobj ), tmploadname );
812 return MAX_PROFILE;
813 }
814
815 // grab a pointer to the object
816 pobj = ProList.lst + iobj;
817
818 // load the character profile
819 pobj->icap = load_one_character_profile_vfs( tmploadname, islot, bfalse );
820 islot = REF_TO_INT( pobj->icap );
821
822 // Load the model for this iobj
823 pobj->imad = load_one_model_profile_vfs( tmploadname, ( MAD_REF )islot );
824
825 // Load the enchantment for this iobj
826 make_newloadname( tmploadname, "/enchant.txt", newloadname );
827 pobj->ieve = load_one_enchant_profile_vfs( newloadname, ( EVE_REF )islot );
828
829 // Load the AI script for this iobj
830 make_newloadname( tmploadname, "/script.txt", newloadname );
831 pobj->iai = load_ai_script_vfs( newloadname );
832
833 // Load the messages for this iobj
834 make_newloadname( tmploadname, "/message.txt", newloadname );
835 load_all_messages_vfs( newloadname, iobj );
836
837 // Load the particles for this iobj
838 for ( cnt = 0; cnt < MAX_PIP_PER_PROFILE; cnt++ )
839 {
840 snprintf( newloadname, SDL_arraysize( newloadname ), "%s/part%d.txt", tmploadname, cnt );
841
842 // Make sure it's referenced properly
843 pobj->prtpip[cnt] = load_one_particle_profile_vfs( newloadname, ( PIP_REF )MAX_PIP );
844 }
845
846 pobj->skins = load_profile_skins_vfs( tmploadname, iobj );
847
848 // Load the waves for this iobj
849 for ( cnt = 0; cnt < MAX_WAVE; cnt++ )
850 {
851 STRING szLoadName, wavename;
852
853 snprintf( wavename, SDL_arraysize( wavename ), "/sound%d", cnt );
854 make_newloadname( tmploadname, wavename, szLoadName );
855 pobj->wavelist[cnt] = sound_load_chunk_vfs( szLoadName );
856 }
857
858 // Load the random naming table for this icap
859 make_newloadname( tmploadname, "/naming.txt", newloadname );
860 pro_load_chop_vfs( iobj, newloadname );
861
862 // Fix lighting if need be
863 if ( CapStack.lst[pobj->icap].uniformlit )
864 {
865 mad_make_equally_lit_ref( pobj->imad );
866 }
867
868 // mark the profile as loaded
869 strncpy( pobj->name, tmploadname, SDL_arraysize( pobj->name ) );
870 pobj->loaded = btrue;
871
872 return islot;
873 }
874
875 //--------------------------------------------------------------------------------------------
reset_messages()876 void reset_messages()
877 {
878 /// @details ZZ@> This makes messages safe to use
879 int cnt;
880
881 MessageOffset.count = 0;
882 message_buffer_carat = 0;
883 msgtimechange = 0;
884 DisplayMsg.count = 0;
885
886 for ( cnt = 0; cnt < MAX_MESSAGE; cnt++ )
887 {
888 DisplayMsg.ary[cnt].time = 0;
889 }
890
891 for ( cnt = 0; cnt < MAXTOTALMESSAGE; cnt++ )
892 {
893 MessageOffset.ary[cnt] = 0;
894 }
895
896 message_buffer[0] = CSTR_END;
897 }
898
899 //--------------------------------------------------------------------------------------------
900 //--------------------------------------------------------------------------------------------
pro_create_chop(const PRO_REF iprofile)901 const char * pro_create_chop( const PRO_REF iprofile )
902 {
903 /// BB@> use the profile's chop to generate a name. Return "*NONE*" on a falure.
904
905 pro_t * ppro;
906 cap_t * pcap;
907 const char * szTmp;
908
909 // The name returned by the function
910 static char buffer[MAXCAPNAMESIZE] = EMPTY_CSTR;
911
912 // the default "bad" name
913 strncpy( buffer, "*NONE*", SDL_arraysize( buffer ) );
914
915 if ( !LOADED_PRO( iprofile ) ) return buffer;
916 ppro = ProList.lst + iprofile;
917
918 if ( !LOADED_CAP( ppro->icap ) ) return buffer;
919 pcap = CapStack.lst + ppro->icap;
920
921 if ( 0 == ppro->chop.section[0].size )
922 {
923 strncpy( buffer, pcap->classname, SDL_arraysize( buffer ) );
924 }
925 else
926 {
927 szTmp = chop_create( &chop_mem, &( ppro->chop ) );
928
929 if ( VALID_CSTR( szTmp ) )
930 {
931 strncpy( buffer, szTmp, SDL_arraysize( buffer ) );
932 }
933 }
934
935 return buffer;
936 }
937
938 //--------------------------------------------------------------------------------------------
pro_load_chop_vfs(const PRO_REF iprofile,const char * szLoadname)939 bool_t pro_load_chop_vfs( const PRO_REF iprofile, const char *szLoadname )
940 {
941 /// BB@> load the chop for the given profile
942 pro_t * ppro;
943
944 if ( !VALID_PRO_RANGE( iprofile ) ) return bfalse;
945 ppro = ProList.lst + iprofile;
946
947 // clear out any current definition
948 chop_definition_init( &( ppro->chop ) );
949
950 return chop_load_vfs( &chop_mem, szLoadname, &( ppro->chop ) );
951 }
952
953 //--------------------------------------------------------------------------------------------
954 //--------------------------------------------------------------------------------------------
chop_definition_init(chop_definition_t * pdefinition)955 chop_definition_t * chop_definition_init( chop_definition_t * pdefinition )
956 {
957 int cnt;
958
959 if ( NULL == pdefinition ) return pdefinition;
960
961 for ( cnt = 0; cnt < MAXSECTION; cnt++ )
962 {
963 pdefinition->section[cnt].start = MAXCHOP;
964 pdefinition->section[cnt].size = 0;
965 }
966
967 return pdefinition;
968 }
969
970 //--------------------------------------------------------------------------------------------
chop_data_init(chop_data_t * pdata)971 chop_data_t * chop_data_init( chop_data_t * pdata )
972 {
973 /// @details ZZ@> This function prepares the name chopper for use
974 /// BB@> It may actually be useful to blank the chop buffer
975
976 if ( NULL == pdata ) return pdata;
977
978 pdata->chop_count = 0;
979 pdata->carat = 0;
980
981 return pdata;
982 }
983
984 //--------------------------------------------------------------------------------------------
chop_create(chop_data_t * pdata,chop_definition_t * pdefinition)985 const char * chop_create( chop_data_t * pdata, chop_definition_t * pdefinition )
986 {
987 /// @details ZZ@> This function generates a random name. Return "Blah" on a falure.
988
989 int read, write, section, mychop;
990 char cTmp;
991
992 // The name returned by the function
993 static char buffer[MAXCAPNAMESIZE] = EMPTY_CSTR;
994
995 strncpy( buffer, "Blah", SDL_arraysize( buffer ) );
996
997 if ( NULL == pdata || NULL == pdefinition ) return buffer;
998
999 write = 0;
1000 for ( section = 0; section < MAXSECTION; section++ )
1001 {
1002 if ( 0 != pdefinition->section[section].size )
1003 {
1004 int irand = RANDIE;
1005
1006 mychop = pdefinition->section[section].start + ( irand % pdefinition->section[section].size );
1007
1008 if ( mychop < MAXCHOP )
1009 {
1010 read = pdata->start[mychop];
1011 cTmp = pdata->buffer[read];
1012 while ( CSTR_END != cTmp && write < MAXCAPNAMESIZE - 1 )
1013 {
1014 buffer[write] = cTmp;
1015 write++;
1016 read++;
1017 cTmp = pdata->buffer[read];
1018 }
1019 buffer[write] = CSTR_END;
1020 }
1021 }
1022 }
1023 if ( write >= MAXCAPNAMESIZE ) write = MAXCAPNAMESIZE - 1;
1024
1025 buffer[write] = CSTR_END;
1026
1027 return buffer;
1028 }
1029
1030 //--------------------------------------------------------------------------------------------
chop_load_vfs(chop_data_t * pdata,const char * szLoadname,chop_definition_t * pdefinition)1031 bool_t chop_load_vfs( chop_data_t * pdata, const char *szLoadname, chop_definition_t * pdefinition )
1032 {
1033 /// @details ZZ@> This function reads a naming.txt file into the chop data buffer and sets the
1034 /// values of a chop definition
1035
1036 int which_section, section_count;
1037 STRING tmp_buffer = EMPTY_CSTR;
1038 vfs_FILE *fileread;
1039
1040 chop_definition_t local_definition;
1041
1042 if ( NULL == pdata || pdata->carat >= CHOPDATACHUNK ) return bfalse;
1043
1044 fileread = vfs_openRead( szLoadname );
1045 if ( NULL == fileread ) return bfalse;
1046
1047 // in case we get a stupid value.
1048 // we could create a dynamically allocated struct in this case...
1049 if ( NULL == pdefinition ) pdefinition = &local_definition;
1050
1051 // clear out any old definition
1052 chop_definition_init( pdefinition );
1053
1054 which_section = 0;
1055 section_count = 0;
1056 while ( which_section < MAXSECTION && pdata->carat < CHOPDATACHUNK && goto_colon( NULL, fileread, btrue ) )
1057 {
1058 fget_string( fileread, tmp_buffer, SDL_arraysize( tmp_buffer ) );
1059
1060 // convert all the '_' and junk in the string
1061 str_decode( tmp_buffer, SDL_arraysize( tmp_buffer ), tmp_buffer );
1062
1063 if ( 0 == strcmp( tmp_buffer, "STOP" ) )
1064 {
1065 if ( which_section < MAXSECTION )
1066 {
1067 int itmp;
1068 pdefinition->section[which_section].size = section_count;
1069 itmp = ( int )pdata->chop_count - ( int )section_count;
1070 pdefinition->section[which_section].start = MAX( 0, itmp );
1071 }
1072
1073 which_section++;
1074 section_count = 0;
1075 tmp_buffer[0] = CSTR_END;
1076 }
1077 else
1078 {
1079 int chop_len;
1080
1081 // fill in the chop data
1082 pdata->start[pdata->chop_count] = pdata->carat;
1083 chop_len = snprintf( pdata->buffer + pdata->carat, CHOPDATACHUNK - pdata->carat - 1, "%s", tmp_buffer );
1084
1085 pdata->carat += chop_len + 1;
1086 pdata->chop_count++;
1087 section_count++;
1088 tmp_buffer[0] = CSTR_END;
1089 }
1090 }
1091
1092 // handle the case where the chop buffer has overflowed
1093 // pretend the last command was "STOP"
1094 if ( CSTR_END != tmp_buffer[0] && which_section < MAXSECTION )
1095 {
1096 int itmp;
1097 pdefinition->section[which_section].size = section_count;
1098 itmp = ( int )pdata->chop_count - ( int )section_count;
1099 pdefinition->section[which_section].start = MAX( 0, itmp );
1100 }
1101
1102 vfs_close( fileread );
1103
1104 return section_count > 0;
1105 }
1106
1107 //--------------------------------------------------------------------------------------------
chop_export_vfs(const char * szSaveName,const char * szChop)1108 bool_t chop_export_vfs( const char *szSaveName, const char * szChop )
1109 {
1110 /// @details ZZ@> This function exports a simple string to the naming.txt file
1111
1112 vfs_FILE* filewrite;
1113 char cTmp;
1114 int cnt, tnc;
1115
1116 if ( !VALID_CSTR( szChop ) ) return bfalse;
1117
1118 // Can it export?
1119 filewrite = vfs_openWrite( szSaveName );
1120 if ( NULL == filewrite ) return bfalse;
1121
1122 cnt = 0;
1123 cTmp = szChop[0];
1124 cnt++;
1125 while ( cnt < MAXCAPNAMESIZE && CSTR_END != cTmp )
1126 {
1127 vfs_printf( filewrite, ":" );
1128
1129 for ( tnc = 0; tnc < 8 && cTmp != 0; tnc++ )
1130 {
1131 if ( ' ' == cTmp )
1132 {
1133 vfs_printf( filewrite, "_" );
1134 }
1135 else
1136 {
1137 vfs_printf( filewrite, "%c", cTmp );
1138 }
1139
1140 cTmp = szChop[cnt];
1141 cnt++;
1142 }
1143
1144 vfs_printf( filewrite, "\n" );
1145 vfs_printf( filewrite, ":STOP\n\n" );
1146 }
1147
1148 vfs_close( filewrite );
1149
1150 return btrue;
1151 }
1152