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 enchant.c
21 /// @brief handles enchantments attached to objects
22 /// @details
23 
24 #include "enchant.inl"
25 
26 #include "char.inl"
27 #include "mad.h"
28 #include "particle.inl"
29 #include "profile.inl"
30 
31 #include "sound.h"
32 #include "camera.h"
33 #include "game.h"
34 #include "script_functions.h"
35 #include "log.h"
36 
37 #include "egoboo_fileutil.h"
38 #include "egoboo.h"
39 
40 //--------------------------------------------------------------------------------------------
41 //--------------------------------------------------------------------------------------------
42 INSTANTIATE_STACK( ACCESS_TYPE_NONE, eve_t, EveStack, MAX_EVE );
43 
44 //--------------------------------------------------------------------------------------------
45 //--------------------------------------------------------------------------------------------
46 static bool_t  enc_free( enc_t * penc );
47 
48 static enc_t * enc_config_ctor( enc_t * penc );
49 static enc_t * enc_config_init( enc_t * penc );
50 static enc_t * enc_config_deinit( enc_t * penc );
51 static enc_t * enc_config_active( enc_t * penc );
52 static enc_t * enc_config_dtor( enc_t * penc );
53 
54 //--------------------------------------------------------------------------------------------
55 //--------------------------------------------------------------------------------------------
enchant_system_begin()56 void enchant_system_begin()
57 {
58     EncList_init();
59     init_all_eve();
60 }
61 
62 //--------------------------------------------------------------------------------------------
enchant_system_end()63 void enchant_system_end()
64 {
65     release_all_eve();
66     EncList_dtor();
67 }
68 
69 //--------------------------------------------------------------------------------------------
70 //--------------------------------------------------------------------------------------------
enc_free(enc_t * penc)71 bool_t  enc_free( enc_t * penc )
72 {
73     if ( !ALLOCATED_PENC( penc ) ) return bfalse;
74 
75     // nothing to do yet
76 
77     return btrue;
78 }
79 
80 //--------------------------------------------------------------------------------------------
enc_ctor(enc_t * penc)81 enc_t * enc_ctor( enc_t * penc )
82 {
83     obj_data_t save_base;
84     obj_data_t * pbase;
85 
86     // grab the base object
87     if ( NULL == penc ) return NULL;
88     pbase = POBJ_GET_PBASE( penc );
89 
90     memcpy( &save_base, pbase, sizeof( obj_data_t ) );
91 
92     memset( penc, 0, sizeof( *penc ) );
93 
94     // restore the base object data
95     memcpy( pbase, &save_base, sizeof( obj_data_t ) );
96 
97     // reset the base counters
98     pbase->update_count = 0;
99     pbase->frame_count = 0;
100 
101     penc->profile_ref      = ( PRO_REF )MAX_PROFILE;
102     penc->eve_ref          = ( EVE_REF )MAX_EVE;
103 
104     penc->target_ref       = ( CHR_REF )MAX_CHR;
105     penc->owner_ref        = ( CHR_REF )MAX_CHR;
106     penc->spawner_ref      = ( CHR_REF )MAX_CHR;
107     penc->spawnermodel_ref = ( PRO_REF )MAX_PROFILE;
108     penc->overlay_ref      = ( CHR_REF )MAX_CHR;
109 
110     penc->nextenchant_ref  = ( ENC_REF )MAX_ENC;
111 
112     // we are done constructing. move on to initializing.
113     pbase->state = ego_object_initializing;
114 
115     return penc;
116 }
117 
118 //--------------------------------------------------------------------------------------------
enc_dtor(enc_t * penc)119 enc_t * enc_dtor( enc_t * penc )
120 {
121     if ( NULL == penc ) return penc;
122 
123     // destroy the object
124     enc_free( penc );
125 
126     // Destroy the base object.
127     // Sets the state to ego_object_terminated automatically.
128     POBJ_TERMINATE( penc );
129 
130     return penc;
131 }
132 
133 //--------------------------------------------------------------------------------------------
134 //--------------------------------------------------------------------------------------------
unlink_enchant(const ENC_REF ienc,ENC_REF * enc_parent)135 bool_t unlink_enchant( const ENC_REF ienc, ENC_REF * enc_parent )
136 {
137     enc_t * penc;
138 
139     if ( !ALLOCATED_ENC( ienc ) ) return bfalse;
140     penc = EncList.lst + ienc;
141 
142     // Unlink it from the spawner (if possible)
143     if ( ALLOCATED_CHR( penc->spawner_ref ) )
144     {
145         chr_t * pspawner = ChrList.lst + penc->spawner_ref;
146 
147         if ( ienc == pspawner->undoenchant )
148         {
149             pspawner->undoenchant = ( ENC_REF ) MAX_ENC;
150         }
151     }
152 
153     // find the parent reference for the enchant
154     if ( NULL == enc_parent && ALLOCATED_CHR( penc->target_ref ) )
155     {
156         ENC_REF ienc_last, ienc_now, ienc_nxt;
157         size_t ienc_count;
158 
159         chr_t * ptarget;
160 
161         ptarget = ChrList.lst + penc->target_ref;
162 
163         if ( ptarget->firstenchant == ienc )
164         {
165             // It was the first in the list
166             enc_parent = &( ptarget->firstenchant );
167         }
168         else
169         {
170             // Search until we find it
171             ienc_last = ienc_now = ptarget->firstenchant;
172             ienc_count = 0;
173             while (( MAX_ENC != ienc_now ) && ( ienc_count < MAX_ENC ) )
174             {
175                 ienc_last = ienc_now;
176                 ienc_nxt  = EncList.lst[ienc_now].nextenchant_ref;
177 
178                 if ( ienc_now == ienc ) break;
179 
180                 ienc_now  = ienc_nxt;
181                 ienc_count++;
182             }
183             if ( ienc_count >= MAX_ENC ) log_error( "%s - bad enchant loop\n", __FUNCTION__ );
184 
185             // Relink the last enchantment
186             if ( ienc_now == ienc )
187             {
188                 enc_parent = &( EncList.lst[ienc_last].nextenchant_ref );
189             }
190         }
191     }
192 
193     // unlink the enchant from the parent reference
194     if ( NULL != enc_parent )
195     {
196         *enc_parent = EncList.lst[ienc].nextenchant_ref;
197     }
198 
199     return NULL != enc_parent;
200 }
201 
202 //--------------------------------------------------------------------------------------------
remove_all_enchants_with_idsz(CHR_REF ichr,IDSZ remove_idsz)203 bool_t remove_all_enchants_with_idsz( CHR_REF ichr, IDSZ remove_idsz )
204 {
205     /// @details ZF@> This function removes all enchants with the character that has the specified
206     ///               IDSZ. If idsz [NONE] is specified, all enchants will be removed. Return btrue
207     ///               if at least one enchant was removed.
208 
209     ENC_REF ienc_now, ienc_nxt;
210     size_t  ienc_count;
211 
212     eve_t * peve;
213     bool_t retval = bfalse;
214     chr_t *pchr;
215 
216     // Stop invalid pointers
217     if ( !ACTIVE_CHR( ichr ) ) return bfalse;
218     pchr = ChrList.lst + ichr;
219 
220     // clean up the enchant list before doing anything
221     cleanup_character_enchants( pchr );
222 
223     // Check all enchants to see if they are removed
224     ienc_now = pchr->firstenchant;
225     ienc_count = 0;
226     while (( MAX_ENC != ienc_now ) && ( ienc_count < MAX_ENC ) )
227     {
228         ienc_nxt  = EncList.lst[ienc_now].nextenchant_ref;
229 
230         peve = enc_get_peve( ienc_now );
231         if ( NULL != peve && ( IDSZ_NONE == remove_idsz || remove_idsz == peve->removedbyidsz ) )
232         {
233             remove_enchant( ienc_now, NULL );
234             retval = btrue;
235         }
236 
237         ienc_now = ienc_nxt;
238         ienc_count++;
239     }
240     if ( ienc_count >= MAX_ENC ) log_error( "%s - bad enchant loop\n", __FUNCTION__ );
241 
242     return retval;
243 }
244 
245 //--------------------------------------------------------------------------------------------
remove_enchant(const ENC_REF ienc,ENC_REF * enc_parent)246 bool_t remove_enchant( const ENC_REF ienc, ENC_REF * enc_parent )
247 {
248     /// @details ZZ@> This function removes a specific enchantment and adds it to the unused list
249 
250     int     iwave;
251     CHR_REF overlay_ref;
252     int add_type, set_type;
253 
254     enc_t * penc;
255     eve_t * peve;
256     CHR_REF itarget, ispawner;
257 
258     if ( !ALLOCATED_ENC( ienc ) ) return bfalse;
259     penc = EncList.lst + ienc;
260 
261     itarget  = penc->target_ref;
262     ispawner = penc->spawner_ref;
263     peve     = enc_get_peve( ienc );
264 
265     // Unsparkle the spellbook
266     if ( INGAME_CHR( ispawner ) )
267     {
268         chr_t * pspawner = ChrList.lst + ispawner;
269 
270         pspawner->sparkle = NOSPARKLE;
271 
272         // Make the spawner unable to undo the enchantment
273         if ( pspawner->undoenchant == ienc )
274         {
275             pspawner->undoenchant = ( ENC_REF ) MAX_ENC;
276         }
277     }
278 
279     //---- Remove all the enchant stuff in exactly the opposite order to how it was applied
280 
281     // Remove all of the cumulative values first, since we did it
282     for ( add_type = ENC_ADD_LAST; add_type >= ENC_ADD_FIRST; add_type-- )
283     {
284         enchant_remove_add( ienc, add_type );
285     }
286 
287     // unset them in the reverse order of setting them, doing morph last
288     for ( set_type = ENC_SET_LAST; set_type >= ENC_SET_FIRST; set_type-- )
289     {
290         enchant_remove_set( ienc, set_type );
291     }
292 
293     // Now fix dem weapons
294     if ( INGAME_CHR( itarget ) )
295     {
296         chr_t * ptarget = ChrList.lst + itarget;
297         reset_character_alpha( ptarget->holdingwhich[SLOT_LEFT] );
298         reset_character_alpha( ptarget->holdingwhich[SLOT_RIGHT] );
299     }
300 
301     // unlink this enchant from its parent
302     unlink_enchant( ienc, enc_parent );
303 
304     // Kill overlay too...
305     overlay_ref = penc->overlay_ref;
306     if ( INGAME_CHR( overlay_ref ) )
307     {
308         chr_t * povl = ChrList.lst + overlay_ref;
309 
310         if ( povl->invictus )
311         {
312             chr_get_pteam_base( overlay_ref )->morale++;
313         }
314 
315         kill_character( overlay_ref, ( CHR_REF )MAX_CHR, btrue );
316     }
317 
318     // nothing above this demends on having a valid enchant profile
319     if ( NULL != peve )
320     {
321         // Play the end sound
322         iwave = peve->endsound_index;
323         if ( VALID_SND( iwave ) )
324         {
325             PRO_REF imodel = penc->spawnermodel_ref;
326             if ( LOADED_PRO( imodel ) )
327             {
328                 if ( INGAME_CHR( itarget ) )
329                 {
330                     sound_play_chunk( ChrList.lst[itarget].pos_old, pro_get_chunk( imodel, iwave ) );
331                 }
332                 else
333                 {
334                     sound_play_chunk_full( pro_get_chunk( imodel, iwave ) );
335                 }
336             }
337         }
338 
339         // See if we spit out an end message
340         if ( peve->endmessage >= 0 )
341         {
342             _display_message( penc->target_ref, penc->profile_ref, peve->endmessage, NULL );
343         }
344 
345         // Check to see if we spawn a poof
346         if ( peve->poofonend )
347         {
348             spawn_poof( penc->target_ref, penc->profile_ref );
349         }
350 
351         //Remove special skills gained by the enchant
352         if ( INGAME_CHR( itarget ) )
353         {
354             chr_t * ptarget = ChrList.lst + penc->target_ref;
355 
356             //Reset see kurses
357             if ( 0 != peve->seekurse )
358             {
359                 ptarget->see_kurse_level = chr_get_skill( ptarget, MAKE_IDSZ( 'C', 'K', 'U', 'R' ) );
360             }
361 
362             //Reset darkvision
363             if ( 0 != peve->darkvision )
364             {
365                 ptarget->darkvision_level = chr_get_skill( ptarget, MAKE_IDSZ( 'D', 'A', 'R', 'K' ) );
366             }
367         }
368     }
369 
370     EncList_free_one( ienc );
371 
372     // save this until the enchant is completely dead, since kill character can generate a
373     // recursive call to this function through cleanup_one_character()
374     // @note all of the values in the penc are now invalid. we have to use previously evaluated
375     // values of itarget and penc to kill the target (if necessary)
376     if ( INGAME_CHR( itarget ) && NULL != peve && peve->killtargetonend )
377     {
378         chr_t * ptarget = ChrList.lst + itarget;
379         if ( ptarget->invictus )  chr_get_pteam_base( itarget )->morale++;
380 
381         kill_character( itarget, ( CHR_REF )MAX_CHR, btrue );
382     }
383 
384     return btrue;
385 }
386 
387 //--------------------------------------------------------------------------------------------
enchant_value_filled(const ENC_REF ienc,int value_idx)388 ENC_REF enchant_value_filled( const ENC_REF  ienc, int value_idx )
389 {
390     /// @details ZZ@> This function returns MAX_ENC if the enchantment's target has no conflicting
391     ///    set values in its other enchantments.  Otherwise it returns the ienc
392     ///    of the conflicting enchantment
393 
394     CHR_REF character;
395     chr_t * pchr;
396 
397     ENC_REF ienc_now, ienc_nxt;
398     size_t  ienc_count;
399 
400     if ( value_idx < 0 || value_idx >= MAX_ENCHANT_SET ) return ( ENC_REF )MAX_ENC;
401 
402     if ( !INGAME_ENC( ienc ) ) return ( ENC_REF )MAX_ENC;
403 
404     character = EncList.lst[ienc].target_ref;
405     if ( !INGAME_CHR( character ) ) return ( ENC_REF )MAX_ENC;
406     pchr = ChrList.lst + character;
407 
408     // cleanup the enchant list
409     cleanup_character_enchants( pchr );
410 
411     // scan the enchant list
412     ienc_now = pchr->firstenchant;
413     ienc_count = 0;
414     while (( MAX_ENC != ienc_now ) && ( ienc_count < MAX_ENC ) )
415     {
416         ienc_nxt = EncList.lst[ienc_now].nextenchant_ref;
417 
418         if ( INGAME_ENC( ienc_now ) && EncList.lst[ienc_now].setyesno[value_idx] )
419         {
420             break;
421         }
422 
423         ienc_now = ienc_nxt;
424         ienc_count++;
425     }
426     if ( ienc_count >= MAX_ENC ) log_error( "%s - bad enchant loop\n", __FUNCTION__ );
427 
428     return ienc_now;
429 }
430 
431 //--------------------------------------------------------------------------------------------
enchant_apply_set(const ENC_REF ienc,int value_idx,const PRO_REF profile)432 void enchant_apply_set( const ENC_REF  ienc, int value_idx, const PRO_REF profile )
433 {
434     /// @details ZZ@> This function sets and saves one of the character's stats
435 
436     ENC_REF conflict;
437     CHR_REF character;
438     enc_t * penc;
439     eve_t * peve;
440     chr_t * ptarget;
441 
442     if ( value_idx < 0 || value_idx >= MAX_ENCHANT_SET ) return;
443 
444     if ( !DEFINED_ENC( ienc ) ) return;
445     penc = EncList.lst + ienc;
446 
447     peve = pro_get_peve( profile );
448     if ( NULL == peve ) return;
449 
450     penc->setyesno[value_idx] = bfalse;
451     if ( peve->setyesno[value_idx] )
452     {
453         conflict = enchant_value_filled( ienc, value_idx );
454         if ( peve->override || MAX_ENC == conflict )
455         {
456             // Check for multiple enchantments
457             if ( DEFINED_ENC( conflict ) )
458             {
459                 // Multiple enchantments aren't allowed for sets
460                 if ( peve->remove_overridden )
461                 {
462                     // Kill the old enchantment
463                     remove_enchant( conflict, NULL );
464                 }
465                 else
466                 {
467                     // Just unset the old enchantment's value
468                     enchant_remove_set( conflict, value_idx );
469                 }
470             }
471 
472             // Set the value, and save the character's real stat
473             if ( DEFINED_CHR( penc->target_ref ) )
474             {
475                 character = penc->target_ref;
476                 ptarget = ChrList.lst + character;
477 
478                 penc->setyesno[value_idx] = btrue;
479 
480                 switch ( value_idx )
481                 {
482                     case SETDAMAGETYPE:
483                         penc->setsave[value_idx]  = ptarget->damagetarget_damagetype;
484                         ptarget->damagetarget_damagetype = peve->setvalue[value_idx];
485                         break;
486 
487                     case SETNUMBEROFJUMPS:
488                         penc->setsave[value_idx] = ptarget->jumpnumberreset;
489                         ptarget->jumpnumberreset = peve->setvalue[value_idx];
490                         break;
491 
492                     case SETLIFEBARCOLOR:
493                         penc->setsave[value_idx] = ptarget->lifecolor;
494                         ptarget->lifecolor       = peve->setvalue[value_idx];
495                         break;
496 
497                     case SETMANABARCOLOR:
498                         penc->setsave[value_idx] = ptarget->manacolor;
499                         ptarget->manacolor       = peve->setvalue[value_idx];
500                         break;
501 
502                     case SETSLASHMODIFIER:
503                         penc->setsave[value_idx]              = ptarget->damage_modifier[DAMAGE_SLASH];
504                         ptarget->damage_modifier[DAMAGE_SLASH] = peve->setvalue[value_idx];
505                         break;
506 
507                     case SETCRUSHMODIFIER:
508                         penc->setsave[value_idx]              = ptarget->damage_modifier[DAMAGE_CRUSH];
509                         ptarget->damage_modifier[DAMAGE_CRUSH] = peve->setvalue[value_idx];
510                         break;
511 
512                     case SETPOKEMODIFIER:
513                         penc->setsave[value_idx]             = ptarget->damage_modifier[DAMAGE_POKE];
514                         ptarget->damage_modifier[DAMAGE_POKE] = peve->setvalue[value_idx];
515                         break;
516 
517                     case SETHOLYMODIFIER:
518                         penc->setsave[value_idx]             = ptarget->damage_modifier[DAMAGE_HOLY];
519                         ptarget->damage_modifier[DAMAGE_HOLY] = peve->setvalue[value_idx];
520                         break;
521 
522                     case SETEVILMODIFIER:
523                         penc->setsave[value_idx]             = ptarget->damage_modifier[DAMAGE_EVIL];
524                         ptarget->damage_modifier[DAMAGE_EVIL] = peve->setvalue[value_idx];
525                         break;
526 
527                     case SETFIREMODIFIER:
528                         penc->setsave[value_idx]             = ptarget->damage_modifier[DAMAGE_FIRE];
529                         ptarget->damage_modifier[DAMAGE_FIRE] = peve->setvalue[value_idx];
530                         break;
531 
532                     case SETICEMODIFIER:
533                         penc->setsave[value_idx]            = ptarget->damage_modifier[DAMAGE_ICE];
534                         ptarget->damage_modifier[DAMAGE_ICE] = peve->setvalue[value_idx];
535                         break;
536 
537                     case SETZAPMODIFIER:
538                         penc->setsave[value_idx]            = ptarget->damage_modifier[DAMAGE_ZAP];
539                         ptarget->damage_modifier[DAMAGE_ZAP] = peve->setvalue[value_idx];
540                         break;
541 
542                     case SETFLASHINGAND:
543                         penc->setsave[value_idx] = ptarget->flashand;
544                         ptarget->flashand        = peve->setvalue[value_idx];
545                         break;
546 
547                     case SETLIGHTBLEND:
548                         penc->setsave[value_idx] = ptarget->inst.light;
549                         chr_set_light( ptarget, peve->setvalue[value_idx] );
550                         break;
551 
552                     case SETALPHABLEND:
553                         penc->setsave[value_idx] = ptarget->inst.alpha;
554                         chr_set_alpha( ptarget, peve->setvalue[value_idx] );
555                         break;
556 
557                     case SETSHEEN:
558                         penc->setsave[value_idx] = ptarget->inst.sheen;
559                         chr_set_sheen( ptarget, peve->setvalue[value_idx] );
560                         break;
561 
562                     case SETFLYTOHEIGHT:
563                         penc->setsave[value_idx] = ptarget->flyheight;
564                         if ( 0 == ptarget->flyheight && ptarget->pos.z > -2 )
565                         {
566                             ptarget->flyheight = peve->setvalue[value_idx];
567                         }
568                         break;
569 
570                     case SETWALKONWATER:
571                         penc->setsave[value_idx] = ptarget->waterwalk;
572                         if ( !ptarget->waterwalk )
573                         {
574                             ptarget->waterwalk = ( 0 != peve->setvalue[value_idx] );
575                         }
576                         break;
577 
578                     case SETCANSEEINVISIBLE:
579                         penc->setsave[value_idx]     = ptarget->see_invisible_level > 0;
580                         ptarget->see_invisible_level = peve->setvalue[value_idx];
581                         break;
582 
583                     case SETMISSILETREATMENT:
584                         penc->setsave[value_idx]  = ptarget->missiletreatment;
585                         ptarget->missiletreatment = peve->setvalue[value_idx];
586                         break;
587 
588                     case SETCOSTFOREACHMISSILE:
589                         penc->setsave[value_idx] = ptarget->missilecost;
590                         ptarget->missilecost     = peve->setvalue[value_idx] * 16.0f;    // adjustment to the value stored in the file
591                         ptarget->missilehandler  = penc->owner_ref;
592                         break;
593 
594                     case SETMORPH:
595                         // Special handler for morph
596                         penc->setsave[value_idx] = ptarget->skin;
597                         change_character( character, profile, 0, ENC_LEAVE_ALL ); // ENC_LEAVE_FIRST);
598                         break;
599 
600                     case SETCHANNEL:
601                         penc->setsave[value_idx] = ptarget->canchannel;
602                         ptarget->canchannel      = ( 0 != peve->setvalue[value_idx] );
603                         break;
604                 }
605             }
606         }
607     }
608 }
609 
610 //--------------------------------------------------------------------------------------------
enchant_apply_add(const ENC_REF ienc,int value_idx,const EVE_REF ieve)611 void enchant_apply_add( const ENC_REF ienc, int value_idx, const EVE_REF ieve )
612 {
613     /// @details ZZ@> This function does cumulative modification to character stats
614 
615     int valuetoadd, newvalue;
616     float fvaluetoadd, fnewvalue;
617     CHR_REF character;
618     enc_t * penc;
619     eve_t * peve;
620     chr_t * ptarget;
621 
622     if ( value_idx < 0 || value_idx >= MAX_ENCHANT_ADD ) return;
623 
624     if ( !DEFINED_ENC( ienc ) ) return;
625     penc = EncList.lst + ienc;
626 
627     if ( ieve >= MAX_EVE || !EveStack.lst[ieve].loaded ) return;
628     peve = EveStack.lst + ieve;
629 
630     if ( !peve->addyesno[value_idx] )
631     {
632         penc->addyesno[value_idx] = bfalse;
633         penc->addsave[value_idx]  = 0.0f;
634         return;
635     }
636 
637     if ( !DEFINED_CHR( penc->target_ref ) ) return;
638     character = penc->target_ref;
639     ptarget = ChrList.lst + character;
640 
641     valuetoadd  = 0;
642     fvaluetoadd = 0.0f;
643     switch ( value_idx )
644     {
645         case ADDJUMPPOWER:
646             fnewvalue = ptarget->jump_power;
647             fvaluetoadd = peve->addvalue[value_idx];
648             fgetadd( 0.0f, fnewvalue, 30.0f, &fvaluetoadd );
649             ptarget->jump_power += fvaluetoadd;
650             break;
651 
652         case ADDBUMPDAMPEN:
653             fnewvalue = ptarget->phys.bumpdampen;
654             fvaluetoadd = peve->addvalue[value_idx];
655             fgetadd( 0.0f, fnewvalue, 1.0f, &fvaluetoadd );
656             ptarget->phys.bumpdampen += fvaluetoadd;
657             break;
658 
659         case ADDBOUNCINESS:
660             fnewvalue = ptarget->phys.dampen;
661             fvaluetoadd = peve->addvalue[value_idx];
662             fgetadd( 0.0f, fnewvalue, 0.95f, &fvaluetoadd );
663             ptarget->phys.dampen += fvaluetoadd;
664             break;
665 
666         case ADDDAMAGE:
667             newvalue = ptarget->damage_boost;
668             valuetoadd = peve->addvalue[value_idx];
669             getadd( 0, newvalue, 4096, &valuetoadd );
670             ptarget->damage_boost += valuetoadd;
671             fvaluetoadd = valuetoadd;
672             break;
673 
674         case ADDSIZE:
675             fnewvalue = ptarget->fat_goto;
676             fvaluetoadd = peve->addvalue[value_idx];
677             fgetadd( 0.5f, fnewvalue, 2.0f, &fvaluetoadd );
678             ptarget->fat_goto += fvaluetoadd;
679             ptarget->fat_goto_time = SIZETIME;
680             break;
681 
682         case ADDACCEL:
683             fnewvalue = ptarget->maxaccel_reset;
684             fvaluetoadd = peve->addvalue[value_idx];
685             fgetadd( 0.0f, fnewvalue, 1.50f, &fvaluetoadd );
686             chr_set_maxaccel( ptarget, ptarget->maxaccel_reset + fvaluetoadd );
687             break;
688 
689         case ADDRED:
690             newvalue = ptarget->inst.redshift;
691             valuetoadd = peve->addvalue[value_idx];
692             getadd( 0, newvalue, 6, &valuetoadd );
693             chr_set_redshift( ptarget, ptarget->inst.redshift + valuetoadd );
694             fvaluetoadd = valuetoadd;
695             break;
696 
697         case ADDGRN:
698             newvalue = ptarget->inst.grnshift;
699             valuetoadd = peve->addvalue[value_idx];
700             getadd( 0, newvalue, 6, &valuetoadd );
701             chr_set_grnshift( ptarget, ptarget->inst.grnshift + valuetoadd );
702             fvaluetoadd = valuetoadd;
703             break;
704 
705         case ADDBLU:
706             newvalue = ptarget->inst.blushift;
707             valuetoadd = peve->addvalue[value_idx];
708             getadd( 0, newvalue, 6, &valuetoadd );
709             chr_set_blushift( ptarget, ptarget->inst.blushift + valuetoadd );
710             fvaluetoadd = valuetoadd;
711             break;
712 
713         case ADDDEFENSE:
714             newvalue = ptarget->defense;
715             valuetoadd = peve->addvalue[value_idx];
716             getadd( 55, newvalue, 255, &valuetoadd );  // Don't fix again!  //ZF> why limit min to 55?
717             ptarget->defense += valuetoadd;
718             fvaluetoadd = valuetoadd;
719             break;
720 
721         case ADDMANA:
722             newvalue = ptarget->manamax;
723             valuetoadd = peve->addvalue[value_idx];
724             getadd( 0, newvalue, PERFECTBIG, &valuetoadd );
725             ptarget->manamax += valuetoadd;
726             //ptarget->mana    += valuetoadd;                       //ZF> bit of a problem here, we dont want players to heal or lose life by requipping magic ornaments
727             ptarget->mana = CLIP( ptarget->mana, 0, ptarget->manamax );
728             fvaluetoadd = valuetoadd;
729             break;
730 
731         case ADDLIFE:
732             newvalue = ptarget->lifemax;
733             valuetoadd = peve->addvalue[value_idx];
734             getadd( LOWSTAT, newvalue, PERFECTBIG, &valuetoadd );
735             ptarget->lifemax += valuetoadd;
736             //ptarget->life += valuetoadd;                        //ZF> bit of a problem here, we dont want players to heal or lose life by requipping magic ornaments
737             ptarget->life = CLIP( ptarget->life, 1, ptarget->lifemax );
738             fvaluetoadd = valuetoadd;
739             break;
740 
741         case ADDSTRENGTH:
742             newvalue = ptarget->strength;
743             valuetoadd = peve->addvalue[value_idx];
744             getadd( 0, newvalue, HIGHSTAT, &valuetoadd );
745             ptarget->strength += valuetoadd;
746             fvaluetoadd = valuetoadd;
747             break;
748 
749         case ADDWISDOM:
750             newvalue = ptarget->wisdom;
751             valuetoadd = peve->addvalue[value_idx];
752             getadd( 0, newvalue, HIGHSTAT, &valuetoadd );
753             ptarget->wisdom += valuetoadd;
754             fvaluetoadd = valuetoadd;
755             break;
756 
757         case ADDINTELLIGENCE:
758             newvalue = ptarget->intelligence;
759             valuetoadd = peve->addvalue[value_idx];
760             getadd( 0, newvalue, HIGHSTAT, &valuetoadd );
761             ptarget->intelligence += valuetoadd;
762             fvaluetoadd = valuetoadd;
763             break;
764 
765         case ADDDEXTERITY:
766             newvalue = ptarget->dexterity;
767             valuetoadd = peve->addvalue[value_idx];
768             getadd( 0, newvalue, HIGHSTAT, &valuetoadd );
769             ptarget->dexterity += valuetoadd;
770             fvaluetoadd = valuetoadd;
771             break;
772     }
773 
774     // save whether there was any change in the value
775     penc->addyesno[value_idx] = ( 0.0f != fvaluetoadd );
776 
777     // Save the value for undo
778     penc->addsave[value_idx]  = fvaluetoadd;
779 }
780 
781 //--------------------------------------------------------------------------------------------
782 //--------------------------------------------------------------------------------------------
enc_config_do_init(enc_t * penc)783 enc_t * enc_config_do_init( enc_t * penc )
784 {
785     enc_spawn_data_t * pdata;
786     ENC_REF ienc;
787     CHR_REF overlay;
788 
789     eve_t * peve;
790     chr_t * ptarget;
791 
792     int add_type, set_type;
793 
794     if ( NULL == penc ) return NULL;
795     ienc  = GET_INDEX_PENC( penc );
796 
797     // get the profile data
798     pdata = &( penc->spawn_data );
799 
800     // store the profile
801     penc->profile_ref  = pdata->profile_ref;
802 
803     // Convert from local pdata->eve_ref to global enchant profile
804     if ( !LOADED_EVE( pdata->eve_ref ) )
805     {
806         log_debug( "spawn_one_enchant() - cannot spawn enchant with invalid enchant template (\"eve\") == %d\n", REF_TO_INT( pdata->eve_ref ) );
807 
808         return NULL;
809     }
810     penc->eve_ref = pdata->eve_ref;
811     peve = EveStack.lst + pdata->eve_ref;
812 
813     // turn the enchant on here. you can't fail to spawn after this point.
814     POBJ_ACTIVATE( penc, peve->name );
815 
816     // does the target exist?
817     if ( !DEFINED_CHR( pdata->target_ref ) )
818     {
819         penc->target_ref   = ( CHR_REF )MAX_CHR;
820         ptarget            = NULL;
821     }
822     else
823     {
824         penc->target_ref = pdata->target_ref;
825         ptarget = ChrList.lst + penc->target_ref;
826     }
827     penc->target_mana  = peve->target_mana;
828     penc->target_life  = peve->target_life;
829 
830     // does the owner exist?
831     if ( !DEFINED_CHR( pdata->owner_ref ) )
832     {
833         penc->owner_ref = ( CHR_REF )MAX_CHR;
834     }
835     else
836     {
837         penc->owner_ref  = pdata->owner_ref;
838     }
839     penc->owner_mana = peve->owner_mana;
840     penc->owner_life = peve->owner_life;
841 
842     // does the spawner exist?
843     if ( !DEFINED_CHR( pdata->spawner_ref ) )
844     {
845         penc->spawner_ref      = ( CHR_REF )MAX_CHR;
846         penc->spawnermodel_ref = ( PRO_REF )MAX_PROFILE;
847     }
848     else
849     {
850         penc->spawner_ref = pdata->spawner_ref;
851         penc->spawnermodel_ref = chr_get_ipro( pdata->spawner_ref );
852 
853         ChrList.lst[penc->spawner_ref].undoenchant = ienc;
854     }
855 
856     // set some other spawning parameters
857     penc->lifetime       = peve->lifetime;
858     penc->spawn_timer    = 1;
859 
860     // Now set all of the specific values, morph first
861     for ( set_type = ENC_SET_FIRST; set_type <= ENC_SET_LAST; set_type++ )
862     {
863         enchant_apply_set( ienc, set_type, pdata->profile_ref );
864     }
865 
866     // Now do all of the stat adds
867     for ( add_type = ENC_ADD_FIRST; add_type <= ENC_ADD_LAST; add_type++ )
868     {
869         enchant_apply_add( ienc, add_type, pdata->eve_ref );
870     }
871 
872     // Add it as first in the list
873     if ( NULL != ptarget )
874     {
875         penc->nextenchant_ref = ptarget->firstenchant;
876         ptarget->firstenchant = ienc;
877     }
878 
879     // Create an overlay character?
880     if ( peve->spawn_overlay && NULL != ptarget )
881     {
882         overlay = spawn_one_character( ptarget->pos, pdata->profile_ref, ptarget->team, 0, ptarget->ori.facing_z, NULL, ( CHR_REF )MAX_CHR );
883         if ( DEFINED_CHR( overlay ) )
884         {
885             chr_t * povl;
886             mad_t * povl_mad;
887             int action;
888 
889             povl     = ChrList.lst + overlay;
890             povl_mad = chr_get_pmad( overlay );
891 
892             penc->overlay_ref = overlay;  // Kill this character on end...
893             povl->ai.target   = pdata->target_ref;
894             povl->is_overlay  = btrue;
895             chr_set_ai_state( povl, peve->spawn_overlay );  // ??? WHY DO THIS ???
896 
897             // Start out with ActionMJ...  Object activated
898             action = mad_get_action_ref( chr_get_imad( overlay ), ACTION_MJ );
899             if ( !ACTION_IS_TYPE( action, D ) )
900             {
901                 chr_start_anim( povl, action, bfalse, btrue );
902             }
903 
904             // Assume it's transparent...
905             chr_set_light( povl, 254 );
906             chr_set_alpha( povl,   0 );
907         }
908     }
909 
910     //Apply special skill effects
911     if ( NULL != ptarget )
912     {
913 
914         // Allow them to see kurses?
915         if ( 0 != peve->seekurse )
916         {
917             ptarget->see_kurse_level = peve->seekurse;
918         }
919 
920         // Allow them to see in darkness (or blindness if negative)
921         if ( 0 != peve->darkvision )
922         {
923             ptarget->darkvision_level = peve->darkvision;
924         }
925 
926     }
927 
928     return penc;
929 }
930 
931 //--------------------------------------------------------------------------------------------
enc_config_do_active(enc_t * penc)932 enc_t * enc_config_do_active( enc_t * penc )
933 {
934     /// @details ZZ@> This function allows enchantments to update, spawn particles,
935     //  do drains, stat boosts and despawn.
936 
937     ENC_REF  ienc;
938     CHR_REF  owner, target;
939     EVE_REF  eve;
940     eve_t * peve;
941     chr_t * ptarget;
942 
943     if ( NULL == penc ) return penc;
944     ienc = GET_REF_PENC( penc );
945 
946     // the following functions should not be done the first time through the update loop
947     if ( 0 == clock_wld ) return penc;
948 
949     peve = enc_get_peve( ienc );
950     if ( NULL == peve ) return penc;
951 
952     // check to see whether the enchant needs to spawn some particles
953     if ( penc->spawn_timer > 0 ) penc->spawn_timer--;
954 
955     if ( 0 == penc->spawn_timer && peve->contspawn_amount <= 0 )
956     {
957         int      tnc;
958         FACING_T facing;
959         penc->spawn_timer = peve->contspawn_delay;
960         ptarget = ChrList.lst + penc->target_ref;
961 
962         facing = ptarget->ori.facing_z;
963         for ( tnc = 0; tnc < peve->contspawn_amount; tnc++ )
964         {
965             spawn_one_particle( ptarget->pos, facing, penc->profile_ref, peve->contspawn_lpip,
966                                 ( CHR_REF )MAX_CHR, GRIP_LAST, chr_get_iteam( penc->owner_ref ), penc->owner_ref, ( PRT_REF )MAX_PRT, tnc, ( CHR_REF )MAX_CHR );
967 
968             facing += peve->contspawn_facingadd;
969         }
970     }
971 
972     // Do enchant drains and regeneration
973     if ( clock_enc_stat >= ONESECOND )
974     {
975         if ( 0 == penc->lifetime )
976         {
977             enc_request_terminate( ienc );
978         }
979         else
980         {
981             // Do enchant timer
982             if ( penc->lifetime > 0 ) penc->lifetime--;
983 
984             // To make life easier
985             owner  = enc_get_iowner( ienc );
986             target = penc->target_ref;
987             eve    = enc_get_ieve( ienc );
988 
989             // Do drains
990             if ( ChrList.lst[owner].alive )
991             {
992 
993                 // Change life
994                 if ( 0 != penc->owner_life )
995                 {
996                     ChrList.lst[owner].life += penc->owner_life;
997                     if ( ChrList.lst[owner].life <= 0 )
998                     {
999                         kill_character( owner, target, bfalse );
1000                     }
1001                     if ( ChrList.lst[owner].life > ChrList.lst[owner].lifemax )
1002                     {
1003                         ChrList.lst[owner].life = ChrList.lst[owner].lifemax;
1004                     }
1005                 }
1006 
1007                 // Change mana
1008                 if ( 0 != penc->owner_mana )
1009                 {
1010                     bool_t mana_paid = cost_mana( owner, -penc->owner_mana, target );
1011                     if ( EveStack.lst[eve].endifcantpay && !mana_paid )
1012                     {
1013                         enc_request_terminate( ienc );
1014                     }
1015                 }
1016 
1017             }
1018             else if ( !EveStack.lst[eve].stayifnoowner )
1019             {
1020                 enc_request_terminate( ienc );
1021             }
1022 
1023             // the enchant could have been inactivated by the stuff above
1024             // check it again
1025             if ( INGAME_ENC( ienc ) )
1026             {
1027                 if ( ChrList.lst[target].alive )
1028                 {
1029 
1030                     // Change life
1031                     if ( 0 != penc->target_life )
1032                     {
1033                         ChrList.lst[target].life += penc->target_life;
1034                         if ( ChrList.lst[target].life <= 0 )
1035                         {
1036                             kill_character( target, owner, bfalse );
1037                         }
1038                         if ( ChrList.lst[target].life > ChrList.lst[target].lifemax )
1039                         {
1040                             ChrList.lst[target].life = ChrList.lst[target].lifemax;
1041                         }
1042                     }
1043 
1044                     // Change mana
1045                     if ( 0 != penc->target_mana )
1046                     {
1047                         bool_t mana_paid = cost_mana( target, -penc->target_mana, owner );
1048                         if ( EveStack.lst[eve].endifcantpay && !mana_paid )
1049                         {
1050                             enc_request_terminate( ienc );
1051                         }
1052                     }
1053 
1054                 }
1055                 else if ( !EveStack.lst[eve].stayiftargetdead )
1056                 {
1057                     enc_request_terminate( ienc );
1058                 }
1059             }
1060         }
1061     }
1062 
1063     return penc;
1064 }
1065 
1066 //--------------------------------------------------------------------------------------------
1067 //--------------------------------------------------------------------------------------------
enc_config_construct(enc_t * penc,int max_iterations)1068 enc_t * enc_config_construct( enc_t * penc, int max_iterations )
1069 {
1070     int          iterations;
1071     obj_data_t * pbase;
1072 
1073     if ( NULL == penc ) return NULL;
1074 
1075     pbase = POBJ_GET_PBASE( penc );
1076     if ( !pbase->allocated ) return NULL;
1077 
1078     // if the enchant is already beyond this stage, deconstruct it and start over
1079     if ( pbase->state > ( int )( ego_object_constructing + 1 ) )
1080     {
1081         enc_t * tmp_enc = enc_config_deconstruct( penc, max_iterations );
1082         if ( tmp_enc == penc ) return NULL;
1083     }
1084 
1085     iterations = 0;
1086     while ( NULL != penc && pbase->state <= ego_object_constructing && iterations < max_iterations )
1087     {
1088         enc_t * ptmp = enc_run_config( penc );
1089         if ( ptmp != penc ) return NULL;
1090         iterations++;
1091     }
1092 
1093     return penc;
1094 }
1095 
1096 //--------------------------------------------------------------------------------------------
enc_config_initialize(enc_t * penc,int max_iterations)1097 enc_t * enc_config_initialize( enc_t * penc, int max_iterations )
1098 {
1099     int          iterations;
1100     obj_data_t * pbase;
1101 
1102     if ( NULL == penc ) return NULL;
1103 
1104     pbase = POBJ_GET_PBASE( penc );
1105     if ( !pbase->allocated ) return NULL;
1106 
1107     // if the enchant is already beyond this stage, deconstruct it and start over
1108     if ( pbase->state > ( int )( ego_object_initializing + 1 ) )
1109     {
1110         enc_t * tmp_enc = enc_config_deconstruct( penc, max_iterations );
1111         if ( tmp_enc == penc ) return NULL;
1112     }
1113 
1114     iterations = 0;
1115     while ( NULL != penc && pbase->state <= ego_object_initializing && iterations < max_iterations )
1116     {
1117         enc_t * ptmp = enc_run_config( penc );
1118         if ( ptmp != penc ) return NULL;
1119         iterations++;
1120     }
1121 
1122     return penc;
1123 }
1124 
1125 //--------------------------------------------------------------------------------------------
enc_config_activate(enc_t * penc,int max_iterations)1126 enc_t * enc_config_activate( enc_t * penc, int max_iterations )
1127 {
1128     int          iterations;
1129     obj_data_t * pbase;
1130 
1131     if ( NULL == penc ) return NULL;
1132 
1133     pbase = POBJ_GET_PBASE( penc );
1134     if ( !pbase->allocated ) return NULL;
1135 
1136     // if the particle is already beyond this stage, deconstruct it and start over
1137     if ( pbase->state > ( int )( ego_object_active + 1 ) )
1138     {
1139         enc_t * tmp_enc = enc_config_deconstruct( penc, max_iterations );
1140         if ( tmp_enc == penc ) return NULL;
1141     }
1142 
1143     iterations = 0;
1144     while ( NULL != penc && pbase->state < ego_object_active && iterations < max_iterations )
1145     {
1146         enc_t * ptmp = enc_run_config( penc );
1147         if ( ptmp != penc ) return NULL;
1148         iterations++;
1149     }
1150 
1151     EGOBOO_ASSERT( pbase->state == ego_object_active );
1152     if ( pbase->state == ego_object_active )
1153     {
1154         EncList_add_used( GET_INDEX_PENC( penc ) );
1155     }
1156 
1157     return penc;
1158 }
1159 
1160 //--------------------------------------------------------------------------------------------
enc_config_deinitialize(enc_t * penc,int max_iterations)1161 enc_t * enc_config_deinitialize( enc_t * penc, int max_iterations )
1162 {
1163     int          iterations;
1164     obj_data_t * pbase;
1165 
1166     if ( NULL == penc ) return NULL;
1167 
1168     pbase = POBJ_GET_PBASE( penc );
1169     if ( !pbase->allocated ) return NULL;
1170 
1171     // if the particle is already beyond this stage, deinitialize it
1172     if ( pbase->state > ( int )( ego_object_deinitializing + 1 ) )
1173     {
1174         return penc;
1175     }
1176     else if ( pbase->state < ego_object_deinitializing )
1177     {
1178         pbase->state = ego_object_deinitializing;
1179     }
1180 
1181     iterations = 0;
1182     while ( NULL != penc && pbase->state <= ego_object_deinitializing && iterations < max_iterations )
1183     {
1184         enc_t * ptmp = enc_run_config( penc );
1185         if ( ptmp != penc ) return NULL;
1186         iterations++;
1187     }
1188 
1189     return penc;
1190 }
1191 
1192 //--------------------------------------------------------------------------------------------
enc_config_deconstruct(enc_t * penc,int max_iterations)1193 enc_t * enc_config_deconstruct( enc_t * penc, int max_iterations )
1194 {
1195     int          iterations;
1196     obj_data_t * pbase;
1197 
1198     if ( NULL == penc ) return NULL;
1199 
1200     pbase = POBJ_GET_PBASE( penc );
1201     if ( !pbase->allocated ) return NULL;
1202 
1203     // if the particle is already beyond this stage, deconstruct it
1204     if ( pbase->state > ( int )( ego_object_destructing + 1 ) )
1205     {
1206         return penc;
1207     }
1208     else if ( pbase->state < ego_object_deinitializing )
1209     {
1210         // make sure that you deinitialize before destructing
1211         pbase->state = ego_object_deinitializing;
1212     }
1213 
1214     iterations = 0;
1215     while ( NULL != penc && pbase->state <= ego_object_destructing && iterations < max_iterations )
1216     {
1217         enc_t * ptmp = enc_run_config( penc );
1218         if ( ptmp != penc ) return NULL;
1219         iterations++;
1220     }
1221 
1222     return penc;
1223 }
1224 
1225 //--------------------------------------------------------------------------------------------
1226 //--------------------------------------------------------------------------------------------
enc_run_config(enc_t * penc)1227 enc_t * enc_run_config( enc_t * penc )
1228 {
1229     obj_data_t * pbase;
1230 
1231     if ( NULL == penc ) return NULL;
1232 
1233     pbase = POBJ_GET_PBASE( penc );
1234     if ( !pbase->allocated ) return NULL;
1235 
1236     // set the object to deinitialize if it is not "dangerous" and if was requested
1237     if ( pbase->kill_me )
1238     {
1239         if ( pbase->state > ego_object_constructing && pbase->state < ego_object_deinitializing )
1240         {
1241             pbase->state = ego_object_deinitializing;
1242         }
1243 
1244         pbase->kill_me = bfalse;
1245     }
1246 
1247     switch ( pbase->state )
1248     {
1249         default:
1250         case ego_object_invalid:
1251             penc = NULL;
1252             break;
1253 
1254         case ego_object_constructing:
1255             penc = enc_config_ctor( penc );
1256             break;
1257 
1258         case ego_object_initializing:
1259             penc = enc_config_init( penc );
1260             break;
1261 
1262         case ego_object_active:
1263             penc = enc_config_active( penc );
1264             break;
1265 
1266         case ego_object_deinitializing:
1267             penc = enc_config_deinit( penc );
1268             break;
1269 
1270         case ego_object_destructing:
1271             penc = enc_config_dtor( penc );
1272             break;
1273 
1274         case ego_object_waiting:
1275         case ego_object_terminated:
1276             /* do nothing */
1277             break;
1278     }
1279 
1280     if ( NULL == penc )
1281     {
1282         pbase->update_guid = INVALID_UPDATE_GUID;
1283     }
1284     else if ( ego_object_active == pbase->state )
1285     {
1286         pbase->update_guid = EncList.update_guid;
1287     }
1288 
1289     return penc;
1290 }
1291 
1292 //--------------------------------------------------------------------------------------------
enc_config_ctor(enc_t * penc)1293 enc_t * enc_config_ctor( enc_t * penc )
1294 {
1295     obj_data_t * pbase;
1296 
1297     // grab the base object
1298     if ( NULL == penc ) return NULL;
1299     pbase = POBJ_GET_PBASE( penc );
1300 
1301     // if we aren't in the correct state, abort.
1302     if ( !STATE_CONSTRUCTING_PBASE( pbase ) ) return penc;
1303 
1304     return enc_ctor( penc );
1305 }
1306 
1307 //--------------------------------------------------------------------------------------------
enc_config_init(enc_t * penc)1308 enc_t * enc_config_init( enc_t * penc )
1309 {
1310     obj_data_t * pbase;
1311 
1312     if ( NULL == penc ) return NULL;
1313 
1314     pbase = POBJ_GET_PBASE( penc );
1315     if ( !STATE_INITIALIZING_PBASE( pbase ) ) return penc;
1316 
1317     penc = enc_config_do_init( penc );
1318     if ( NULL == penc ) return NULL;
1319 
1320     if ( 0 == enc_loop_depth )
1321     {
1322         penc->obj_base.on = btrue;
1323     }
1324     else
1325     {
1326         EncList_add_activation( GET_INDEX_PENC( penc ) );
1327     }
1328 
1329     pbase->state = ego_object_active;
1330 
1331     return penc;
1332 }
1333 
1334 //--------------------------------------------------------------------------------------------
enc_config_active(enc_t * penc)1335 enc_t * enc_config_active( enc_t * penc )
1336 {
1337     // there's nothing to configure if the object is active...
1338 
1339     obj_data_t * pbase;
1340 
1341     if ( NULL == penc ) return NULL;
1342 
1343     pbase = POBJ_GET_PBASE( penc );
1344     if ( !pbase->allocated ) return NULL;
1345 
1346     if ( !STATE_ACTIVE_PBASE( pbase ) ) return penc;
1347 
1348     POBJ_END_SPAWN( penc );
1349 
1350     penc = enc_config_do_active( penc );
1351 
1352     return penc;
1353 }
1354 
1355 //--------------------------------------------------------------------------------------------
enc_config_deinit(enc_t * penc)1356 enc_t * enc_config_deinit( enc_t * penc )
1357 {
1358     /// @details BB@> deinitialize the character data
1359 
1360     obj_data_t * pbase;
1361 
1362     if ( NULL == penc ) return NULL;
1363     pbase = POBJ_GET_PBASE( penc );
1364 
1365     if ( !STATE_DEINITIALIZING_PBASE( pbase ) ) return penc;
1366 
1367     POBJ_END_SPAWN( penc );
1368 
1369     pbase->state = ego_object_destructing;
1370     pbase->on    = bfalse;
1371 
1372     return penc;
1373 }
1374 
1375 //--------------------------------------------------------------------------------------------
enc_config_dtor(enc_t * penc)1376 enc_t * enc_config_dtor( enc_t * penc )
1377 {
1378     obj_data_t * pbase;
1379 
1380     if ( NULL == penc ) return NULL;
1381     pbase = POBJ_GET_PBASE( penc );
1382 
1383     if ( !STATE_DESTRUCTING_PBASE( pbase ) ) return penc;
1384 
1385     POBJ_END_SPAWN( penc );
1386 
1387     return enc_dtor( penc );
1388 }
1389 
1390 //--------------------------------------------------------------------------------------------
spawn_one_enchant(const CHR_REF owner,const CHR_REF target,const CHR_REF spawner,const ENC_REF enc_override,const PRO_REF modeloptional)1391 ENC_REF spawn_one_enchant( const CHR_REF owner, const CHR_REF target, const CHR_REF spawner, const ENC_REF enc_override, const PRO_REF modeloptional )
1392 {
1393     /// @details ZZ@> This function enchants a target, returning the enchantment index or MAX_ENC
1394     ///    if failed
1395 
1396     ENC_REF enc_ref;
1397     EVE_REF eve_ref;
1398 
1399     eve_t * peve;
1400     enc_t * penc;
1401     chr_t * ptarget;
1402 
1403     PRO_REF loc_profile;
1404     CHR_REF loc_target;
1405 
1406     // Target must both be alive and on and valid
1407     loc_target = target;
1408     if ( !DEFINED_CHR( loc_target ) )
1409     {
1410         log_warning( "spawn_one_enchant() - failed because the target does not exist.\n" );
1411         return ( ENC_REF )MAX_ENC;
1412     }
1413     ptarget = ChrList.lst + loc_target;
1414 
1415     // you should be able to enchant dead stuff to raise the dead...
1416     // if( !ptarget->alive ) return (ENC_REF)MAX_ENC;
1417 
1418     if ( LOADED_PRO( modeloptional ) )
1419     {
1420         // The enchantment type is given explicitly
1421         loc_profile = modeloptional;
1422     }
1423     else
1424     {
1425         // The enchantment type is given by the spawner
1426         loc_profile = chr_get_ipro( spawner );
1427 
1428         if ( !LOADED_PRO( loc_profile ) )
1429         {
1430             log_warning( "spawn_one_enchant() - no valid profile for the spawning character \"%s\"(%d).\n", ChrList.lst[spawner].obj_base._name, REF_TO_INT( spawner ) );
1431             return ( ENC_REF )MAX_ENC;
1432         }
1433     }
1434 
1435     eve_ref = pro_get_ieve( loc_profile );
1436     if ( !LOADED_EVE( eve_ref ) )
1437     {
1438         log_warning( "spawn_one_enchant() - the object \"%s\"(%d) does not have an enchant profile.\n", ProList.lst[loc_profile].name, REF_TO_INT( loc_profile ) );
1439 
1440         return ( ENC_REF )MAX_ENC;
1441     }
1442     peve = EveStack.lst + eve_ref;
1443 
1444     // count all the requests for this enchantment type
1445     peve->request_count++;
1446 
1447     // Owner must both be alive and on and valid if it isn't a stayifnoowner enchant
1448     if ( !peve->stayifnoowner && ( !INGAME_CHR( owner ) || !ChrList.lst[owner].alive ) )
1449     {
1450         log_warning( "spawn_one_enchant() - failed because the required enchant owner cannot be found.\n" );
1451         return ( ENC_REF )MAX_ENC;
1452     }
1453 
1454     // do retargeting, if necessary
1455     // Should it choose an inhand item?
1456     if ( peve->retarget )
1457     {
1458         // Left, right, or both are valid
1459         if ( INGAME_CHR( ptarget->holdingwhich[SLOT_LEFT] ) )
1460         {
1461             // Only right hand is valid
1462             loc_target = ptarget->holdingwhich[SLOT_RIGHT];
1463         }
1464         else if ( INGAME_CHR( ptarget->holdingwhich[SLOT_LEFT] ) )
1465         {
1466             // Pick left hand
1467             loc_target = ptarget->holdingwhich[SLOT_LEFT];
1468         }
1469         else
1470         {
1471             // No weapons to pick, should it pick itself???
1472             loc_target = ( CHR_REF )MAX_CHR;
1473         }
1474     }
1475 
1476     // make sure the loc_target is alive
1477     if ( !DEFINED_PCHR( ptarget ) || !ptarget->alive )
1478     {
1479         log_warning( "spawn_one_enchant() - failed because the target is not alive.\n" );
1480         return ( ENC_REF )MAX_ENC;
1481     }
1482     ptarget = ChrList.lst + loc_target;
1483 
1484     // Check peve->required_damagetype
1485     if ( peve->required_damagetype < DAMAGE_COUNT )
1486     {
1487         if (
1488             GET_DAMAGE_RESIST( ptarget->damage_modifier[peve->required_damagetype] ) >= 3 ||
1489             HAS_SOME_BITS( ptarget->damage_modifier[peve->required_damagetype], DAMAGECHARGE ) )
1490         {
1491             log_warning( "spawn_one_enchant() - failed because the target is immune to the enchant.\n" );
1492             return ( ENC_REF )MAX_ENC;
1493         }
1494     }
1495 
1496     // Check peve->require_damagetarget_damagetype
1497     if ( peve->require_damagetarget_damagetype < DAMAGE_COUNT )
1498     {
1499         if ( ptarget->damagetarget_damagetype != peve->require_damagetarget_damagetype )
1500         {
1501             log_warning( "spawn_one_enchant() - failed because the target not have the right damagetarget_damagetype.\n" );
1502             return ( ENC_REF )MAX_ENC;
1503         }
1504     }
1505 
1506     // Find an enchant index to use
1507     enc_ref = EncList_allocate( enc_override );
1508 
1509     if ( !ALLOCATED_ENC( enc_ref ) )
1510     {
1511         log_warning( "spawn_one_enchant() - could not allocate an enchant.\n" );
1512         return ( ENC_REF )MAX_ENC;
1513     }
1514     penc = EncList.lst + enc_ref;
1515 
1516     POBJ_BEGIN_SPAWN( penc );
1517 
1518     penc->spawn_data.owner_ref   = owner;
1519     penc->spawn_data.target_ref  = loc_target;
1520     penc->spawn_data.spawner_ref = spawner;
1521     penc->spawn_data.profile_ref = loc_profile;
1522     penc->spawn_data.eve_ref     = eve_ref;
1523 
1524     // actually force the character to spawn
1525     penc = enc_config_activate( penc, 100 );
1526 
1527     // log all the successful spawns
1528     if ( NULL != penc )
1529     {
1530         POBJ_END_SPAWN( penc );
1531         peve->create_count++;
1532     }
1533 
1534     return enc_ref;
1535 }
1536 
1537 //--------------------------------------------------------------------------------------------
load_one_enchant_profile_vfs(const char * szLoadName,const EVE_REF ieve)1538 EVE_REF load_one_enchant_profile_vfs( const char* szLoadName, const EVE_REF ieve )
1539 {
1540     /// @details ZZ@> This function loads an enchantment profile into the EveStack
1541 
1542     EVE_REF retval = ( EVE_REF )MAX_EVE;
1543 
1544     if ( VALID_EVE_RANGE( ieve ) )
1545     {
1546         eve_t * peve = EveStack.lst + ieve;
1547 
1548         if ( NULL != load_one_enchant_file_vfs( szLoadName, peve ) )
1549         {
1550             retval = ieve;
1551 
1552             // limit the endsound_index
1553             peve->endsound_index = CLIP( peve->endsound_index, INVALID_SOUND, MAX_WAVE );
1554         }
1555     }
1556 
1557     return retval;
1558 }
1559 
1560 //--------------------------------------------------------------------------------------------
enchant_remove_set(const ENC_REF ienc,int value_idx)1561 void enchant_remove_set( const ENC_REF ienc, int value_idx )
1562 {
1563     /// @details ZZ@> This function unsets a set value
1564     CHR_REF character;
1565     enc_t * penc;
1566     chr_t * ptarget;
1567 
1568     if ( value_idx < 0 || value_idx >= MAX_ENCHANT_SET ) return;
1569 
1570     if ( !ALLOCATED_ENC( ienc ) ) return;
1571     penc = EncList.lst + ienc;
1572 
1573     if ( value_idx >= MAX_ENCHANT_SET || !penc->setyesno[value_idx] ) return;
1574 
1575     if ( !INGAME_CHR( penc->target_ref ) ) return;
1576     character = penc->target_ref;
1577     ptarget   = ChrList.lst + penc->target_ref;
1578 
1579     switch ( value_idx )
1580     {
1581         case SETDAMAGETYPE:
1582             ptarget->damagetarget_damagetype = penc->setsave[value_idx];
1583             break;
1584 
1585         case SETNUMBEROFJUMPS:
1586             ptarget->jumpnumberreset = penc->setsave[value_idx];
1587             break;
1588 
1589         case SETLIFEBARCOLOR:
1590             ptarget->lifecolor = penc->setsave[value_idx];
1591             break;
1592 
1593         case SETMANABARCOLOR:
1594             ptarget->manacolor = penc->setsave[value_idx];
1595             break;
1596 
1597         case SETSLASHMODIFIER:
1598             ptarget->damage_modifier[DAMAGE_SLASH] = penc->setsave[value_idx];
1599             break;
1600 
1601         case SETCRUSHMODIFIER:
1602             ptarget->damage_modifier[DAMAGE_CRUSH] = penc->setsave[value_idx];
1603             break;
1604 
1605         case SETPOKEMODIFIER:
1606             ptarget->damage_modifier[DAMAGE_POKE] = penc->setsave[value_idx];
1607             break;
1608 
1609         case SETHOLYMODIFIER:
1610             ptarget->damage_modifier[DAMAGE_HOLY] = penc->setsave[value_idx];
1611             break;
1612 
1613         case SETEVILMODIFIER:
1614             ptarget->damage_modifier[DAMAGE_EVIL] = penc->setsave[value_idx];
1615             break;
1616 
1617         case SETFIREMODIFIER:
1618             ptarget->damage_modifier[DAMAGE_FIRE] = penc->setsave[value_idx];
1619             break;
1620 
1621         case SETICEMODIFIER:
1622             ptarget->damage_modifier[DAMAGE_ICE] = penc->setsave[value_idx];
1623             break;
1624 
1625         case SETZAPMODIFIER:
1626             ptarget->damage_modifier[DAMAGE_ZAP] = penc->setsave[value_idx];
1627             break;
1628 
1629         case SETFLASHINGAND:
1630             ptarget->flashand = penc->setsave[value_idx];
1631             break;
1632 
1633         case SETLIGHTBLEND:
1634             chr_set_light( ptarget, penc->setsave[value_idx] );
1635             break;
1636 
1637         case SETALPHABLEND:
1638             chr_set_alpha( ptarget, penc->setsave[value_idx] );
1639             break;
1640 
1641         case SETSHEEN:
1642             chr_set_sheen( ptarget, penc->setsave[value_idx] );
1643             break;
1644 
1645         case SETFLYTOHEIGHT:
1646             ptarget->flyheight = penc->setsave[value_idx];
1647             break;
1648 
1649         case SETWALKONWATER:
1650             ptarget->waterwalk = ( 0 != penc->setsave[value_idx] );
1651             break;
1652 
1653         case SETCANSEEINVISIBLE:
1654             ptarget->see_invisible_level = penc->setsave[value_idx];
1655             break;
1656 
1657         case SETMISSILETREATMENT:
1658             ptarget->missiletreatment = penc->setsave[value_idx];
1659             break;
1660 
1661         case SETCOSTFOREACHMISSILE:
1662             ptarget->missilecost = penc->setsave[value_idx];
1663             ptarget->missilehandler = character;
1664             break;
1665 
1666         case SETMORPH:
1667             // Need special handler for when this is removed
1668             change_character( character, ptarget->basemodel_ref, penc->setsave[value_idx], ENC_LEAVE_ALL );
1669             break;
1670 
1671         case SETCHANNEL:
1672             ptarget->canchannel = ( 0 != penc->setsave[value_idx] );
1673             break;
1674     }
1675 
1676     penc->setyesno[value_idx] = bfalse;
1677 }
1678 
1679 //--------------------------------------------------------------------------------------------
enchant_remove_add(const ENC_REF ienc,int value_idx)1680 void enchant_remove_add( const ENC_REF ienc, int value_idx )
1681 {
1682     /// @details ZZ@> This function undoes cumulative modification to character stats
1683 
1684     float fvaluetoadd;
1685     int valuetoadd;
1686     CHR_REF character;
1687     enc_t * penc;
1688     chr_t * ptarget;
1689 
1690     if ( value_idx < 0 || value_idx >= MAX_ENCHANT_ADD ) return;
1691 
1692     if ( !ALLOCATED_ENC( ienc ) ) return;
1693     penc = EncList.lst + ienc;
1694 
1695     if ( !INGAME_CHR( penc->target_ref ) ) return;
1696     character = penc->target_ref;
1697     ptarget = ChrList.lst + penc->target_ref;
1698 
1699     if ( penc->addyesno[value_idx] )
1700     {
1701         switch ( value_idx )
1702         {
1703             case ADDJUMPPOWER:
1704                 fvaluetoadd = penc->addsave[value_idx];
1705                 ptarget->jump_power -= fvaluetoadd;
1706                 break;
1707 
1708             case ADDBUMPDAMPEN:
1709                 fvaluetoadd = penc->addsave[value_idx];
1710                 ptarget->phys.bumpdampen -= fvaluetoadd;
1711                 break;
1712 
1713             case ADDBOUNCINESS:
1714                 fvaluetoadd = penc->addsave[value_idx];
1715                 ptarget->phys.dampen -= fvaluetoadd;
1716                 break;
1717 
1718             case ADDDAMAGE:
1719                 valuetoadd = penc->addsave[value_idx];
1720                 ptarget->damage_boost -= valuetoadd;
1721                 break;
1722 
1723             case ADDSIZE:
1724                 fvaluetoadd = penc->addsave[value_idx];
1725                 ptarget->fat_goto -= fvaluetoadd;
1726                 ptarget->fat_goto_time = SIZETIME;
1727                 break;
1728 
1729             case ADDACCEL:
1730                 fvaluetoadd = penc->addsave[value_idx];
1731                 chr_set_maxaccel( ptarget, ptarget->maxaccel_reset - fvaluetoadd );
1732                 break;
1733 
1734             case ADDRED:
1735                 valuetoadd = penc->addsave[value_idx];
1736                 chr_set_redshift( ptarget, ptarget->inst.redshift - valuetoadd );
1737                 break;
1738 
1739             case ADDGRN:
1740                 valuetoadd = penc->addsave[value_idx];
1741                 chr_set_grnshift( ptarget, ptarget->inst.grnshift - valuetoadd );
1742                 break;
1743 
1744             case ADDBLU:
1745                 valuetoadd = penc->addsave[value_idx];
1746                 chr_set_blushift( ptarget, ptarget->inst.blushift - valuetoadd );
1747                 break;
1748 
1749             case ADDDEFENSE:
1750                 valuetoadd = penc->addsave[value_idx];
1751                 ptarget->defense -= valuetoadd;
1752                 break;
1753 
1754             case ADDMANA:
1755                 valuetoadd = penc->addsave[value_idx];
1756                 ptarget->manamax -= valuetoadd;
1757                 ptarget->mana -= valuetoadd;
1758                 if ( ptarget->mana < 0 ) ptarget->mana = 0;
1759                 break;
1760 
1761             case ADDLIFE:
1762                 valuetoadd = penc->addsave[value_idx];
1763                 ptarget->lifemax -= valuetoadd;
1764                 ptarget->life -= valuetoadd;
1765                 if ( ptarget->life < 1 ) ptarget->life = 1;
1766                 break;
1767 
1768             case ADDSTRENGTH:
1769                 valuetoadd = penc->addsave[value_idx];
1770                 ptarget->strength -= valuetoadd;
1771                 break;
1772 
1773             case ADDWISDOM:
1774                 valuetoadd = penc->addsave[value_idx];
1775                 ptarget->wisdom -= valuetoadd;
1776                 break;
1777 
1778             case ADDINTELLIGENCE:
1779                 valuetoadd = penc->addsave[value_idx];
1780                 ptarget->intelligence -= valuetoadd;
1781                 break;
1782 
1783             case ADDDEXTERITY:
1784                 valuetoadd = penc->addsave[value_idx];
1785                 ptarget->dexterity -= valuetoadd;
1786                 break;
1787         }
1788 
1789         penc->addyesno[value_idx] = bfalse;
1790     }
1791 }
1792 
1793 //--------------------------------------------------------------------------------------------
1794 //--------------------------------------------------------------------------------------------
init_all_eve()1795 void init_all_eve()
1796 {
1797     EVE_REF cnt;
1798 
1799     for ( cnt = 0; cnt < MAX_EVE; cnt++ )
1800     {
1801         eve_init( EveStack.lst + cnt );
1802     }
1803 }
1804 
1805 //--------------------------------------------------------------------------------------------
release_all_eve()1806 void release_all_eve()
1807 {
1808     EVE_REF cnt;
1809 
1810     for ( cnt = 0; cnt < MAX_EVE; cnt++ )
1811     {
1812         release_one_eve( cnt );
1813     }
1814 }
1815 
1816 //--------------------------------------------------------------------------------------------
release_one_eve(const EVE_REF ieve)1817 bool_t release_one_eve( const EVE_REF ieve )
1818 {
1819     eve_t * peve;
1820 
1821     if ( !VALID_EVE_RANGE( ieve ) ) return bfalse;
1822     peve = EveStack.lst + ieve;
1823 
1824     if ( !peve->loaded ) return btrue;
1825 
1826     eve_init( peve );
1827 
1828     return btrue;
1829 }
1830 
1831 //--------------------------------------------------------------------------------------------
update_all_enchants()1832 void update_all_enchants()
1833 {
1834     ENC_REF ienc;
1835 
1836     // update all enchants
1837     for ( ienc = 0; ienc < MAX_ENC; ienc++ )
1838     {
1839         enc_run_config( EncList.lst + ienc );
1840     }
1841 
1842     // fix the stat timer
1843     if ( clock_enc_stat >= ONESECOND )
1844     {
1845         // Reset the clock
1846         clock_enc_stat -= ONESECOND;
1847     }
1848 }
1849 
1850 //--------------------------------------------------------------------------------------------
cleanup_enchant_list(const ENC_REF ienc,ENC_REF * enc_parent)1851 ENC_REF cleanup_enchant_list( const ENC_REF ienc, ENC_REF * enc_parent )
1852 {
1853     /// @details BB@> remove all the dead enchants from the enchant list
1854     ///     and report back the first non-dead enchant in the list.
1855 
1856     bool_t enc_used[MAX_ENC];
1857 
1858     ENC_REF first_valid_enchant;
1859 
1860     ENC_REF ienc_now, ienc_nxt;
1861     size_t  ienc_count;
1862 
1863     if ( !VALID_ENC_RANGE( ienc ) ) return MAX_ENC;
1864 
1865     // clear the list
1866     memset( enc_used, 0, sizeof( enc_used ) );
1867 
1868     // scan the list of enchants
1869     ienc_nxt            = ( ENC_REF ) MAX_ENC;
1870     first_valid_enchant = ienc_now = ienc;
1871     ienc_count = 0;
1872     while (( MAX_ENC != ienc_now ) && ( ienc_count < MAX_ENC ) )
1873     {
1874         ienc_nxt = EncList.lst[ienc_now].nextenchant_ref;
1875 
1876         // coerce the list of enchants to a valid value
1877         if ( !VALID_ENC_RANGE( ienc_nxt ) )
1878         {
1879             ienc_nxt = EncList.lst[ienc_now].nextenchant_ref = MAX_ENC;
1880         }
1881 
1882         // fix any loops in the enchant list
1883         if ( enc_used[ienc_nxt] )
1884         {
1885             EncList.lst[ienc_now].nextenchant_ref = MAX_ENC;
1886             break;
1887         }
1888 
1889         //( !INGAME_CHR( EncList.lst[ienc_now].target_ref ) && !EveStack.lst[EncList.lst[ienc_now].eve_ref].stayiftargetdead )
1890 
1891         // remove any expired enchants
1892         if ( !INGAME_ENC( ienc_now ) )
1893         {
1894             remove_enchant( ienc_now, enc_parent );
1895             enc_used[ienc_now] = btrue;
1896         }
1897         else
1898         {
1899             // store this enchant in the list of used enchants
1900             enc_used[ienc_now] = btrue;
1901 
1902             // keep track of the first valid enchant
1903             if ( MAX_ENC == first_valid_enchant )
1904             {
1905                 first_valid_enchant = ienc_now;
1906             }
1907         }
1908 
1909         enc_parent = &( EncList.lst[ienc_now].nextenchant_ref );
1910         ienc_now    = ienc_nxt;
1911         ienc_count++;
1912     }
1913     if ( ienc_count >= MAX_ENC ) log_error( "%s - bad enchant loop\n", __FUNCTION__ );
1914 
1915     return first_valid_enchant;
1916 }
1917 
1918 //--------------------------------------------------------------------------------------------
cleanup_all_enchants()1919 void cleanup_all_enchants()
1920 {
1921     /// @details ZZ@> this function scans all the enchants and removes any dead ones.
1922     ///               this happens only once a loop
1923 
1924     ENC_BEGIN_LOOP_ACTIVE( ienc, penc )
1925     {
1926         ENC_REF * enc_lst;
1927         eve_t   * peve;
1928         bool_t    do_remove;
1929         bool_t valid_owner, valid_target;
1930 
1931         // try to determine something about the parent
1932         enc_lst = NULL;
1933         valid_target = bfalse;
1934         if ( INGAME_CHR( penc->target_ref ) )
1935         {
1936             valid_target = ChrList.lst[penc->target_ref].alive;
1937 
1938             // this is linked to a known character
1939             enc_lst = &( ChrList.lst[penc->target_ref].firstenchant );
1940         }
1941 
1942         //try to determine if the owner exists and is alive
1943         valid_owner = bfalse;
1944         if ( INGAME_CHR( penc->owner_ref ) )
1945         {
1946             valid_owner = ChrList.lst[penc->owner_ref].alive;
1947         }
1948 
1949         if ( !LOADED_EVE( penc->eve_ref ) )
1950         {
1951             // this should never happen
1952             EGOBOO_ASSERT( bfalse );
1953             continue;
1954         }
1955         peve = EveStack.lst + penc->eve_ref;
1956 
1957         do_remove = bfalse;
1958         if ( WAITING_PBASE( POBJ_GET_PBASE( penc ) ) )
1959         {
1960             // the enchant has been marked for removal
1961             do_remove = btrue;
1962         }
1963         else if ( !valid_owner && !peve->stayifnoowner )
1964         {
1965             // the enchant's owner has died
1966             do_remove = btrue;
1967         }
1968         else if ( !valid_target && !peve->stayiftargetdead )
1969         {
1970             // the enchant's target has died
1971             do_remove = btrue;
1972         }
1973         else if ( valid_owner && peve->endifcantpay )
1974         {
1975             // Undo enchants that cannot be sustained anymore
1976             if ( 0 == ChrList.lst[penc->owner_ref].mana ) do_remove = btrue;
1977         }
1978         else
1979         {
1980             // the enchant has timed out
1981             do_remove = ( 0 == penc->lifetime );
1982         }
1983 
1984         if ( do_remove )
1985         {
1986             remove_enchant( ienc, NULL );
1987         }
1988     }
1989     ENC_END_LOOP();
1990 }
1991 
1992 //--------------------------------------------------------------------------------------------
bump_all_enchants_update_counters()1993 void bump_all_enchants_update_counters()
1994 {
1995     ENC_REF cnt;
1996 
1997     for ( cnt = 0; cnt < MAX_ENC; cnt++ )
1998     {
1999         obj_data_t * pbase;
2000 
2001         pbase = POBJ_GET_PBASE( EncList.lst + cnt );
2002         if ( !ACTIVE_PBASE( pbase ) ) continue;
2003 
2004         pbase->update_count++;
2005     }
2006 }
2007 
2008 //--------------------------------------------------------------------------------------------
enc_request_terminate(const ENC_REF ienc)2009 bool_t enc_request_terminate( const ENC_REF ienc )
2010 {
2011     if ( !ALLOCATED_ENC( ienc ) || TERMINATED_ENC( ienc ) ) return bfalse;
2012 
2013     POBJ_REQUEST_TERMINATE( EncList.lst + ienc );
2014 
2015     return btrue;
2016 }
2017