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 script.c
21 /// @brief Implements the game's scripting language.
22 /// @details
23 
24 #include "script.h"
25 #include "script_compile.h"
26 #include "script_functions.h"
27 
28 #include "mad.h"
29 
30 #include "log.h"
31 #include "camera.h"
32 #include "game.h"
33 #include "network.h"
34 
35 #include "egoboo_vfs.h"
36 #include "egoboo_setup.h"
37 #include "egoboo_strutil.h"
38 #include "egoboo_math.h"
39 
40 #include "profile.inl"
41 #include "char.inl"
42 
43 #include <assert.h>
44 
45 //--------------------------------------------------------------------------------------------
46 //--------------------------------------------------------------------------------------------
47 
48 static const char *  script_error_classname = "UNKNOWN";
49 static PRO_REF       script_error_model     = ( PRO_REF )MAX_PROFILE;
50 static const char *  script_error_name      = "UNKNOWN";
51 static REF_T         script_error_index     = ( Uint16 )( ~0 );
52 
53 static bool_t scr_increment_exe( ai_state_t * pself );
54 static bool_t scr_set_exe( ai_state_t * pself, size_t offset );
55 
56 // static Uint8 run_function_obsolete( script_state_t * pstate, ai_state_t * pself );
57 static Uint8 scr_run_function( script_state_t * pstate, ai_state_t * pself );
58 static void  scr_set_operand( script_state_t * pstate, Uint8 variable );
59 static void  scr_run_operand( script_state_t * pstate, ai_state_t * pself );
60 
61 static bool_t scr_run_operation( script_state_t * pstate, ai_state_t * pself );
62 static bool_t scr_run_function_call( script_state_t * pstate, ai_state_t * pself );
63 
64 PROFILE_DECLARE( script_function )
65 
66 static int    _script_function_calls[SCRIPT_FUNCTIONS_COUNT];
67 static double _script_function_times[SCRIPT_FUNCTIONS_COUNT];
68 
69 static bool_t _scripting_system_initialized = bfalse;
70 
71 //--------------------------------------------------------------------------------------------
72 //--------------------------------------------------------------------------------------------
scripting_system_begin()73 void scripting_system_begin()
74 {
75     if ( !_scripting_system_initialized )
76     {
77         int cnt;
78 
79         PROFILE_INIT( script_function );
80 
81         for ( cnt = 0; cnt < SCRIPT_FUNCTIONS_COUNT; cnt++ )
82         {
83             _script_function_calls[cnt] = 0;
84             _script_function_times[cnt] = 0.0F;
85         }
86 
87         _scripting_system_initialized = btrue;
88     }
89 }
90 
91 //--------------------------------------------------------------------------------------------
scripting_system_end()92 void scripting_system_end()
93 {
94     if ( _scripting_system_initialized )
95     {
96         PROFILE_FREE( script_function );
97 
98 #if (DEBUG_SCRIPT_LEVEL > 1 ) && defined(DEBUG_PROFILE) && defined(_DEBUG)
99         {
100             FILE * ftmp = fopen( vfs_resolveWriteFilename( "/debug/script_function_timing.txt" ), "a+" );
101 
102             if ( NULL != ftmp )
103             {
104                 int cnt;
105 
106                 for ( cnt = 0; cnt < SCRIPT_FUNCTIONS_COUNT; cnt++ )
107                 {
108                     if ( _script_function_calls[cnt] > 0 )
109                     {
110                         fprintf( ftmp, "function == %d\tname == \"%s\"\tcalls == %d\ttime == %lf\n",
111                                  cnt, script_function_names[cnt], _script_function_calls[cnt], _script_function_times[cnt] );
112                     }
113                 }
114 
115                 fflush( ftmp );
116                 fclose( ftmp );
117             }
118         }
119 #endif
120 
121         _scripting_system_initialized = bfalse;
122     }
123 }
124 
125 //--------------------------------------------------------------------------------------------
126 //--------------------------------------------------------------------------------------------
scr_run_chr_script(const CHR_REF character)127 void scr_run_chr_script( const CHR_REF character )
128 {
129     /// @details ZZ@> This function lets one character do AI stuff
130 
131     script_state_t   my_state;
132     chr_t          * pchr;
133     ai_state_t     * pself;
134 
135     // make sure that this module is initialized
136     scripting_system_begin();
137 
138     if ( !INGAME_CHR( character ) )  return;
139     pchr  = ChrList.lst + character;
140     pself = &( pchr->ai );
141 
142     // has the time for this character to die come and gone?
143     if ( pself->poof_time >= 0 && pself->poof_time <= ( Sint32 )update_wld ) return;
144 
145     // grab the "changed" value from the last time the script was run
146     if ( pself->changed )
147     {
148         SET_BIT( pself->alert, ALERTIF_CHANGED );
149         pself->changed = bfalse;
150     }
151 
152     PROFILE_BEGIN_STRUCT( pself );
153 
154     // debug a certain script
155     // debug_scripts = ( 385 == pself->index && 76 == pchr->profile_ref );
156 
157     // target_old is set to the target every time the script is run
158     pself->target_old = pself->target;
159 
160     // Make life easier
161     script_error_classname = "UNKNOWN";
162     script_error_model     = pchr->profile_ref;
163     script_error_index     = ( Uint16 )( ~0 );
164     script_error_name      = "UNKNOWN";
165     if ( script_error_model < MAX_PROFILE )
166     {
167         CAP_REF icap = pro_get_icap( script_error_model );
168 
169         script_error_classname = CapStack.lst[ icap ].classname;
170 
171         script_error_index = ProList.lst[script_error_model].iai;
172         if ( script_error_index < MAX_AI )
173         {
174             script_error_name = AisStorage.ary[script_error_index].szName;
175         }
176     }
177 
178     if ( debug_scripts )
179     {
180         FILE * scr_file = ( NULL == debug_script_file ) ? stdout : debug_script_file;
181 
182         fprintf( scr_file,  "\n\n--------\n%d - %s\n", script_error_index, script_error_name );
183         fprintf( scr_file,  "%d - %s\n", REF_TO_INT( script_error_model ), script_error_classname );
184 
185         // who are we related to?
186         fprintf( scr_file,  "\tindex  == %d\n", REF_TO_INT( pself->index ) );
187         fprintf( scr_file,  "\ttarget == %d\n", REF_TO_INT( pself->target ) );
188         fprintf( scr_file,  "\towner  == %d\n", REF_TO_INT( pself->owner ) );
189         fprintf( scr_file,  "\tchild  == %d\n", REF_TO_INT( pself->child ) );
190 
191         // some local storage
192         fprintf( scr_file,  "\talert     == %x\n", pself->alert );
193         fprintf( scr_file,  "\tstate     == %d\n", pself->state );
194         fprintf( scr_file,  "\tcontent   == %d\n", pself->content );
195         fprintf( scr_file,  "\ttimer     == %d\n", pself->timer );
196         fprintf( scr_file,  "\tupdate_wld == %d\n", update_wld );
197 
198         // ai memory from the last event
199         fprintf( scr_file,  "\tbumplast       == %d\n", REF_TO_INT( pself->bumplast ) );
200         fprintf( scr_file,  "\tattacklast     == %d\n", REF_TO_INT( pself->attacklast ) );
201         fprintf( scr_file,  "\thitlast        == %d\n", REF_TO_INT( pself->hitlast ) );
202         fprintf( scr_file,  "\tdirectionlast  == %d\n", pself->directionlast );
203         fprintf( scr_file,  "\tdamagetypelast == %d\n", pself->damagetypelast );
204         fprintf( scr_file,  "\tlastitemused   == %d\n", REF_TO_INT( pself->lastitemused ) );
205         fprintf( scr_file,  "\ttarget_old     == %d\n", REF_TO_INT( pself->target_old ) );
206 
207         // message handling
208         fprintf( scr_file,  "\torder == %d\n", pself->order_value );
209         fprintf( scr_file,  "\tcounter == %d\n", pself->order_counter );
210 
211         // waypoints
212         fprintf( scr_file,  "\twp_tail == %d\n", pself->wp_lst.tail );
213         fprintf( scr_file,  "\twp_head == %d\n\n", pself->wp_lst.head );
214     }
215 
216     // Clear the button latches
217     if ( !VALID_PLA( pchr->is_which_player ) )
218     {
219         RESET_BIT_FIELD( pchr->latch.b );
220     }
221 
222     // Reset the target if it can't be seen
223     if (( pself->target != pself->index ) && !chr_can_see_object( character, pself->target ) )
224     {
225         pself->target = pself->index;
226     }
227 
228     // reset the script state
229     memset( &my_state, 0, sizeof( my_state ) );
230 
231     // reset the ai
232     pself->terminate = bfalse;
233     pself->indent    = 0;
234     pself->exe_stt   = AisStorage.ary[pself->type].iStartPosition;
235     pself->exe_end   = AisStorage.ary[pself->type].iEndPosition;
236 
237     // Run the AI Script
238     scr_set_exe( pself, pself->exe_stt );
239     while ( !pself->terminate && pself->exe_pos < pself->exe_end )
240     {
241         // This is used by the Else function
242         // it only keeps track of functions
243         pself->indent_last = pself->indent;
244         pself->indent = GET_DATA_BITS( pself->opcode );
245 
246         // Was it a function
247         if ( HAS_SOME_BITS( pself->opcode, FUNCTION_BIT ) )
248         {
249             if ( !scr_run_function_call( &my_state, pself ) )
250             {
251                 break;
252             }
253         }
254         else
255         {
256             if ( !scr_run_operation( &my_state, pself ) )
257             {
258                 break;
259             }
260         }
261     }
262 
263     // Set latches
264     if ( !VALID_PLA( pchr->is_which_player ) )
265     {
266         float latch2;
267 
268         ai_state_ensure_wp( pself );
269 
270         if ( pchr->ismount && INGAME_CHR( pchr->holdingwhich[SLOT_LEFT] ) )
271         {
272             // Mount
273             pchr->latch.x = ChrList.lst[pchr->holdingwhich[SLOT_LEFT]].latch.x;
274             pchr->latch.y = ChrList.lst[pchr->holdingwhich[SLOT_LEFT]].latch.y;
275         }
276         else if ( pself->wp_valid )
277         {
278             // Normal AI
279             pchr->latch.x = ( pself->wp[kX] - pchr->pos.x ) / ( GRID_ISIZE << 2 );
280             pchr->latch.y = ( pself->wp[kY] - pchr->pos.y ) / ( GRID_ISIZE << 2 );
281         }
282         else
283         {
284             // AI, but no valid waypoints
285             pchr->latch.x = 0;
286             pchr->latch.y = 0;
287         }
288 
289         latch2 = pchr->latch.x * pchr->latch.x + pchr->latch.y * pchr->latch.y;
290         if ( latch2 > 1.0f )
291         {
292             float scale = 1.0f / SQRT( latch2 );
293             pchr->latch.x *= scale;
294             pchr->latch.y *= scale;
295         }
296     }
297 
298     // Clear alerts for next time around
299     RESET_BIT_FIELD( pself->alert );
300 
301     PROFILE_END2_STRUCT( pself );
302 }
303 
304 //--------------------------------------------------------------------------------------------
scr_run_function_call(script_state_t * pstate,ai_state_t * pself)305 bool_t scr_run_function_call( script_state_t * pstate, ai_state_t * pself )
306 {
307     Uint8  functionreturn;
308 
309     // check for valid pointers
310     if ( NULL == pstate || NULL == pself ) return bfalse;
311 
312     // check for valid execution pointer
313     if ( pself->exe_pos < pself->exe_stt || pself->exe_pos >= pself->exe_end ) return bfalse;
314 
315     // Run the function
316     functionreturn = scr_run_function( pstate, pself );
317 
318     // move the execution pointer to the jump code
319     scr_increment_exe( pself );
320     if ( functionreturn )
321     {
322         // move the execution pointer to the next opcode
323         scr_increment_exe( pself );
324     }
325     else
326     {
327         // use the jump code to jump to the right location
328         size_t new_index = pself->opcode;
329 
330         // make sure the value is valid
331         EGOBOO_ASSERT( new_index < AISMAXCOMPILESIZE && new_index >= pself->exe_stt && new_index <= pself->exe_end );
332 
333         // actually do the jump
334         scr_set_exe( pself, new_index );
335     }
336 
337     return btrue;
338 }
339 
340 //--------------------------------------------------------------------------------------------
scr_run_operation(script_state_t * pstate,ai_state_t * pself)341 bool_t scr_run_operation( script_state_t * pstate, ai_state_t * pself )
342 {
343     const char * variable;
344     Uint32 var_value, operand_count, i;
345 
346     // check for valid pointers
347     if ( NULL == pstate || NULL == pself ) return bfalse;
348 
349     // check for valid execution pointer
350     if ( pself->exe_pos < pself->exe_stt || pself->exe_pos >= pself->exe_end ) return bfalse;
351 
352     var_value = pself->opcode & VALUE_BITS;
353 
354     // debug stuff
355     variable = "UNKNOWN";
356     if ( debug_scripts )
357     {
358         FILE * scr_file = ( NULL == debug_script_file ) ? stdout : debug_script_file;
359 
360         for ( i = 0; i < pself->indent; i++ ) { fprintf( scr_file, "  " ); }
361 
362         for ( i = 0; i < MAX_OPCODE; i++ )
363         {
364             if ( 'V' == OpList.ary[i].cType && var_value == OpList.ary[i].iValue )
365             {
366                 variable = OpList.ary[i].cName;
367                 break;
368             };
369         }
370 
371         fprintf( scr_file, "%s = ", variable );
372     }
373 
374     // Get the number of operands
375     scr_increment_exe( pself );
376     operand_count = pself->opcode;
377 
378     // Now run the operation
379     pstate->operationsum = 0;
380     for ( i = 0; i < operand_count && pself->exe_pos < pself->exe_end; i++ )
381     {
382         scr_increment_exe( pself );
383         scr_run_operand( pstate, pself );
384     }
385     if ( debug_scripts )
386     {
387         FILE * scr_file = ( NULL == debug_script_file ) ? stdout : debug_script_file;
388         fprintf( scr_file, " == %d \n", pstate->operationsum );
389     }
390 
391     // Save the results in the register that called the arithmetic
392     scr_set_operand( pstate, var_value );
393 
394     // go to the next opcode
395     scr_increment_exe( pself );
396 
397     return btrue;
398 }
399 
400 //--------------------------------------------------------------------------------------------
scr_run_function(script_state_t * pstate,ai_state_t * pself)401 Uint8 scr_run_function( script_state_t * pstate, ai_state_t * pself )
402 {
403     /// @details BB@> This is about half-way to what is needed for Lua integration
404 
405     // Mask out the indentation
406     Uint32 valuecode = pself->opcode & VALUE_BITS;
407 
408     // Assume that the function will pass, as most do
409     Uint8 returncode = btrue;
410     if ( MAX_OPCODE == valuecode )
411     {
412         log_message( "SCRIPT ERROR: scr_run_function() - model == %d, class name == \"%s\" - Unknown opcode found!\n", REF_TO_INT( script_error_model ), script_error_classname );
413         return bfalse;
414     }
415 
416     // debug stuff
417     if ( debug_scripts )
418     {
419         Uint32 i;
420         FILE * scr_file = ( NULL == debug_script_file ) ? stdout : debug_script_file;
421 
422         for ( i = 0; i < pself->indent; i++ ) { fprintf( scr_file,  "  " ); }
423 
424         for ( i = 0; i < MAX_OPCODE; i++ )
425         {
426             if ( 'F' == OpList.ary[i].cType && valuecode == OpList.ary[i].iValue )
427             {
428                 fprintf( scr_file,  "%s\n", OpList.ary[i].cName );
429                 break;
430             };
431         }
432     }
433 
434     if ( valuecode > SCRIPT_FUNCTIONS_COUNT )
435     {
436     }
437     else
438     {
439         PROFILE_RESET( script_function );
440 
441         PROFILE_BEGIN( script_function )
442         {
443             // Figure out which function to run
444             switch ( valuecode )
445             {
446                 case FIFSPAWNED: returncode = scr_Spawned( pstate, pself ); break;
447                 case FIFTIMEOUT: returncode = scr_TimeOut( pstate, pself ); break;
448                 case FIFATWAYPOINT: returncode = scr_AtWaypoint( pstate, pself ); break;
449                 case FIFATLASTWAYPOINT: returncode = scr_AtLastWaypoint( pstate, pself ); break;
450                 case FIFATTACKED: returncode = scr_Attacked( pstate, pself ); break;
451                 case FIFBUMPED: returncode = scr_Bumped( pstate, pself ); break;
452                 case FIFORDERED: returncode = scr_Ordered( pstate, pself ); break;
453                 case FIFCALLEDFORHELP: returncode = scr_CalledForHelp( pstate, pself ); break;
454                 case FSETCONTENT: returncode = scr_set_Content( pstate, pself ); break;
455                 case FIFKILLED: returncode = scr_Killed( pstate, pself ); break;
456                 case FIFTARGETKILLED: returncode = scr_TargetKilled( pstate, pself ); break;
457                 case FCLEARWAYPOINTS: returncode = scr_ClearWaypoints( pstate, pself ); break;
458                 case FADDWAYPOINT: returncode = scr_AddWaypoint( pstate, pself ); break;
459                 case FFINDPATH: returncode = scr_FindPath( pstate, pself ); break;
460                 case FCOMPASS: returncode = scr_Compass( pstate, pself ); break;
461                 case FGETTARGETARMORPRICE: returncode = scr_get_TargetArmorPrice( pstate, pself ); break;
462                 case FSETTIME: returncode = scr_set_Time( pstate, pself ); break;
463                 case FGETCONTENT: returncode = scr_get_Content( pstate, pself ); break;
464                 case FJOINTARGETTEAM: returncode = scr_JoinTargetTeam( pstate, pself ); break;
465                 case FSETTARGETTONEARBYENEMY: returncode = scr_set_TargetToNearbyEnemy( pstate, pself ); break;
466                 case FSETTARGETTOTARGETLEFTHAND: returncode = scr_set_TargetToTargetLeftHand( pstate, pself ); break;
467                 case FSETTARGETTOTARGETRIGHTHAND: returncode = scr_set_TargetToTargetRightHand( pstate, pself ); break;
468                 case FSETTARGETTOWHOEVERATTACKED: returncode = scr_set_TargetToWhoeverAttacked( pstate, pself ); break;
469                 case FSETTARGETTOWHOEVERBUMPED: returncode = scr_set_TargetToWhoeverBumped( pstate, pself ); break;
470                 case FSETTARGETTOWHOEVERCALLEDFORHELP: returncode = scr_set_TargetToWhoeverCalledForHelp( pstate, pself ); break;
471                 case FSETTARGETTOOLDTARGET: returncode = scr_set_TargetToOldTarget( pstate, pself ); break;
472                 case FSETTURNMODETOVELOCITY: returncode = scr_set_TurnModeToVelocity( pstate, pself ); break;
473                 case FSETTURNMODETOWATCH: returncode = scr_set_TurnModeToWatch( pstate, pself ); break;
474                 case FSETTURNMODETOSPIN: returncode = scr_set_TurnModeToSpin( pstate, pself ); break;
475                 case FSETBUMPHEIGHT: returncode = scr_set_BumpHeight( pstate, pself ); break;
476                 case FIFTARGETHASID: returncode = scr_TargetHasID( pstate, pself ); break;
477                 case FIFTARGETHASITEMID: returncode = scr_TargetHasItemID( pstate, pself ); break;
478                 case FIFTARGETHOLDINGITEMID: returncode = scr_TargetHoldingItemID( pstate, pself ); break;
479                 case FIFTARGETHASSKILLID: returncode = scr_TargetHasSkillID( pstate, pself ); break;
480                 case FELSE: returncode = scr_Else( pstate, pself ); break;
481                 case FRUN: returncode = scr_Run( pstate, pself ); break;
482                 case FWALK: returncode = scr_Walk( pstate, pself ); break;
483                 case FSNEAK: returncode = scr_Sneak( pstate, pself ); break;
484                 case FDOACTION: returncode = scr_DoAction( pstate, pself ); break;
485                 case FKEEPACTION: returncode = scr_KeepAction( pstate, pself ); break;
486                 case FISSUEORDER: returncode = scr_IssueOrder( pstate, pself ); break;
487                 case FDROPWEAPONS: returncode = scr_DropWeapons( pstate, pself ); break;
488                 case FTARGETDOACTION: returncode = scr_TargetDoAction( pstate, pself ); break;
489                 case FOPENPASSAGE: returncode = scr_OpenPassage( pstate, pself ); break;
490                 case FCLOSEPASSAGE: returncode = scr_ClosePassage( pstate, pself ); break;
491                 case FIFPASSAGEOPEN: returncode = scr_PassageOpen( pstate, pself ); break;
492                 case FGOPOOF: returncode = scr_GoPoof( pstate, pself ); break;
493                 case FCOSTTARGETITEMID: returncode = scr_CostTargetItemID( pstate, pself ); break;
494                 case FDOACTIONOVERRIDE: returncode = scr_DoActionOverride( pstate, pself ); break;
495                 case FIFHEALED: returncode = scr_Healed( pstate, pself ); break;
496                 case FSENDMESSAGE: returncode = scr_SendPlayerMessage( pstate, pself ); break;
497                 case FCALLFORHELP: returncode = scr_CallForHelp( pstate, pself ); break;
498                 case FADDIDSZ: returncode = scr_AddIDSZ( pstate, pself ); break;
499                 case FSETSTATE: returncode = scr_set_State( pstate, pself ); break;
500                 case FGETSTATE: returncode = scr_get_State( pstate, pself ); break;
501                 case FIFSTATEIS: returncode = scr_StateIs( pstate, pself ); break;
502                 case FIFTARGETCANOPENSTUFF: returncode = scr_TargetCanOpenStuff( pstate, pself ); break;
503                 case FIFGRABBED: returncode = scr_Grabbed( pstate, pself ); break;
504                 case FIFDROPPED: returncode = scr_Dropped( pstate, pself ); break;
505                 case FSETTARGETTOWHOEVERISHOLDING: returncode = scr_set_TargetToWhoeverIsHolding( pstate, pself ); break;
506                 case FDAMAGETARGET: returncode = scr_DamageTarget( pstate, pself ); break;
507                 case FIFXISLESSTHANY: returncode = scr_XIsLessThanY( pstate, pself ); break;
508                 case FSETWEATHERTIME: returncode = scr_set_WeatherTime( pstate, pself ); break;
509                 case FGETBUMPHEIGHT: returncode = scr_get_BumpHeight( pstate, pself ); break;
510                 case FIFREAFFIRMED: returncode = scr_Reaffirmed( pstate, pself ); break;
511                 case FUNKEEPACTION: returncode = scr_UnkeepAction( pstate, pself ); break;
512                 case FIFTARGETISONOTHERTEAM: returncode = scr_TargetIsOnOtherTeam( pstate, pself ); break;
513                 case FIFTARGETISONHATEDTEAM: returncode = scr_TargetIsOnHatedTeam( pstate, pself ); break;
514                 case FPRESSLATCHBUTTON: returncode = scr_PressLatchButton( pstate, pself ); break;
515                 case FSETTARGETTOTARGETOFLEADER: returncode = scr_set_TargetToTargetOfLeader( pstate, pself ); break;
516                 case FIFLEADERKILLED: returncode = scr_LeaderKilled( pstate, pself ); break;
517                 case FBECOMELEADER: returncode = scr_BecomeLeader( pstate, pself ); break;
518                 case FCHANGETARGETARMOR: returncode = scr_ChangeTargetArmor( pstate, pself ); break;
519                 case FGIVEMONEYTOTARGET: returncode = scr_GiveMoneyToTarget( pstate, pself ); break;
520                 case FDROPKEYS: returncode = scr_DropKeys( pstate, pself ); break;
521                 case FIFLEADERISALIVE: returncode = scr_LeaderIsAlive( pstate, pself ); break;
522                 case FIFTARGETISOLDTARGET: returncode = scr_TargetIsOldTarget( pstate, pself ); break;
523                 case FSETTARGETTOLEADER: returncode = scr_set_TargetToLeader( pstate, pself ); break;
524                 case FSPAWNCHARACTER: returncode = scr_SpawnCharacter( pstate, pself ); break;
525                 case FRESPAWNCHARACTER: returncode = scr_RespawnCharacter( pstate, pself ); break;
526                 case FCHANGETILE: returncode = scr_ChangeTile( pstate, pself ); break;
527                 case FIFUSED: returncode = scr_Used( pstate, pself ); break;
528                 case FDROPMONEY: returncode = scr_DropMoney( pstate, pself ); break;
529                 case FSETOLDTARGET: returncode = scr_set_OldTarget( pstate, pself ); break;
530                 case FDETACHFROMHOLDER: returncode = scr_DetachFromHolder( pstate, pself ); break;
531                 case FIFTARGETHASVULNERABILITYID: returncode = scr_TargetHasVulnerabilityID( pstate, pself ); break;
532                 case FCLEANUP: returncode = scr_CleanUp( pstate, pself ); break;
533                 case FIFCLEANEDUP: returncode = scr_CleanedUp( pstate, pself ); break;
534                 case FIFSITTING: returncode = scr_Sitting( pstate, pself ); break;
535                 case FIFTARGETISHURT: returncode = scr_TargetIsHurt( pstate, pself ); break;
536                 case FIFTARGETISAPLAYER: returncode = scr_TargetIsAPlayer( pstate, pself ); break;
537                 case FPLAYSOUND: returncode = scr_PlaySound( pstate, pself ); break;
538                 case FSPAWNPARTICLE: returncode = scr_SpawnParticle( pstate, pself ); break;
539                 case FIFTARGETISALIVE: returncode = scr_TargetIsAlive( pstate, pself ); break;
540                 case FSTOP: returncode = scr_Stop( pstate, pself ); break;
541                 case FDISAFFIRMCHARACTER: returncode = scr_DisaffirmCharacter( pstate, pself ); break;
542                 case FREAFFIRMCHARACTER: returncode = scr_ReaffirmCharacter( pstate, pself ); break;
543                 case FIFTARGETISSELF: returncode = scr_TargetIsSelf( pstate, pself ); break;
544                 case FIFTARGETISMALE: returncode = scr_TargetIsMale( pstate, pself ); break;
545                 case FIFTARGETISFEMALE: returncode = scr_TargetIsFemale( pstate, pself ); break;
546                 case FSETTARGETTOSELF: returncode = scr_set_TargetToSelf( pstate, pself ); break;
547                 case FSETTARGETTORIDER: returncode = scr_set_TargetToRider( pstate, pself ); break;
548                 case FGETATTACKTURN: returncode = scr_get_AttackTurn( pstate, pself ); break;
549                 case FGETDAMAGETYPE: returncode = scr_get_DamageType( pstate, pself ); break;
550                 case FBECOMESPELL: returncode = scr_BecomeSpell( pstate, pself ); break;
551                 case FBECOMESPELLBOOK: returncode = scr_BecomeSpellbook( pstate, pself ); break;
552                 case FIFSCOREDAHIT: returncode = scr_ScoredAHit( pstate, pself ); break;
553                 case FIFDISAFFIRMED: returncode = scr_Disaffirmed( pstate, pself ); break;
554                 case FTRANSLATEORDER: returncode = scr_TranslateOrder( pstate, pself ); break;
555                 case FSETTARGETTOWHOEVERWASHIT: returncode = scr_set_TargetToWhoeverWasHit( pstate, pself ); break;
556                 case FSETTARGETTOWIDEENEMY: returncode = scr_set_TargetToWideEnemy( pstate, pself ); break;
557                 case FIFCHANGED: returncode = scr_Changed( pstate, pself ); break;
558                 case FIFINWATER: returncode = scr_InWater( pstate, pself ); break;
559                 case FIFBORED: returncode = scr_Bored( pstate, pself ); break;
560                 case FIFTOOMUCHBAGGAGE: returncode = scr_TooMuchBaggage( pstate, pself ); break;
561                 case FIFGROGGED: returncode = scr_Grogged( pstate, pself ); break;
562                 case FIFDAZED: returncode = scr_Dazed( pstate, pself ); break;
563                 case FIFTARGETHASSPECIALID: returncode = scr_TargetHasSpecialID( pstate, pself ); break;
564                 case FPRESSTARGETLATCHBUTTON: returncode = scr_PressTargetLatchButton( pstate, pself ); break;
565                 case FIFINVISIBLE: returncode = scr_Invisible( pstate, pself ); break;
566                 case FIFARMORIS: returncode = scr_ArmorIs( pstate, pself ); break;
567                 case FGETTARGETGROGTIME: returncode = scr_get_TargetGrogTime( pstate, pself ); break;
568                 case FGETTARGETDAZETIME: returncode = scr_get_TargetDazeTime( pstate, pself ); break;
569                 case FSETDAMAGETYPE: returncode = scr_set_DamageType( pstate, pself ); break;
570                 case FSETWATERLEVEL: returncode = scr_set_WaterLevel( pstate, pself ); break;
571                 case FENCHANTTARGET: returncode = scr_EnchantTarget( pstate, pself ); break;
572                 case FENCHANTCHILD: returncode = scr_EnchantChild( pstate, pself ); break;
573                 case FTELEPORTTARGET: returncode = scr_TeleportTarget( pstate, pself ); break;
574                 case FGIVEEXPERIENCETOTARGET: returncode = scr_GiveExperienceToTarget( pstate, pself ); break;
575                 case FINCREASEAMMO: returncode = scr_IncreaseAmmo( pstate, pself ); break;
576                 case FUNKURSETARGET: returncode = scr_UnkurseTarget( pstate, pself ); break;
577                 case FGIVEEXPERIENCETOTARGETTEAM: returncode = scr_GiveExperienceToTargetTeam( pstate, pself ); break;
578                 case FIFUNARMED: returncode = scr_Unarmed( pstate, pself ); break;
579                 case FRESTOCKTARGETAMMOIDALL: returncode = scr_RestockTargetAmmoIDAll( pstate, pself ); break;
580                 case FRESTOCKTARGETAMMOIDFIRST: returncode = scr_RestockTargetAmmoIDFirst( pstate, pself ); break;
581                 case FFLASHTARGET: returncode = scr_FlashTarget( pstate, pself ); break;
582                 case FSETREDSHIFT: returncode = scr_set_RedShift( pstate, pself ); break;
583                 case FSETGREENSHIFT: returncode = scr_set_GreenShift( pstate, pself ); break;
584                 case FSETBLUESHIFT: returncode = scr_set_BlueShift( pstate, pself ); break;
585                 case FSETLIGHT: returncode = scr_set_Light( pstate, pself ); break;
586                 case FSETALPHA: returncode = scr_set_Alpha( pstate, pself ); break;
587                 case FIFHITFROMBEHIND: returncode = scr_HitFromBehind( pstate, pself ); break;
588                 case FIFHITFROMFRONT: returncode = scr_HitFromFront( pstate, pself ); break;
589                 case FIFHITFROMLEFT: returncode = scr_HitFromLeft( pstate, pself ); break;
590                 case FIFHITFROMRIGHT: returncode = scr_HitFromRight( pstate, pself ); break;
591                 case FIFTARGETISONSAMETEAM: returncode = scr_TargetIsOnSameTeam( pstate, pself ); break;
592                 case FKILLTARGET: returncode = scr_KillTarget( pstate, pself ); break;
593                 case FUNDOENCHANT: returncode = scr_UndoEnchant( pstate, pself ); break;
594                 case FGETWATERLEVEL: returncode = scr_get_WaterLevel( pstate, pself ); break;
595                 case FCOSTTARGETMANA: returncode = scr_CostTargetMana( pstate, pself ); break;
596                 case FIFTARGETHASANYID: returncode = scr_TargetHasAnyID( pstate, pself ); break;
597                 case FSETBUMPSIZE: returncode = scr_set_BumpSize( pstate, pself ); break;
598                 case FIFNOTDROPPED: returncode = scr_NotDropped( pstate, pself ); break;
599                 case FIFYISLESSTHANX: returncode = scr_YIsLessThanX( pstate, pself ); break;
600                 case FSETFLYHEIGHT: returncode = scr_set_FlyHeight( pstate, pself ); break;
601                 case FIFBLOCKED: returncode = scr_Blocked( pstate, pself ); break;
602                 case FIFTARGETISDEFENDING: returncode = scr_TargetIsDefending( pstate, pself ); break;
603                 case FIFTARGETISATTACKING: returncode = scr_TargetIsAttacking( pstate, pself ); break;
604                 case FIFSTATEIS0: returncode = scr_StateIs0( pstate, pself ); break;
605                 case FIFSTATEIS1: returncode = scr_StateIs1( pstate, pself ); break;
606                 case FIFSTATEIS2: returncode = scr_StateIs2( pstate, pself ); break;
607                 case FIFSTATEIS3: returncode = scr_StateIs3( pstate, pself ); break;
608                 case FIFSTATEIS4: returncode = scr_StateIs4( pstate, pself ); break;
609                 case FIFSTATEIS5: returncode = scr_StateIs5( pstate, pself ); break;
610                 case FIFSTATEIS6: returncode = scr_StateIs6( pstate, pself ); break;
611                 case FIFSTATEIS7: returncode = scr_StateIs7( pstate, pself ); break;
612                 case FIFCONTENTIS: returncode = scr_ContentIs( pstate, pself ); break;
613                 case FSETTURNMODETOWATCHTARGET: returncode = scr_set_TurnModeToWatchTarget( pstate, pself ); break;
614                 case FIFSTATEISNOT: returncode = scr_StateIsNot( pstate, pself ); break;
615                 case FIFXISEQUALTOY: returncode = scr_XIsEqualToY( pstate, pself ); break;
616                 case FDEBUGMESSAGE: returncode = scr_DebugMessage( pstate, pself ); break;
617                 case FBLACKTARGET: returncode = scr_BlackTarget( pstate, pself ); break;
618                 case FSENDMESSAGENEAR: returncode = scr_SendMessageNear( pstate, pself ); break;
619                 case FIFHITGROUND: returncode = scr_HitGround( pstate, pself ); break;
620                 case FIFNAMEISKNOWN: returncode = scr_NameIsKnown( pstate, pself ); break;
621                 case FIFUSAGEISKNOWN: returncode = scr_UsageIsKnown( pstate, pself ); break;
622                 case FIFHOLDINGITEMID: returncode = scr_HoldingItemID( pstate, pself ); break;
623                 case FIFHOLDINGRANGEDWEAPON: returncode = scr_HoldingRangedWeapon( pstate, pself ); break;
624                 case FIFHOLDINGMELEEWEAPON: returncode = scr_HoldingMeleeWeapon( pstate, pself ); break;
625                 case FIFHOLDINGSHIELD: returncode = scr_HoldingShield( pstate, pself ); break;
626                 case FIFKURSED: returncode = scr_Kursed( pstate, pself ); break;
627                 case FIFTARGETISKURSED: returncode = scr_TargetIsKursed( pstate, pself ); break;
628                 case FIFTARGETISDRESSEDUP: returncode = scr_TargetIsDressedUp( pstate, pself ); break;
629                 case FIFOVERWATER: returncode = scr_OverWater( pstate, pself ); break;
630                 case FIFTHROWN: returncode = scr_Thrown( pstate, pself ); break;
631                 case FMAKENAMEKNOWN: returncode = scr_MakeNameKnown( pstate, pself ); break;
632                 case FMAKEUSAGEKNOWN: returncode = scr_MakeUsageKnown( pstate, pself ); break;
633                 case FSTOPTARGETMOVEMENT: returncode = scr_StopTargetMovement( pstate, pself ); break;
634                 case FSETXY: returncode = scr_set_XY( pstate, pself ); break;
635                 case FGETXY: returncode = scr_get_XY( pstate, pself ); break;
636                 case FADDXY: returncode = scr_AddXY( pstate, pself ); break;
637                 case FMAKEAMMOKNOWN: returncode = scr_MakeAmmoKnown( pstate, pself ); break;
638                 case FSPAWNATTACHEDPARTICLE: returncode = scr_SpawnAttachedParticle( pstate, pself ); break;
639                 case FSPAWNEXACTPARTICLE: returncode = scr_SpawnExactParticle( pstate, pself ); break;
640                 case FACCELERATETARGET: returncode = scr_AccelerateTarget( pstate, pself ); break;
641                 case FIFDISTANCEISMORETHANTURN: returncode = scr_distanceIsMoreThanTurn( pstate, pself ); break;
642                 case FIFCRUSHED: returncode = scr_Crushed( pstate, pself ); break;
643                 case FMAKECRUSHVALID: returncode = scr_MakeCrushValid( pstate, pself ); break;
644                 case FSETTARGETTOLOWESTTARGET: returncode = scr_set_TargetToLowestTarget( pstate, pself ); break;
645                 case FIFNOTPUTAWAY: returncode = scr_NotPutAway( pstate, pself ); break;
646                 case FIFTAKENOUT: returncode = scr_TakenOut( pstate, pself ); break;
647                 case FIFAMMOOUT: returncode = scr_AmmoOut( pstate, pself ); break;
648                 case FPLAYSOUNDLOOPED: returncode = scr_PlaySoundLooped( pstate, pself ); break;
649                 case FSTOPSOUND: returncode = scr_StopSound( pstate, pself ); break;
650                 case FHEALSELF: returncode = scr_HealSelf( pstate, pself ); break;
651                 case FEQUIP: returncode = scr_Equip( pstate, pself ); break;
652                 case FIFTARGETHASITEMIDEQUIPPED: returncode = scr_TargetHasItemIDEquipped( pstate, pself ); break;
653                 case FSETOWNERTOTARGET: returncode = scr_set_OwnerToTarget( pstate, pself ); break;
654                 case FSETTARGETTOOWNER: returncode = scr_set_TargetToOwner( pstate, pself ); break;
655                 case FSETFRAME: returncode = scr_set_Frame( pstate, pself ); break;
656                 case FBREAKPASSAGE: returncode = scr_BreakPassage( pstate, pself ); break;
657                 case FSETRELOADTIME: returncode = scr_set_ReloadTime( pstate, pself ); break;
658                 case FSETTARGETTOWIDEBLAHID: returncode = scr_set_TargetToWideBlahID( pstate, pself ); break;
659                 case FPOOFTARGET: returncode = scr_PoofTarget( pstate, pself ); break;
660                 case FCHILDDOACTIONOVERRIDE: returncode = scr_ChildDoActionOverride( pstate, pself ); break;
661                 case FSPAWNPOOF: returncode = scr_SpawnPoof( pstate, pself ); break;
662                 case FSETSPEEDPERCENT: returncode = scr_set_SpeedPercent( pstate, pself ); break;
663                 case FSETCHILDSTATE: returncode = scr_set_ChildState( pstate, pself ); break;
664                 case FSPAWNATTACHEDSIZEDPARTICLE: returncode = scr_SpawnAttachedSizedParticle( pstate, pself ); break;
665                 case FCHANGEARMOR: returncode = scr_ChangeArmor( pstate, pself ); break;
666                 case FSHOWTIMER: returncode = scr_ShowTimer( pstate, pself ); break;
667                 case FIFFACINGTARGET: returncode = scr_FacingTarget( pstate, pself ); break;
668                 case FPLAYSOUNDVOLUME: returncode = scr_PlaySoundVolume( pstate, pself ); break;
669                 case FSPAWNATTACHEDFACEDPARTICLE: returncode = scr_SpawnAttachedFacedParticle( pstate, pself ); break;
670                 case FIFSTATEISODD: returncode = scr_StateIsOdd( pstate, pself ); break;
671                 case FSETTARGETTODISTANTENEMY: returncode = scr_set_TargetToDistantEnemy( pstate, pself ); break;
672                 case FTELEPORT: returncode = scr_Teleport( pstate, pself ); break;
673                 case FGIVESTRENGTHTOTARGET: returncode = scr_GiveStrengthToTarget( pstate, pself ); break;
674                 case FGIVEWISDOMTOTARGET: returncode = scr_GiveWisdomToTarget( pstate, pself ); break;
675                 case FGIVEINTELLIGENCETOTARGET: returncode = scr_GiveIntelligenceToTarget( pstate, pself ); break;
676                 case FGIVEDEXTERITYTOTARGET: returncode = scr_GiveDexterityToTarget( pstate, pself ); break;
677                 case FGIVELIFETOTARGET: returncode = scr_GiveLifeToTarget( pstate, pself ); break;
678                 case FGIVEMANATOTARGET: returncode = scr_GiveManaToTarget( pstate, pself ); break;
679                 case FSHOWMAP: returncode = scr_ShowMap( pstate, pself ); break;
680                 case FSHOWYOUAREHERE: returncode = scr_ShowYouAreHere( pstate, pself ); break;
681                 case FSHOWBLIPXY: returncode = scr_ShowBlipXY( pstate, pself ); break;
682                 case FHEALTARGET: returncode = scr_HealTarget( pstate, pself ); break;
683                 case FPUMPTARGET: returncode = scr_PumpTarget( pstate, pself ); break;
684                 case FCOSTAMMO: returncode = scr_CostAmmo( pstate, pself ); break;
685                 case FMAKESIMILARNAMESKNOWN: returncode = scr_MakeSimilarNamesKnown( pstate, pself ); break;
686                 case FSPAWNATTACHEDHOLDERPARTICLE: returncode = scr_SpawnAttachedHolderParticle( pstate, pself ); break;
687                 case FSETTARGETRELOADTIME: returncode = scr_set_TargetReloadTime( pstate, pself ); break;
688                 case FSETFOGLEVEL: returncode = scr_set_FogLevel( pstate, pself ); break;
689                 case FGETFOGLEVEL: returncode = scr_get_FogLevel( pstate, pself ); break;
690                 case FSETFOGTAD: returncode = scr_set_FogTAD( pstate, pself ); break;
691                 case FSETFOGBOTTOMLEVEL: returncode = scr_set_FogBottomLevel( pstate, pself ); break;
692                 case FGETFOGBOTTOMLEVEL: returncode = scr_get_FogBottomLevel( pstate, pself ); break;
693                 case FCORRECTACTIONFORHAND: returncode = scr_CorrectActionForHand( pstate, pself ); break;
694                 case FIFTARGETISMOUNTED: returncode = scr_TargetIsMounted( pstate, pself ); break;
695                 case FSPARKLEICON: returncode = scr_SparkleIcon( pstate, pself ); break;
696                 case FUNSPARKLEICON: returncode = scr_UnsparkleIcon( pstate, pself ); break;
697                 case FGETTILEXY: returncode = scr_get_TileXY( pstate, pself ); break;
698                 case FSETTILEXY: returncode = scr_set_TileXY( pstate, pself ); break;
699                 case FSETSHADOWSIZE: returncode = scr_set_ShadowSize( pstate, pself ); break;
700                 case FORDERTARGET: returncode = scr_OrderTarget( pstate, pself ); break;
701                 case FSETTARGETTOWHOEVERISINPASSAGE: returncode = scr_set_TargetToWhoeverIsInPassage( pstate, pself ); break;
702                 case FIFCHARACTERWASABOOK: returncode = scr_CharacterWasABook( pstate, pself ); break;
703                 case FSETENCHANTBOOSTVALUES: returncode = scr_set_EnchantBoostValues( pstate, pself ); break;
704                 case FSPAWNCHARACTERXYZ: returncode = scr_SpawnCharacterXYZ( pstate, pself ); break;
705                 case FSPAWNEXACTCHARACTERXYZ: returncode = scr_SpawnExactCharacterXYZ( pstate, pself ); break;
706                 case FCHANGETARGETCLASS: returncode = scr_ChangeTargetClass( pstate, pself ); break;
707                 case FPLAYFULLSOUND: returncode = scr_PlayFullSound( pstate, pself ); break;
708                 case FSPAWNEXACTCHASEPARTICLE: returncode = scr_SpawnExactChaseParticle( pstate, pself ); break;
709                 case FCREATEORDER: returncode = scr_CreateOrder( pstate, pself ); break;
710                 case FORDERSPECIALID: returncode = scr_OrderSpecialID( pstate, pself ); break;
711                 case FUNKURSETARGETINVENTORY: returncode = scr_UnkurseTargetInventory( pstate, pself ); break;
712                 case FIFTARGETISSNEAKING: returncode = scr_TargetIsSneaking( pstate, pself ); break;
713                 case FDROPITEMS: returncode = scr_DropItems( pstate, pself ); break;
714                 case FRESPAWNTARGET: returncode = scr_RespawnTarget( pstate, pself ); break;
715                 case FTARGETDOACTIONSETFRAME: returncode = scr_TargetDoActionSetFrame( pstate, pself ); break;
716                 case FIFTARGETCANSEEINVISIBLE: returncode = scr_TargetCanSeeInvisible( pstate, pself ); break;
717                 case FSETTARGETTONEARESTBLAHID: returncode = scr_set_TargetToNearestBlahID( pstate, pself ); break;
718                 case FSETTARGETTONEARESTENEMY: returncode = scr_set_TargetToNearestEnemy( pstate, pself ); break;
719                 case FSETTARGETTONEARESTFRIEND: returncode = scr_set_TargetToNearestFriend( pstate, pself ); break;
720                 case FSETTARGETTONEARESTLIFEFORM: returncode = scr_set_TargetToNearestLifeform( pstate, pself ); break;
721                 case FFLASHPASSAGE: returncode = scr_FlashPassage( pstate, pself ); break;
722                 case FFINDTILEINPASSAGE: returncode = scr_FindTileInPassage( pstate, pself ); break;
723                 case FIFHELDINLEFTHAND: returncode = scr_HeldInLeftHand( pstate, pself ); break;
724                 case FNOTANITEM: returncode = scr_NotAnItem( pstate, pself ); break;
725                 case FSETCHILDAMMO: returncode = scr_set_ChildAmmo( pstate, pself ); break;
726                 case FIFHITVULNERABLE: returncode = scr_HitVulnerable( pstate, pself ); break;
727                 case FIFTARGETISFLYING: returncode = scr_TargetIsFlying( pstate, pself ); break;
728                 case FIDENTIFYTARGET: returncode = scr_IdentifyTarget( pstate, pself ); break;
729                 case FBEATMODULE: returncode = scr_BeatModule( pstate, pself ); break;
730                 case FENDMODULE: returncode = scr_EndModule( pstate, pself ); break;
731                 case FDISABLEEXPORT: returncode = scr_DisableExport( pstate, pself ); break;
732                 case FENABLEEXPORT: returncode = scr_EnableExport( pstate, pself ); break;
733                 case FGETTARGETSTATE: returncode = scr_get_TargetState( pstate, pself ); break;
734                 case FIFEQUIPPED: returncode = scr_Equipped( pstate, pself ); break;
735                 case FDROPTARGETMONEY: returncode = scr_DropTargetMoney( pstate, pself ); break;
736                 case FGETTARGETCONTENT: returncode = scr_get_TargetContent( pstate, pself ); break;
737                 case FDROPTARGETKEYS: returncode = scr_DropTargetKeys( pstate, pself ); break;
738                 case FJOINTEAM: returncode = scr_JoinTeam( pstate, pself ); break;
739                 case FTARGETJOINTEAM: returncode = scr_TargetJoinTeam( pstate, pself ); break;
740                 case FCLEARMUSICPASSAGE: returncode = scr_ClearMusicPassage( pstate, pself ); break;
741                 case FCLEARENDMESSAGE: returncode = scr_ClearEndMessage( pstate, pself ); break;
742                 case FADDENDMESSAGE: returncode = scr_AddEndMessage( pstate, pself ); break;
743                 case FPLAYMUSIC: returncode = scr_PlayMusic( pstate, pself ); break;
744                 case FSETMUSICPASSAGE: returncode = scr_set_MusicPassage( pstate, pself ); break;
745                 case FMAKECRUSHINVALID: returncode = scr_MakeCrushInvalid( pstate, pself ); break;
746                 case FSTOPMUSIC: returncode = scr_StopMusic( pstate, pself ); break;
747                 case FFLASHVARIABLE: returncode = scr_FlashVariable( pstate, pself ); break;
748                 case FACCELERATEUP: returncode = scr_AccelerateUp( pstate, pself ); break;
749                 case FFLASHVARIABLEHEIGHT: returncode = scr_FlashVariableHeight( pstate, pself ); break;
750                 case FSETDAMAGETIME: returncode = scr_set_DamageTime( pstate, pself ); break;
751                 case FIFSTATEIS8: returncode = scr_StateIs8( pstate, pself ); break;
752                 case FIFSTATEIS9: returncode = scr_StateIs9( pstate, pself ); break;
753                 case FIFSTATEIS10: returncode = scr_StateIs10( pstate, pself ); break;
754                 case FIFSTATEIS11: returncode = scr_StateIs11( pstate, pself ); break;
755                 case FIFSTATEIS12: returncode = scr_StateIs12( pstate, pself ); break;
756                 case FIFSTATEIS13: returncode = scr_StateIs13( pstate, pself ); break;
757                 case FIFSTATEIS14: returncode = scr_StateIs14( pstate, pself ); break;
758                 case FIFSTATEIS15: returncode = scr_StateIs15( pstate, pself ); break;
759                 case FIFTARGETISAMOUNT: returncode = scr_TargetIsAMount( pstate, pself ); break;
760                 case FIFTARGETISAPLATFORM: returncode = scr_TargetIsAPlatform( pstate, pself ); break;
761                 case FADDSTAT: returncode = scr_AddStat( pstate, pself ); break;
762                 case FDISENCHANTTARGET: returncode = scr_DisenchantTarget( pstate, pself ); break;
763                 case FDISENCHANTALL: returncode = scr_DisenchantAll( pstate, pself ); break;
764                 case FSETVOLUMENEARESTTEAMMATE: returncode = scr_set_VolumeNearestTeammate( pstate, pself ); break;
765                 case FADDSHOPPASSAGE: returncode = scr_AddShopPassage( pstate, pself ); break;
766                 case FTARGETPAYFORARMOR: returncode = scr_TargetPayForArmor( pstate, pself ); break;
767                 case FJOINEVILTEAM: returncode = scr_JoinEvilTeam( pstate, pself ); break;
768                 case FJOINNULLTEAM: returncode = scr_JoinNullTeam( pstate, pself ); break;
769                 case FJOINGOODTEAM: returncode = scr_JoinGoodTeam( pstate, pself ); break;
770                 case FPITSKILL: returncode = scr_PitsKill( pstate, pself ); break;
771                 case FSETTARGETTOPASSAGEID: returncode = scr_set_TargetToPassageID( pstate, pself ); break;
772                 case FMAKENAMEUNKNOWN: returncode = scr_MakeNameUnknown( pstate, pself ); break;
773                 case FSPAWNEXACTPARTICLEENDSPAWN: returncode = scr_SpawnExactParticleEndSpawn( pstate, pself ); break;
774                 case FSPAWNPOOFSPEEDSPACINGDAMAGE: returncode = scr_SpawnPoofSpeedSpacingDamage( pstate, pself ); break;
775                 case FGIVEEXPERIENCETOGOODTEAM: returncode = scr_GiveExperienceToGoodTeam( pstate, pself ); break;
776                 case FDONOTHING: returncode = scr_DoNothing( pstate, pself ); break;
777                 case FGROGTARGET: returncode = scr_GrogTarget( pstate, pself ); break;
778                 case FDAZETARGET: returncode = scr_DazeTarget( pstate, pself ); break;
779                 case FENABLERESPAWN: returncode = scr_EnableRespawn( pstate, pself ); break;
780                 case FDISABLERESPAWN: returncode = scr_DisableRespawn( pstate, pself ); break;
781                 case FDISPELTARGETENCHANTID: returncode = scr_DispelTargetEnchantID( pstate, pself ); break;
782                 case FIFHOLDERBLOCKED: returncode = scr_HolderBlocked( pstate, pself ); break;
783                     // case FGETSKILLLEVEL: returncode = scr_get_SkillLevel( pstate, pself ); break;
784                 case FIFTARGETHASNOTFULLMANA: returncode = scr_TargetHasNotFullMana( pstate, pself ); break;
785                 case FENABLELISTENSKILL: returncode = scr_EnableListenSkill( pstate, pself ); break;
786                 case FSETTARGETTOLASTITEMUSED: returncode = scr_set_TargetToLastItemUsed( pstate, pself ); break;
787                 case FFOLLOWLINK: returncode = scr_FollowLink( pstate, pself ); break;
788                 case FIFOPERATORISLINUX: returncode = scr_OperatorIsLinux( pstate, pself ); break;
789                 case FIFTARGETISAWEAPON: returncode = scr_TargetIsAWeapon( pstate, pself ); break;
790                 case FIFSOMEONEISSTEALING: returncode = scr_SomeoneIsStealing( pstate, pself ); break;
791                 case FIFTARGETISASPELL: returncode = scr_TargetIsASpell( pstate, pself ); break;
792                 case FIFBACKSTABBED: returncode = scr_Backstabbed( pstate, pself ); break;
793                 case FGETTARGETDAMAGETYPE: returncode = scr_get_TargetDamageType( pstate, pself ); break;
794                 case FADDQUEST: returncode = scr_AddQuest( pstate, pself ); break;
795                 case FBEATQUESTALLPLAYERS: returncode = scr_BeatQuestAllPlayers( pstate, pself ); break;
796                 case FIFTARGETHASQUEST: returncode = scr_TargetHasQuest( pstate, pself ); break;
797                 case FSETQUESTLEVEL: returncode = scr_set_QuestLevel( pstate, pself ); break;
798                 case FADDQUESTALLPLAYERS: returncode = scr_AddQuestAllPlayers( pstate, pself ); break;
799                 case FADDBLIPALLENEMIES: returncode = scr_AddBlipAllEnemies( pstate, pself ); break;
800                 case FPITSFALL: returncode = scr_PitsFall( pstate, pself ); break;
801                 case FIFTARGETISOWNER: returncode = scr_TargetIsOwner( pstate, pself ); break;
802                 case FEND: returncode = scr_End( pstate, pself ); break;
803 
804                 case FSETSPEECH:           returncode = scr_set_Speech( pstate, pself );           break;
805                 case FSETMOVESPEECH:       returncode = scr_set_MoveSpeech( pstate, pself );       break;
806                 case FSETSECONDMOVESPEECH: returncode = scr_set_SecondMoveSpeech( pstate, pself ); break;
807                 case FSETATTACKSPEECH:     returncode = scr_set_AttackSpeech( pstate, pself );     break;
808                 case FSETASSISTSPEECH:     returncode = scr_set_AssistSpeech( pstate, pself );     break;
809                 case FSETTERRAINSPEECH:    returncode = scr_set_TerrainSpeech( pstate, pself );    break;
810                 case FSETSELECTSPEECH:     returncode = scr_set_SelectSpeech( pstate, pself );     break;
811 
812                 case FTAKEPICTURE:           returncode = scr_TakePicture( pstate, pself );         break;
813                 case FIFOPERATORISMACINTOSH: returncode = scr_OperatorIsMacintosh( pstate, pself ); break;
814                 case FIFMODULEHASIDSZ:       returncode = scr_ModuleHasIDSZ( pstate, pself );       break;
815                 case FMORPHTOTARGET:         returncode = scr_MorphToTarget( pstate, pself );       break;
816                 case FGIVEMANAFLOWTOTARGET:  returncode = scr_GiveManaFlowToTarget( pstate, pself ); break;
817                 case FGIVEMANARETURNTOTARGET:returncode = scr_GiveManaReturnToTarget( pstate, pself ); break;
818                 case FSETMONEY:              returncode = scr_set_Money( pstate, pself );           break;
819                 case FIFTARGETCANSEEKURSES:  returncode = scr_TargetCanSeeKurses( pstate, pself );  break;
820                 case FSPAWNATTACHEDCHARACTER:returncode = scr_SpawnAttachedCharacter( pstate, pself ); break;
821                 case FKURSETARGET:           returncode = scr_KurseTarget( pstate, pself );            break;
822                 case FSETCHILDCONTENT:       returncode = scr_set_ChildContent( pstate, pself );    break;
823                 case FSETTARGETTOCHILD:      returncode = scr_set_TargetToChild( pstate, pself );   break;
824                 case FSETDAMAGETHRESHOLD:     returncode = scr_set_DamageThreshold( pstate, pself );   break;
825                 case FACCELERATETARGETUP:    returncode = scr_AccelerateTargetUp( pstate, pself ); break;
826                 case FSETTARGETAMMO:         returncode = scr_set_TargetAmmo( pstate, pself ); break;
827                 case FENABLEINVICTUS:        returncode = scr_EnableInvictus( pstate, pself ); break;
828                 case FDISABLEINVICTUS:       returncode = scr_DisableInvictus( pstate, pself ); break;
829                 case FTARGETDAMAGESELF:      returncode = scr_TargetDamageSelf( pstate, pself ); break;
830                 case FSETTARGETSIZE:         returncode = scr_SetTargetSize( pstate, pself ); break;
831                 case FIFTARGETISFACINGSELF:  returncode = scr_TargetIsFacingSelf( pstate, pself ); break;
832                 case FDRAWBILLBOARD:         returncode = scr_DrawBillboard( pstate, pself ); break;
833                 case FSETTARGETTOFIRSTBLAHINPASSAGE: returncode = scr_set_TargetToBlahInPassage( pstate, pself ); break;
834 
835                 case FIFLEVELUP:            returncode = scr_LevelUp( pstate, pself ); break;
836                 case FGIVESKILLTOTARGET:    returncode = scr_GiveSkillToTarget( pstate, pself ); break;
837 
838                     // if none of the above, skip the line and log an error
839                 default:
840                     log_message( "SCRIPT ERROR: scr_run_function() - ai script %d - unhandled script function %d\n", pself->type, valuecode );
841                     returncode = bfalse;
842                     break;
843             }
844 
845         }
846         PROFILE_END2( script_function );
847 
848         _script_function_calls[valuecode] += 1;
849         _script_function_times[valuecode] += clktime_script_function;
850     }
851 
852     return returncode;
853 }
854 
855 //--------------------------------------------------------------------------------------------
scr_set_operand(script_state_t * pstate,Uint8 variable)856 void scr_set_operand( script_state_t * pstate, Uint8 variable )
857 {
858     /// @details ZZ@> This function sets one of the tmp* values for scripted AI
859     switch ( variable )
860     {
861         case VARTMPX:
862             pstate->x = pstate->operationsum;
863             break;
864 
865         case VARTMPY:
866             pstate->y = pstate->operationsum;
867             break;
868 
869         case VARTMPDISTANCE:
870             pstate->distance = pstate->operationsum;
871             break;
872 
873         case VARTMPTURN:
874             pstate->turn = pstate->operationsum;
875             break;
876 
877         case VARTMPARGUMENT:
878             pstate->argument = pstate->operationsum;
879             break;
880 
881         default:
882             log_warning( "scr_set_operand() - cannot assign a number to index %d", variable );
883             break;
884     }
885 }
886 
887 //--------------------------------------------------------------------------------------------
scr_run_operand(script_state_t * pstate,ai_state_t * pself)888 void scr_run_operand( script_state_t * pstate, ai_state_t * pself )
889 {
890     /// @details ZZ@> This function does the scripted arithmetic in OPERATOR, OPERAND pairs
891 
892     const char * varname, * op;
893 
894     STRING buffer = EMPTY_CSTR;
895     Uint8  variable;
896     Uint8  operation;
897 
898     Uint32 iTmp;
899 
900     chr_t * pchr = NULL, * ptarget = NULL, * powner = NULL;
901 
902     if ( !DEFINED_CHR( pself->index ) ) return;
903     pchr = ChrList.lst + pself->index;
904 
905     if ( DEFINED_CHR( pself->target ) )
906     {
907         ptarget = ChrList.lst + pself->target;
908     }
909 
910     if ( DEFINED_CHR( pself->owner ) )
911     {
912         powner = ChrList.lst + pself->owner;
913     }
914 
915     // get the operator
916     iTmp      = 0;
917     varname   = buffer;
918     operation = GET_DATA_BITS( pself->opcode );
919     if ( HAS_SOME_BITS( pself->opcode, FUNCTION_BIT ) )
920     {
921         // Get the working opcode from a constant, constants are all but high 5 bits
922         iTmp = pself->opcode & VALUE_BITS;
923         if ( debug_scripts ) snprintf( buffer, SDL_arraysize( buffer ), "%d", iTmp );
924     }
925     else
926     {
927         // Get the variable opcode from a register
928         variable = pself->opcode & VALUE_BITS;
929 
930         switch ( variable )
931         {
932             case VARTMPX:
933                 varname = "TMPX";
934                 iTmp = pstate->x;
935                 break;
936 
937             case VARTMPY:
938                 varname = "TMPY";
939                 iTmp = pstate->y;
940                 break;
941 
942             case VARTMPDISTANCE:
943                 varname = "TMPDISTANCE";
944                 iTmp = pstate->distance;
945                 break;
946 
947             case VARTMPTURN:
948                 varname = "TMPTURN";
949                 iTmp = pstate->turn;
950                 break;
951 
952             case VARTMPARGUMENT:
953                 varname = "TMPARGUMENT";
954                 iTmp = pstate->argument;
955                 break;
956 
957             case VARRAND:
958                 varname = "RAND";
959                 iTmp = RANDIE;
960                 break;
961 
962             case VARSELFX:
963                 varname = "SELFX";
964                 iTmp = pchr->pos.x;
965                 break;
966 
967             case VARSELFY:
968                 varname = "SELFY";
969                 iTmp = pchr->pos.y;
970                 break;
971 
972             case VARSELFTURN:
973                 varname = "SELFTURN";
974                 iTmp = pchr->ori.facing_z;
975                 break;
976 
977             case VARSELFCOUNTER:
978                 varname = "SELFCOUNTER";
979                 iTmp = pself->order_counter;
980                 break;
981 
982             case VARSELFORDER:
983                 varname = "SELFORDER";
984                 iTmp = pself->order_value;
985                 break;
986 
987             case VARSELFMORALE:
988                 varname = "SELFMORALE";
989                 iTmp = TeamStack.lst[pchr->baseteam].morale;
990                 break;
991 
992             case VARSELFLIFE:
993                 varname = "SELFLIFE";
994                 iTmp = pchr->life;
995                 break;
996 
997             case VARTARGETX:
998                 varname = "TARGETX";
999                 iTmp = ( NULL == ptarget ) ? 0 : ptarget->pos.x;
1000                 break;
1001 
1002             case VARTARGETY:
1003                 varname = "TARGETY";
1004                 iTmp = ( NULL == ptarget ) ? 0 : ptarget->pos.y;
1005                 break;
1006 
1007             case VARTARGETDISTANCE:
1008                 varname = "TARGETDISTANCE";
1009                 if ( NULL == ptarget )
1010                 {
1011                     iTmp = 0x7FFFFFFF;
1012                 }
1013                 else
1014                 {
1015                     iTmp = ABS( ptarget->pos.x - pchr->pos.x ) + ABS( ptarget->pos.y - pchr->pos.y );
1016                 }
1017                 break;
1018 
1019             case VARTARGETTURN:
1020                 varname = "TARGETTURN";
1021                 iTmp = ( NULL == ptarget ) ? 0 : ptarget->ori.facing_z;
1022                 break;
1023 
1024             case VARLEADERX:
1025                 varname = "LEADERX";
1026                 iTmp = pchr->pos.x;
1027                 if ( TeamStack.lst[pchr->team].leader != NOLEADER )
1028                     iTmp = team_get_pleader( pchr->team )->pos.x;
1029 
1030                 break;
1031 
1032             case VARLEADERY:
1033                 varname = "LEADERY";
1034                 iTmp = pchr->pos.y;
1035                 if ( TeamStack.lst[pchr->team].leader != NOLEADER )
1036                     iTmp = team_get_pleader( pchr->team )->pos.y;
1037 
1038                 break;
1039 
1040             case VARLEADERDISTANCE:
1041                 {
1042                     chr_t * pleader;
1043                     varname = "LEADERDISTANCE";
1044 
1045                     pleader = team_get_pleader( pchr->team );
1046 
1047                     if ( NULL == pleader )
1048                     {
1049                         iTmp = 0x7FFFFFFF;
1050                     }
1051                     else
1052                     {
1053                         iTmp = ABS( pleader->pos.x - pchr->pos.x ) + ABS( pleader->pos.y - pchr->pos.y );
1054                     }
1055                 }
1056                 break;
1057 
1058             case VARLEADERTURN:
1059                 varname = "LEADERTURN";
1060                 iTmp = pchr->ori.facing_z;
1061                 if ( TeamStack.lst[pchr->team].leader != NOLEADER )
1062                     iTmp = team_get_pleader( pchr->team )->ori.facing_z;
1063 
1064                 break;
1065 
1066             case VARGOTOX:
1067                 varname = "GOTOX";
1068 
1069                 ai_state_ensure_wp( pself );
1070 
1071                 if ( !pself->wp_valid )
1072                 {
1073                     iTmp = pchr->pos.x;
1074                 }
1075                 else
1076                 {
1077                     iTmp = pself->wp[kX];
1078                 }
1079                 break;
1080 
1081             case VARGOTOY:
1082                 varname = "GOTOY";
1083 
1084                 ai_state_ensure_wp( pself );
1085 
1086                 if ( !pself->wp_valid )
1087                 {
1088                     iTmp = pchr->pos.y;
1089                 }
1090                 else
1091                 {
1092                     iTmp = pself->wp[kY];
1093                 }
1094                 break;
1095 
1096             case VARGOTODISTANCE:
1097                 varname = "GOTODISTANCE";
1098 
1099                 ai_state_ensure_wp( pself );
1100 
1101                 if ( !pself->wp_valid )
1102                 {
1103                     iTmp = 0x7FFFFFFF;
1104                 }
1105                 else
1106                 {
1107                     iTmp = ABS( pself->wp[kX] - pchr->pos.x ) +
1108                            ABS( pself->wp[kY] - pchr->pos.y );
1109                 }
1110                 break;
1111 
1112             case VARTARGETTURNTO:
1113                 varname = "TARGETTURNTO";
1114                 if ( NULL == ptarget )
1115                 {
1116                     iTmp = 0;
1117                 }
1118                 else
1119                 {
1120                     iTmp = vec_to_facing( ptarget->pos.x - pchr->pos.x , ptarget->pos.y - pchr->pos.y );
1121                     iTmp = CLIP_TO_16BITS( iTmp );
1122                 }
1123                 break;
1124 
1125             case VARPASSAGE:
1126                 varname = "PASSAGE";
1127                 iTmp = pself->passage;
1128                 break;
1129 
1130             case VARWEIGHT:
1131                 varname = "WEIGHT";
1132                 iTmp = pchr->holdingweight;
1133                 break;
1134 
1135             case VARSELFALTITUDE:
1136                 varname = "SELFALTITUDE";
1137                 iTmp = pchr->pos.z - pchr->enviro.floor_level;
1138                 break;
1139 
1140             case VARSELFID:
1141                 varname = "SELFID";
1142                 iTmp = chr_get_idsz( pself->index, IDSZ_TYPE );
1143                 break;
1144 
1145             case VARSELFHATEID:
1146                 varname = "SELFHATEID";
1147                 iTmp = chr_get_idsz( pself->index, IDSZ_HATE );
1148                 break;
1149 
1150             case VARSELFMANA:
1151                 varname = "SELFMANA";
1152                 iTmp = pchr->mana;
1153                 if ( pchr->canchannel )  iTmp += pchr->life;
1154 
1155                 break;
1156 
1157             case VARTARGETSTR:
1158                 varname = "TARGETSTR";
1159                 iTmp = ( NULL == ptarget ) ? 0 : ptarget->strength;
1160                 break;
1161 
1162             case VARTARGETWIS:
1163                 varname = "TARGETWIS";
1164                 iTmp = ( NULL == ptarget ) ? 0 : ptarget->wisdom;
1165                 break;
1166 
1167             case VARTARGETINT:
1168                 varname = "TARGETINT";
1169                 iTmp = ( NULL == ptarget ) ? 0 : ptarget->intelligence;
1170                 break;
1171 
1172             case VARTARGETDEX:
1173                 varname = "TARGETDEX";
1174                 iTmp = ( NULL == ptarget ) ? 0 : ptarget->dexterity;
1175                 break;
1176 
1177             case VARTARGETLIFE:
1178                 varname = "TARGETLIFE";
1179                 iTmp = ( NULL == ptarget ) ? 0 : ptarget->life;
1180                 break;
1181 
1182             case VARTARGETMANA:
1183                 varname = "TARGETMANA";
1184                 if ( NULL == ptarget )
1185                 {
1186                     iTmp = 0;
1187                 }
1188                 else
1189                 {
1190                     iTmp = ptarget->mana;
1191                     if ( ptarget->canchannel ) iTmp += ptarget->life;
1192                 }
1193 
1194                 break;
1195 
1196             case VARTARGETLEVEL:
1197                 varname = "TARGETLEVEL";
1198                 iTmp = ( NULL == ptarget ) ? 0 : ptarget->experiencelevel;
1199                 break;
1200 
1201             case VARTARGETSPEEDX:
1202                 varname = "TARGETSPEEDX";
1203                 iTmp = ( NULL == ptarget ) ? 0 : ABS( ptarget->vel.x );
1204                 break;
1205 
1206             case VARTARGETSPEEDY:
1207                 varname = "TARGETSPEEDY";
1208                 iTmp = ( NULL == ptarget ) ? 0 : ABS( ptarget->vel.y );
1209                 break;
1210 
1211             case VARTARGETSPEEDZ:
1212                 varname = "TARGETSPEEDZ";
1213                 iTmp = ( NULL == ptarget ) ? 0 : ABS( ptarget->vel.z );
1214                 break;
1215 
1216             case VARSELFSPAWNX:
1217                 varname = "SELFSPAWNX";
1218                 iTmp = pchr->pos_stt.x;
1219                 break;
1220 
1221             case VARSELFSPAWNY:
1222                 varname = "SELFSPAWNY";
1223                 iTmp = pchr->pos_stt.y;
1224                 break;
1225 
1226             case VARSELFSTATE:
1227                 varname = "SELFSTATE";
1228                 iTmp = pself->state;
1229                 break;
1230 
1231             case VARSELFCONTENT:
1232                 varname = "SELFCONTENT";
1233                 iTmp = pself->content;
1234                 break;
1235 
1236             case VARSELFSTR:
1237                 varname = "SELFSTR";
1238                 iTmp = pchr->strength;
1239                 break;
1240 
1241             case VARSELFWIS:
1242                 varname = "SELFWIS";
1243                 iTmp = pchr->wisdom;
1244                 break;
1245 
1246             case VARSELFINT:
1247                 varname = "SELFINT";
1248                 iTmp = pchr->intelligence;
1249                 break;
1250 
1251             case VARSELFDEX:
1252                 varname = "SELFDEX";
1253                 iTmp = pchr->dexterity;
1254                 break;
1255 
1256             case VARSELFMANAFLOW:
1257                 varname = "SELFMANAFLOW";
1258                 iTmp = pchr->manaflow;
1259                 break;
1260 
1261             case VARTARGETMANAFLOW:
1262                 varname = "TARGETMANAFLOW";
1263                 iTmp = ( NULL == ptarget ) ? 0 : ptarget->manaflow;
1264                 break;
1265 
1266             case VARSELFATTACHED:
1267                 varname = "SELFATTACHED";
1268                 iTmp = number_of_attached_particles( pself->index );
1269                 break;
1270 
1271             case VARSWINGTURN:
1272                 varname = "SWINGTURN";
1273                 iTmp = PCamera->swing << 2;
1274                 break;
1275 
1276             case VARXYDISTANCE:
1277                 varname = "XYDISTANCE";
1278                 iTmp = SQRT( pstate->x * pstate->x + pstate->y * pstate->y );
1279                 break;
1280 
1281             case VARSELFZ:
1282                 varname = "SELFZ";
1283                 iTmp = pchr->pos.z;
1284                 break;
1285 
1286             case VARTARGETALTITUDE:
1287                 varname = "TARGETALTITUDE";
1288                 iTmp = ( NULL == ptarget ) ? 0 : ptarget->pos.z - ptarget->enviro.floor_level;
1289                 break;
1290 
1291             case VARTARGETZ:
1292                 varname = "TARGETZ";
1293                 iTmp = ( NULL == ptarget ) ? 0 : ptarget->pos.z;
1294                 break;
1295 
1296             case VARSELFINDEX:
1297                 varname = "SELFINDEX";
1298                 iTmp = REF_TO_INT( pself->index );
1299                 break;
1300 
1301             case VAROWNERX:
1302                 varname = "OWNERX";
1303                 iTmp = ( NULL == powner ) ? 0 : powner->pos.x;
1304                 break;
1305 
1306             case VAROWNERY:
1307                 varname = "OWNERY";
1308                 iTmp = ( NULL == powner ) ? 0 : powner->pos.y;
1309                 break;
1310 
1311             case VAROWNERTURN:
1312                 varname = "OWNERTURN";
1313                 iTmp = ( NULL == powner ) ? 0 : powner->ori.facing_z;
1314                 break;
1315 
1316             case VAROWNERDISTANCE:
1317                 varname = "OWNERDISTANCE";
1318                 if ( NULL == powner )
1319                 {
1320                     iTmp = 0x7FFFFFFF;
1321                 }
1322                 else
1323                 {
1324                     iTmp = ABS( powner->pos.x - pchr->pos.x ) + ABS( powner->pos.y - pchr->pos.y );
1325                 }
1326                 break;
1327 
1328             case VAROWNERTURNTO:
1329                 varname = "OWNERTURNTO";
1330                 if ( NULL == powner )
1331                 {
1332                     iTmp = 0;
1333                 }
1334                 else
1335                 {
1336                     iTmp = vec_to_facing( powner->pos.x - pchr->pos.x , powner->pos.y - pchr->pos.y );
1337                     iTmp = CLIP_TO_16BITS( iTmp );
1338                 }
1339                 break;
1340 
1341             case VARXYTURNTO:
1342                 varname = "XYTURNTO";
1343                 iTmp = vec_to_facing( pstate->x - pchr->pos.x , pstate->y - pchr->pos.y );
1344                 iTmp = CLIP_TO_16BITS( iTmp );
1345                 break;
1346 
1347             case VARSELFMONEY:
1348                 varname = "SELFMONEY";
1349                 iTmp = pchr->money;
1350                 break;
1351 
1352             case VARSELFACCEL:
1353                 varname = "SELFACCEL";
1354                 iTmp = ( pchr->maxaccel_reset * 100.0f );
1355                 break;
1356 
1357             case VARTARGETEXP:
1358                 varname = "TARGETEXP";
1359                 iTmp = ( NULL == ptarget ) ? 0 : ptarget->experience;
1360                 break;
1361 
1362             case VARSELFAMMO:
1363                 varname = "SELFAMMO";
1364                 iTmp = pchr->ammo;
1365                 break;
1366 
1367             case VARTARGETAMMO:
1368                 varname = "TARGETAMMO";
1369                 iTmp = ( NULL == ptarget ) ? 0 : ptarget->ammo;
1370                 break;
1371 
1372             case VARTARGETMONEY:
1373                 varname = "TARGETMONEY";
1374                 iTmp = ( NULL == ptarget ) ? 0 : ptarget->money;
1375                 break;
1376 
1377             case VARTARGETTURNAWAY:
1378                 varname = "TARGETTURNAWAY";
1379                 if ( NULL == ptarget )
1380                 {
1381                     iTmp = 0;
1382                 }
1383                 else
1384                 {
1385                     iTmp = vec_to_facing( ptarget->pos.x - pchr->pos.x , ptarget->pos.y - pchr->pos.y );
1386                     iTmp = CLIP_TO_16BITS( iTmp );
1387                 }
1388                 break;
1389 
1390             case VARSELFLEVEL:
1391                 varname = "SELFLEVEL";
1392                 iTmp = pchr->experiencelevel;
1393                 break;
1394 
1395             case VARTARGETRELOADTIME:
1396                 varname = "TARGETRELOADTIME";
1397                 iTmp = ( NULL == ptarget ) ? 0 : ptarget->reload_timer;
1398                 break;
1399 
1400             case VARSPAWNDISTANCE:
1401                 varname = "SPAWNDISTANCE";
1402                 iTmp = ABS( pchr->pos_stt.x - pchr->pos.x ) + ABS( pchr->pos_stt.y - pchr->pos.y );
1403                 break;
1404 
1405             case VARTARGETMAXLIFE:
1406                 varname = "TARGETMAXLIFE";
1407                 iTmp = ( NULL == ptarget ) ? 0 : ptarget->lifemax;
1408                 break;
1409 
1410             case VARTARGETTEAM:
1411                 varname = "TARGETTEAM";
1412                 iTmp = ( NULL == ptarget ) ? 0 : ptarget->team;
1413                 //iTmp = REF_TO_INT( chr_get_iteam( pself->target ) );
1414                 break;
1415 
1416             case VARTARGETARMOR:
1417                 varname = "TARGETARMOR";
1418                 iTmp = ( NULL == ptarget ) ? 0 : ptarget->skin;
1419                 break;
1420 
1421             case VARDIFFICULTY:
1422                 varname = "DIFFICULTY";
1423                 iTmp = cfg.difficulty;
1424                 break;
1425 
1426             case VARTIMEHOURS:
1427                 varname = "TIMEHOURS";
1428                 iTmp = getCurrentTime()->tm_hour;
1429                 break;
1430 
1431             case VARTIMEMINUTES:
1432                 varname = "TIMEMINUTES";
1433                 iTmp = getCurrentTime()->tm_min;
1434                 break;
1435 
1436             case VARTIMESECONDS:
1437                 varname = "TIMESECONDS";
1438                 iTmp = getCurrentTime()->tm_sec;
1439                 break;
1440 
1441             case VARDATEMONTH:
1442                 varname = "DATEMONTH";
1443                 iTmp = getCurrentTime()->tm_mon + 1;
1444                 break;
1445 
1446             case VARDATEDAY:
1447                 varname = "DATEDAY";
1448                 iTmp = getCurrentTime()->tm_mday;
1449                 break;
1450 
1451             default:
1452                 log_message( "SCRIPT ERROR: scr_run_operand() - model == %d, class name == \"%s\" - Unknown variable found!\n", REF_TO_INT( script_error_model ), script_error_classname );
1453                 break;
1454         }
1455     }
1456 
1457     // Now do the math
1458     op = "UNKNOWN";
1459     switch ( operation )
1460     {
1461         case OPADD:
1462             op = "ADD";
1463             pstate->operationsum += iTmp;
1464             break;
1465 
1466         case OPSUB:
1467             op = "SUB";
1468             pstate->operationsum -= iTmp;
1469             break;
1470 
1471         case OPAND:
1472             op = "AND";
1473             pstate->operationsum &= iTmp;
1474             break;
1475 
1476         case OPSHR:
1477             op = "SHR";
1478             pstate->operationsum >>= iTmp;
1479             break;
1480 
1481         case OPSHL:
1482             op = "SHL";
1483             pstate->operationsum <<= iTmp;
1484             break;
1485 
1486         case OPMUL:
1487             op = "MUL";
1488             pstate->operationsum *= iTmp;
1489             break;
1490 
1491         case OPDIV:
1492             op = "DIV";
1493             if ( iTmp != 0 )
1494             {
1495                 pstate->operationsum = (( float )pstate->operationsum ) / iTmp;
1496             }
1497             else
1498             {
1499                 log_message( "SCRIPT ERROR: scr_run_operand() - model == %d, class name == \"%s\" - Cannot divide by zero!\n", REF_TO_INT( script_error_model ), script_error_classname );
1500             }
1501             break;
1502 
1503         case OPMOD:
1504             op = "MOD";
1505             if ( iTmp != 0 )
1506             {
1507                 pstate->operationsum %= iTmp;
1508             }
1509             else
1510             {
1511                 log_message( "SCRIPT ERROR: scr_run_operand() - model == %d, class name == \"%s\" - Cannot modulo by zero!\n", REF_TO_INT( script_error_model ), script_error_classname );
1512             }
1513             break;
1514 
1515         default:
1516             log_message( "SCRIPT ERROR: scr_run_operand() - model == %d, class name == \"%s\" - unknown op\n", REF_TO_INT( script_error_model ), script_error_classname );
1517             break;
1518     }
1519 
1520     if ( debug_scripts )
1521     {
1522         FILE * scr_file = ( NULL == debug_script_file ) ? stdout : debug_script_file;
1523         fprintf( scr_file, "%s %s(%d) ", op, varname, iTmp );
1524     }
1525 }
1526 
scr_increment_exe(ai_state_t * pself)1527 bool_t scr_increment_exe( ai_state_t * pself )
1528 {
1529     if ( NULL == pself ) return bfalse;
1530     if ( pself->exe_pos < pself->exe_stt || pself->exe_pos >= pself->exe_end ) return bfalse;
1531 
1532     pself->exe_pos++;
1533     pself->opcode = AisCompiled_buffer[pself->exe_pos];
1534 
1535     return btrue;
1536 }
1537 
1538 //--------------------------------------------------------------------------------------------
scr_set_exe(ai_state_t * pself,size_t offset)1539 bool_t scr_set_exe( ai_state_t * pself, size_t offset )
1540 {
1541     if ( NULL == pself ) return bfalse;
1542     if ( offset < pself->exe_stt || offset >= pself->exe_end ) return bfalse;
1543 
1544     pself->exe_pos = offset;
1545     pself->opcode  = AisCompiled_buffer[pself->exe_pos];
1546 
1547     return btrue;
1548 }
1549 
1550 //--------------------------------------------------------------------------------------------
1551 //--------------------------------------------------------------------------------------------
waypoint_list_peek(waypoint_list_t * plst,waypoint_t wp)1552 bool_t waypoint_list_peek( waypoint_list_t * plst, waypoint_t wp )
1553 {
1554     int index;
1555 
1556     // is the list valid?
1557     if ( NULL == plst || plst->tail >= MAXWAY ) return bfalse;
1558 
1559     // is the list is empty?
1560     if ( 0 == plst->head ) return bfalse;
1561 
1562     if ( plst->tail > plst->head )
1563     {
1564         // fix the tail
1565         plst->tail = plst->head;
1566 
1567         // we have passed the last waypoint
1568         // just tell them the previous waypoint
1569         index = plst->tail - 1;
1570     }
1571     else if ( plst->tail == plst->head )
1572     {
1573         // we have passed the last waypoint
1574         // just tell them the previous waypoint
1575         index = plst->tail - 1;
1576     }
1577     else
1578     {
1579         // tell them the current waypoint
1580         index = plst->tail;
1581     }
1582 
1583     wp[kX] = plst->pos[index][kX];
1584     wp[kY] = plst->pos[index][kY];
1585     wp[kZ] = plst->pos[index][kZ];
1586 
1587     return btrue;
1588 }
1589 
1590 //--------------------------------------------------------------------------------------------
waypoint_list_push(waypoint_list_t * plst,int x,int y)1591 bool_t waypoint_list_push( waypoint_list_t * plst, int x, int y )
1592 {
1593     /// @details BB@> Add a waypoint to the waypoint list
1594 
1595     if ( NULL == plst ) return bfalse;
1596 
1597     // add the value
1598     plst->pos[plst->head][kX] = x;
1599     plst->pos[plst->head][kY] = y;
1600     plst->pos[plst->head][kZ] = 0;
1601 
1602     // do not let the list overflow
1603     plst->head++;
1604     if ( plst->head >= MAXWAY ) plst->head = MAXWAY - 1;
1605 
1606     return btrue;
1607 }
1608 
1609 //--------------------------------------------------------------------------------------------
waypoint_list_reset(waypoint_list_t * plst)1610 bool_t waypoint_list_reset( waypoint_list_t * plst )
1611 {
1612     /// @details BB@> reset the waypoint list to the beginning
1613 
1614     if ( NULL == plst ) return bfalse;
1615 
1616     plst->tail = 0;
1617 
1618     return btrue;
1619 }
1620 
1621 //--------------------------------------------------------------------------------------------
waypoint_list_clear(waypoint_list_t * plst)1622 bool_t waypoint_list_clear( waypoint_list_t * plst )
1623 {
1624     /// @details BB@> Clear out all waypoints
1625 
1626     if ( NULL == plst ) return bfalse;
1627 
1628     plst->tail = 0;
1629     plst->head = 0;
1630 
1631     return btrue;
1632 }
1633 
1634 //--------------------------------------------------------------------------------------------
waypoint_list_empty(waypoint_list_t * plst)1635 bool_t waypoint_list_empty( waypoint_list_t * plst )
1636 {
1637     if ( NULL == plst ) return btrue;
1638 
1639     return 0 == plst->head;
1640 }
1641 
1642 //--------------------------------------------------------------------------------------------
waypoint_list_finished(waypoint_list_t * plst)1643 bool_t waypoint_list_finished( waypoint_list_t * plst )
1644 {
1645     if ( NULL == plst || 0 == plst->head ) return btrue;
1646 
1647     return plst->tail == plst->head;
1648 }
1649 
1650 //--------------------------------------------------------------------------------------------
waypoint_list_advance(waypoint_list_t * plst)1651 bool_t waypoint_list_advance( waypoint_list_t * plst )
1652 {
1653     bool_t retval;
1654 
1655     if ( NULL == plst ) return bfalse;
1656 
1657     retval = bfalse;
1658     if ( plst->tail > plst->head )
1659     {
1660         // fix the tail
1661         plst->tail = plst->head;
1662     }
1663     else if ( plst->tail < plst->head )
1664     {
1665         // advance the tail
1666         plst->tail++;
1667         retval = btrue;
1668     }
1669 
1670     // clamp the tail to valid values
1671     if ( plst->tail >= MAXWAY ) plst->tail = MAXWAY - 1;
1672 
1673     return retval;
1674 }
1675 
1676 //--------------------------------------------------------------------------------------------
ai_state_get_wp(ai_state_t * pself)1677 bool_t ai_state_get_wp( ai_state_t * pself )
1678 {
1679     // try to load up the top waypoint
1680 
1681     if ( NULL == pself || !INGAME_CHR( pself->index ) ) return bfalse;
1682 
1683     pself->wp_valid = waypoint_list_peek( &( pself->wp_lst ), pself->wp );
1684 
1685     return btrue;
1686 }
1687 
1688 //--------------------------------------------------------------------------------------------
ai_state_ensure_wp(ai_state_t * pself)1689 bool_t ai_state_ensure_wp( ai_state_t * pself )
1690 {
1691     // is the current waypoint is not valid, try to load up the top waypoint
1692 
1693     if ( NULL == pself || !INGAME_CHR( pself->index ) ) return bfalse;
1694 
1695     if ( pself->wp_valid ) return btrue;
1696 
1697     return ai_state_get_wp( pself );
1698 }
1699 
1700 //--------------------------------------------------------------------------------------------
1701 //--------------------------------------------------------------------------------------------
set_alerts(const CHR_REF character)1702 void set_alerts( const CHR_REF character )
1703 {
1704     /// @details ZZ@> This function polls some alert conditions
1705 
1706     chr_t      * pchr;
1707     ai_state_t * pai;
1708     bool_t at_waypoint;
1709 
1710     // invalid characters do not think
1711     if ( !INGAME_CHR( character ) ) return;
1712     pchr = ChrList.lst + character;
1713     pai  = chr_get_pai( character );
1714 
1715     if ( waypoint_list_empty( &( pai->wp_lst ) ) ) return;
1716 
1717     // let's let mounts get alert updates...
1718     // imagine a mount, like a racecar, that needs to make sure that it follows X
1719     // waypoints around a track or something
1720 
1721     // mounts do not get alerts
1722     // if ( INGAME_CHR(pchr->attachedto) ) return;
1723 
1724     // is the current waypoint is not valid, try to load up the top waypoint
1725     ai_state_ensure_wp( pai );
1726 
1727     at_waypoint = bfalse;
1728     if ( pai->wp_valid )
1729     {
1730         at_waypoint = ( ABS( pchr->pos.x - pai->wp[kX] ) < WAYTHRESH ) &&
1731                       ( ABS( pchr->pos.y - pai->wp[kY] ) < WAYTHRESH );
1732     }
1733 
1734     if ( at_waypoint )
1735     {
1736         SET_BIT( pai->alert, ALERTIF_ATWAYPOINT );
1737 
1738         if ( waypoint_list_finished( &( pai->wp_lst ) ) )
1739         {
1740             // we are now at the last waypoint
1741             // if the object can be alerted to last waypoint, do it
1742             // this test needs to be done because the ALERTIF_ATLASTWAYPOINT
1743             // doubles for "at last waypoint" and "not put away"
1744             if ( !chr_get_pcap( character )->isequipment )
1745             {
1746                 SET_BIT( pai->alert, ALERTIF_ATLASTWAYPOINT );
1747             }
1748 
1749             // !!!!restart the waypoint list, do not clear them!!!!
1750             waypoint_list_reset( &( pai->wp_lst ) );
1751 
1752             // load the top waypoint
1753             ai_state_get_wp( pai );
1754         }
1755         else if ( waypoint_list_advance( &( pai->wp_lst ) ) )
1756         {
1757             // load the top waypoint
1758             ai_state_get_wp( pai );
1759         }
1760     }
1761 }
1762 
1763 //--------------------------------------------------------------------------------------------
issue_order(const CHR_REF character,Uint32 value)1764 void issue_order( const CHR_REF character, Uint32 value )
1765 {
1766     /// @details ZZ@> This function issues an value for help to all teammates
1767 
1768     CHR_REF cnt;
1769     int     counter;
1770 
1771     for ( cnt = 0, counter = 0; cnt < MAX_CHR; cnt++ )
1772     {
1773         if ( !INGAME_CHR( cnt ) ) continue;
1774 
1775         if ( chr_get_iteam( cnt ) == chr_get_iteam( character ) )
1776         {
1777             ai_add_order( chr_get_pai( cnt ), value, counter );
1778             counter++;
1779         }
1780     }
1781 }
1782 
1783 //--------------------------------------------------------------------------------------------
issue_special_order(Uint32 value,IDSZ idsz)1784 void issue_special_order( Uint32 value, IDSZ idsz )
1785 {
1786     /// @details ZZ@> This function issues an order to all characters with the a matching special IDSZ
1787 
1788     CHR_REF cnt;
1789     int     counter;
1790 
1791     for ( cnt = 0, counter = 0; cnt < MAX_CHR; cnt++ )
1792     {
1793         cap_t * pcap;
1794 
1795         if ( !INGAME_CHR( cnt ) ) continue;
1796 
1797         pcap = chr_get_pcap( cnt );
1798         if ( NULL == pcap ) continue;
1799 
1800         if ( idsz == pcap->idsz[IDSZ_SPECIAL] )
1801         {
1802             ai_add_order( chr_get_pai( cnt ), value, counter );
1803             counter++;
1804         }
1805     }
1806 }
1807 
1808 //--------------------------------------------------------------------------------------------
1809 //--------------------------------------------------------------------------------------------
ai_state_free(ai_state_t * pself)1810 bool_t ai_state_free( ai_state_t * pself )
1811 {
1812     if ( NULL == pself ) return bfalse;
1813 
1814     // free any allocated data
1815     PROFILE_FREE_STRUCT( pself );
1816 
1817     return btrue;
1818 };
1819 
1820 //--------------------------------------------------------------------------------------------
ai_state_reconstruct(ai_state_t * pself)1821 ai_state_t * ai_state_reconstruct( ai_state_t * pself )
1822 {
1823     if ( NULL == pself ) return pself;
1824 
1825     // deallocate any existing data
1826     ai_state_free( pself );
1827 
1828     // set everything to safe values
1829     memset( pself, 0, sizeof( *pself ) );
1830 
1831     pself->index      = ( CHR_REF )MAX_CHR;
1832     pself->target     = ( CHR_REF )MAX_CHR;
1833     pself->owner      = ( CHR_REF )MAX_CHR;
1834     pself->child      = ( CHR_REF )MAX_CHR;
1835     pself->target_old = ( CHR_REF )MAX_CHR;
1836     pself->poof_time  = -1;
1837 
1838     pself->bumplast   = ( CHR_REF )MAX_CHR;
1839     pself->attacklast = ( CHR_REF )MAX_CHR;
1840     pself->hitlast    = ( CHR_REF )MAX_CHR;
1841 
1842     return pself;
1843 }
1844 
1845 //--------------------------------------------------------------------------------------------
ai_state_ctor(ai_state_t * pself)1846 ai_state_t * ai_state_ctor( ai_state_t * pself )
1847 {
1848     if ( NULL == ai_state_reconstruct( pself ) ) return NULL;
1849 
1850     PROFILE_INIT_STRUCT( ai, pself );
1851 
1852     return pself;
1853 }
1854 
1855 //--------------------------------------------------------------------------------------------
ai_state_dtor(ai_state_t * pself)1856 ai_state_t * ai_state_dtor( ai_state_t * pself )
1857 {
1858     if ( NULL == pself ) return pself;
1859 
1860     // initialize the object
1861     ai_state_reconstruct( pself );
1862 
1863     return pself;
1864 }
1865 
1866