1 /*
2  * OpenBOR - http://www.LavaLit.com
3  * -----------------------------------------------------------------------
4  * All rights reserved, see LICENSE in OpenBOR root for details.
5  *
6  * Copyright (c) 2004 - 2011 OpenBOR Team
7  */
8 
9 /////////////////////////////////////////////////////////////////////////////
10 //	Beats of Rage                                                           //
11 //	Side-scrolling beat-'em-up                                              //
12 /////////////////////////////////////////////////////////////////////////////
13 
14 #include "openbor.h"
15 #include "commands.h"
16 #include "models.h"
17 
18 #define GET_ARG(z) (arglist.count > z ? arglist.args[z] : "")
19 #define GET_ARG_LEN(z) (arglist.count > z ? arglist.arglen[z] : 0)
20 #define GET_ARGP(z) (arglist->count > z ? arglist->args[z] : "")
21 #define GET_ARGP_LEN(z) (arglist->count > z ? arglist->arglen[z] : 0)
22 #define GET_INT_ARG(z) getValidInt(GET_ARG(z), filename, command)
23 #define GET_FLOAT_ARG(z) getValidFloat(GET_ARG(z), filename, command)
24 #define GET_INT_ARGP(z) getValidInt(GET_ARGP(z), filename, command)
25 #define GET_FLOAT_ARGP(z) getValidFloat(GET_ARGP(z), filename, command)
26 
27 #define GET_FRAME_ARG(z) (stricmp(GET_ARG(z), "this")==0?newanim->numframes:GET_INT_ARG(z))
28 
29 #define NaN 0xAAAAAAAA
30 
31 static const char* E_OUT_OF_MEMORY = "Error: Could not allocate sufficient memory.\n";
32 static int DEFAULT_OFFSCREEN_KILL = 3000;
33 
34 
35 s_sprite_list *sprite_list;
36 s_sprite_map *sprite_map;
37 
38 
39 /////////////////////////////////////////////////////////////////////////////
40 //  Global Variables                                                        //
41 /////////////////////////////////////////////////////////////////////////////
42 
43 s_set_entry *levelsets = NULL;
44 int        num_difficulties;
45 
46 int		skiptoset = -1;
47 
48 s_level*            level               = NULL;
49 s_filestream filestreams[LEVEL_MAX_FILESTREAMS];
50 s_screen*           vscreen             = NULL;
51 s_screen*           background          = NULL;
52 s_videomodes        videomodes;
53 int sprite_map_max_items = 0;
54 int cache_map_max_items = 0;
55 
56 int startup_done = 0; // startup is only called when a game is loaded. so when exitting from the menu we need a way to figure out which resources to free.
57 List* modelcmdlist = NULL;
58 List* modelstxtcmdlist = NULL;
59 List* levelcmdlist = NULL;
60 List* levelordercmdlist = NULL;
61 
62 int atkchoices[MAX_ANIS]; //tempory values for ai functions, should be well enough LOL
63 
64 //see types.h
65 const s_drawmethod plainmethod = {
66 	NULL, // table
67 	NULL, //fp
68 	0,    // fillcolor
69 	1,    //flag
70 	-1,   // alpha
71 	-1,   // remap
72 	0,    //flipx
73 	0,    //flipy
74 	0,    //transbg
75 	0,    //fliprotate
76 	0,    //rotate
77 	256,  //scalex
78 	256,  //scaley
79 	0,    //shiftx
80 	0,    //centerx  //currently used only by gfxshadow, do not touch it
81 	0,    //centery
82 	1,    //xrepeat
83 	1,    //yrepeat
84 	0,    //xspan
85 	0,    //yspan
86 	{{.beginsize=0.0}, {.endsize=0.0}, 0, {.wavespeed=0}, 0} //water
87 };
88 
89 const s_defense default_defense =
90 {
91 	1.f,
92 	0.f,
93 	1.f,
94 	0.f,
95 	0.f,
96 	0.f,
97 	0.f
98 };
99 
100 // unknockdown attack
101 const s_attack emptyattack = {
102 	0, // force
103    {0,0,0,0,0}, // coods
104    {0, 0, 0}, // dropv
105    {0,0,0}, //staydown
106    -1, // sound
107    -1, // flash
108    -1, // blockflash
109    -1, // blocksound
110    0, //no_block
111    0, //counterattack;
112    0, //no_pain
113    0, //no_kill
114    0, //no_flash
115    0, //grab
116    0, //freeze
117    0, //steal
118    0, //blast
119    0, //force_direction
120    0, //forcemap
121    0, //seal
122    0, //freezetime
123    0, //maptime;
124    0, //sealtime;
125    0, //dot
126    0, //dot_index
127    0, //dot_time
128    0, //dot_force
129    0, //dot_rate
130    0, //otg
131    0, //jugglecost
132    0, //guardcost
133    0, //attack_drop
134    0, //attack_type
135    0, //damage_on_landing
136    0, //grab_distance
137    0, //pause_add
138    0 //pain_time
139 };
140 
141 //default values
142 float default_level_maxtossspeed = 100.0f;
143 float default_level_maxfallspeed = -6.0f;
144 float default_level_gravity = -0.1f;
145 
146 float default_model_jumpheight = 4.0f;
147 float default_model_jumpspeed = -1;
148 float default_model_dropv[3] = {3.0f, 1.2f, 0.0f};
149 float default_model_grabdistance = 36.0f;
150 
151 // AI attack debug stuff for development purpose,
152 // Don't open them to modders yet
153 float move_noatk_factor=3.0f;
154 float group_noatk_factor=0.01f;
155 float agg_noatk_factor=0.0f;
156 float min_noatk_chance=0.0f;
157 float max_noatk_chance=0.6f;
158 float offscreen_noatk_factor=0.5f;
159 float noatk_duration=0.75f;
160 
161 char                *custScenes = NULL;
162 char                *custBkgrds = NULL;
163 char                *custLevels = NULL;
164 char                *custModels = NULL;
165 char                rush_names[2][MAX_NAME_LEN];
166 char				skipselect[MAX_PLAYERS][MAX_NAME_LEN];
167 char                branch_name[MAX_NAME_LEN+1];    // Used for branches
168 int					useSave = 0;
169 unsigned char       pal[MAX_PAL_SIZE] = {""};
170 int                 blendfx[MAX_BLENDINGS] = {0,1,0,0,0,0};
171 char                blendfx_is_set = 0;
172 int                 fontmonospace[MAX_FONTS] = {0,0,0,0,0,0,0,0};
173 int                 fontmbs[MAX_FONTS] = {0,0,0,0,0,0,0,0};
174 
175 // move all blending effects here
176 unsigned char*      blendings[MAX_BLENDINGS] = {NULL, NULL, NULL, NULL, NULL, NULL} ;
177 // function pointers to create the tables
178 palette_table_function blending_table_functions[MAX_BLENDINGS] = {palette_table_screen, palette_table_multiply, palette_table_overlay,palette_table_hardlight, palette_table_dodge, palette_table_half};
179 blend_table_function blending_table_functions16[MAX_BLENDINGS] = {create_screen16_tbl,create_multiply16_tbl,create_overlay16_tbl,create_hardlight16_tbl,create_dodge16_tbl,create_half16_tbl};
180 blend_table_function blending_table_functions32[MAX_BLENDINGS] = {create_screen32_tbl,create_multiply32_tbl,create_overlay32_tbl,create_hardlight32_tbl,create_dodge32_tbl,create_half32_tbl};
181 
182 int                 current_set = 0;
183 int                 current_level = 0;
184 int                 current_stage = 1;
185 
186 int					timevar;
187 float               bgtravelled;
188 int                 traveltime;
189 int                 texttime;
190 int					timetoshow;
191 int					showgo;
192 float               advancex;
193 float               advancey;
194 
195 float               scrolldx;                       // advancex changed previous loop
196 float               scrolldy;                       // advancey .....................
197 float               scrollminz;                     // Limit level z-scroll
198 float               scrollmaxz;
199 float               blockade;                       // Limit x scroll back
200 float               lasthitx;						//Last hit X location.
201 float               lasthitz;						//Last hit Z location.
202 float               lasthita;						//Last hit A location.
203 int                 lasthitt;                       //Last hit type.
204 int                 lasthitc;                       //Last hit confirm (i.e. if engine hit code will be used).
205 
206 int					combodelay = GAME_SPEED/2;		// avoid annoying 112112... infinite combo
207 
208 // used by gfx shadow
209 int                 light[2] = {128, 64};
210 int                 shadowcolor = 0;
211 int                 shadowalpha = BLEND_MULTIPLY+1;
212 
213 u64 totalram = 0;
214 u64 usedram = 0;
215 u64 freeram = 0;
216 u32 interval = 0;
217 extern unsigned long seed;
218 
219 int                 SAMPLE_GO			= -1;
220 int                 SAMPLE_BEAT			= -1;
221 int                 SAMPLE_BLOCK		= -1;
222 int                 SAMPLE_INDIRECT		= -1;
223 int                 SAMPLE_GET			= -1;
224 int                 SAMPLE_GET2			= -1;
225 int                 SAMPLE_FALL			= -1;
226 int                 SAMPLE_JUMP			= -1;
227 int                 SAMPLE_PUNCH		= -1;
228 int                 SAMPLE_1UP			= -1;
229 int                 SAMPLE_TIMEOVER		= -1;
230 int                 SAMPLE_BEEP			= -1;
231 int                 SAMPLE_BEEP2		= -1;
232 int                 SAMPLE_BIKE			= -1;
233 
234 int                 max_downs           = MAX_DOWNS;
235 int                 max_ups             = MAX_UPS;
236 int                 max_backwalks       = MAX_BACKWALKS;
237 int                 max_walks           = MAX_WALKS;
238 int                 max_idles           = MAX_IDLES;
239 int                 max_attack_types    = MAX_ATKS;
240 int                 max_freespecials    = MAX_SPECIALS;
241 int                 max_follows         = MAX_FOLLOWS;
242 int                 max_attacks         = MAX_ATTACKS;
243 int                 max_animations      = MAX_ANIS;
244 
245 // -------dynamic animation indexes-------
246 int*                animdowns           = NULL;
247 int*                animups             = NULL;
248 int*                animbackwalks       = NULL;
249 int*                animwalks           = NULL;
250 int*                animidles           = NULL;
251 int*                animpains           = NULL;
252 int*                animdies            = NULL;
253 int*                animfalls           = NULL;
254 int*                animrises           = NULL;
255 int*                animriseattacks     = NULL;
256 int*                animblkpains        = NULL;
257 int*                animattacks         = NULL;
258 int*                animfollows         = NULL;
259 int*                animspecials        = NULL;
260 
261 // system default values
262 int                 downs[MAX_DOWNS]        = {ANI_DOWN};
263 int                 ups[MAX_UPS]            = {ANI_UP};
264 int                 backwalks[MAX_BACKWALKS]= {ANI_BACKWALK};
265 int                 walks[MAX_WALKS]        = {ANI_WALK};
266 int                 idles[MAX_IDLES]        = {ANI_IDLE};
267 
268 int                 falls[MAX_ATKS] = {
269 						ANI_FALL,  ANI_FALL2, ANI_FALL3, ANI_FALL4,
270 						ANI_FALL,  ANI_BURN,  ANI_FALL,  ANI_SHOCK,
271 						ANI_FALL,  ANI_FALL5, ANI_FALL6, ANI_FALL7,
272 						ANI_FALL8, ANI_FALL9, ANI_FALL10
273 					};
274 
275 int                 rises[MAX_ATKS] = {
276 						ANI_RISE,  ANI_RISE2, ANI_RISE3, ANI_RISE4,
277 						ANI_RISE,  ANI_RISEB,  ANI_RISE,  ANI_RISES,
278 						ANI_RISE,  ANI_RISE5, ANI_RISE6, ANI_RISE7,
279 						ANI_RISE8, ANI_RISE9, ANI_RISE10
280 					};
281 
282 int                 riseattacks[MAX_ATKS] = {
283 						ANI_RISEATTACK,  ANI_RISEATTACK2, ANI_RISEATTACK3, ANI_RISEATTACK4,
284 						ANI_RISEATTACK,  ANI_RISEATTACKB,  ANI_RISEATTACK,  ANI_RISEATTACKS,
285 						ANI_RISEATTACK,  ANI_RISEATTACK5, ANI_RISEATTACK6, ANI_RISEATTACK7,
286 						ANI_RISEATTACK8, ANI_RISEATTACK9, ANI_RISEATTACK10
287 					};
288 
289 int                 pains[MAX_ATKS] = {
290 						ANI_PAIN,  ANI_PAIN2,    ANI_PAIN3, ANI_PAIN4,
291 						ANI_PAIN,  ANI_BURNPAIN, ANI_PAIN,  ANI_SHOCKPAIN,
292 						ANI_PAIN,  ANI_PAIN5,    ANI_PAIN6, ANI_PAIN7,
293 						ANI_PAIN8, ANI_PAIN9,    ANI_PAIN10
294 					};
295 
296 int                 deaths[MAX_ATKS] = {
297 						ANI_DIE,   ANI_DIE2,     ANI_DIE3,  ANI_DIE4,
298 						ANI_DIE,   ANI_BURNDIE,  ANI_DIE,   ANI_SHOCKDIE,
299 						ANI_DIE,   ANI_DIE5,     ANI_DIE6,  ANI_DIE7,
300 						ANI_DIE8,  ANI_DIE9,     ANI_DIE10
301 					};
302 
303 int                 blkpains[MAX_ATKS] = {
304 						ANI_BLOCKPAIN,  ANI_BLOCKPAIN2,    ANI_BLOCKPAIN3, ANI_BLOCKPAIN4,
305 						ANI_BLOCKPAIN,  ANI_BLOCKPAINB, ANI_BLOCKPAIN,  ANI_BLOCKPAINS,
306 						ANI_BLOCKPAIN,  ANI_BLOCKPAIN5,    ANI_BLOCKPAIN6, ANI_BLOCKPAIN7,
307 						ANI_BLOCKPAIN8, ANI_BLOCKPAIN9,    ANI_BLOCKPAIN10
308 					};
309 
310 int                 normal_attacks[MAX_ATTACKS] = {
311 						ANI_ATTACK1, ANI_ATTACK2, ANI_ATTACK3, ANI_ATTACK4
312 					};
313 
314 int                 grab_attacks[5][2] = {
315 						{ANI_GRABATTACK, ANI_GRABATTACK2},
316 						{ANI_GRABFORWARD, ANI_GRABFORWARD2},
317 						{ANI_GRABUP, ANI_GRABUP2},
318 						{ANI_GRABDOWN, ANI_GRABDOWN2},
319 						{ANI_GRABBACKWARD, ANI_GRABBACKWARD2}
320 					};
321 
322 int                 freespecials[MAX_SPECIALS] = {
323 						ANI_FREESPECIAL,   ANI_FREESPECIAL2,  ANI_FREESPECIAL3,
324 						ANI_FREESPECIAL4,  ANI_FREESPECIAL5,  ANI_FREESPECIAL6,
325 						ANI_FREESPECIAL7,  ANI_FREESPECIAL8
326 					};
327 
328 int                 follows[MAX_FOLLOWS] = {
329 						ANI_FOLLOW1, ANI_FOLLOW2, ANI_FOLLOW3, ANI_FOLLOW4
330 					};
331 
332 #ifndef DISABLE_MOVIE
333 #define DISABLE_MOVIE
334 #endif
335 
336 //movie log stuffs
337 #ifndef DISABLE_MOVIE
338 #define MOVIEBUF_LEN 2048
339 int movielog = 0;
340 int movieplay = 0;
341 int moviebufptr = 0;
342 int movielen = 0;
343 int movieloglen = 0;
344 FILE* moviefile = NULL;
345 u32 (*moviebuffer)[5][2] = NULL; //keyflags, newkeyflags;
346 #endif
347 
348 // background cache to speed up in-game menus
349 #if WII
350 s_screen*           bg_cache[MAX_CACHED_BACKGROUNDS] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
351 unsigned char		bg_palette_cache[MAX_CACHED_BACKGROUNDS][MAX_PAL_SIZE];
352 #endif
353 
354 /*
355 int                 maxplayers[MAX_DIFFICULTIES] = {2,2,2,2,2,2,2,2,2,2};
356 int                 ctrlmaxplayers[MAX_DIFFICULTIES] = {0,0,0,0,0,0,0,0,0,0};
357 unsigned int        num_levels[MAX_DIFFICULTIES];
358 unsigned int        ifcomplete[MAX_DIFFICULTIES];
359 unsigned int        noshowhof[MAX_DIFFICULTIES];
360 unsigned int        difflives[MAX_DIFFICULTIES];				// What too easy?  change the # of lives players get
361 unsigned int        custfade[MAX_DIFFICULTIES];
362 unsigned int        diffcreds[MAX_DIFFICULTIES];				// What still to easy - lets see how they do without continues!
363 unsigned int        diffoverlap[MAX_DIFFICULTIES];				// Music overlap
364 unsigned int        typemp[MAX_DIFFICULTIES];
365 unsigned int        continuescore[MAX_DIFFICULTIES];             //what to do with score if continue is used.
366 char*               (*skipselect)[MAX_DIFFICULTIES][MAX_PLAYERS] = NULL;              // skips select screen and automatically gives players models specified
367 int                 cansave_flag[MAX_DIFFICULTIES];             // 0, no save, 1 save level position 2 save all: lives/credits/hp/mp/also player
368 int                 same[MAX_DIFFICULTIES];						// ltb 1-13-05   sameplayer
369 */
370 int                 cameratype          = 0;
371 int					defaultmaxplayers	= 2;
372 
373 u32                 go_time             = 0;
374 u32                 time                = 0;
375 u32                 newtime             = 0;
376 unsigned char       slowmotion[3]       = {0,2,0};              // [0] = enable/disable; [1] = duration; [2] = counter;
377 int                 disablelog          = 0;
378 int                 currentspawnplayer  = 0;
379 int					ent_list_size		= 0;
380 int                 PLAYER_MIN_Z        = 160;
381 int                 PLAYER_MAX_Z        = 232;
382 int                 BGHEIGHT            = 160;
383 int                 MAX_WALL_HEIGHT     = 1000;					// Max wall height that an entity can be spawned on
384 int                 saveslot            = 0;
385 int                 current_palette     = 0;
386 int                 fade                = 24;
387 int                 credits             = 0;
388 int                 gosound             = 0;					// Used to prevent go sound playing too frequently,
389 int                 musicoverlap        = 0;
390 int                 colorbars           = 0;
391 int                 current_spawn       = 0;
392 int                 level_completed     = 0;
393 int                 nojoin              = 0;					// dont allow new hero to join in, use "Please Wait" instead of "Select Hero"
394 int                 groupmin            = 0;
395 int					groupmax            = 0;
396 int                 selectScreen        = 0;					// Flag to determine if at select screen (used for setting animations)
397 int					titleScreen			= 0;
398 int					menuScreen			= 0;
399 int					hallOfFame			= 0;
400 int					gameOver			= 0;
401 int					showComplete		= 0;
402 char*				currentScene		= NULL;
403 int                 tospeedup           = 0;          			// If set will speed the level back up after a boss hits the ground
404 int                 reached[4]          = {0,0,0,0};			// Used with TYPE_ENDLEVEL to determine which players have reached the point //4player
405 int                 noslowfx			= 0;           			// Flag to determine if sound speed when hitting opponent slows or not
406 int                 equalairpause 		= 0;         			// If set to 1, there will be no extra pausetime for players who hit multiple enemies in midair
407 int                 hiscorebg			= 0;					// If set to 1, will look for a background image to display at the highscore screen
408 int                 completebg			= 0;           			// If set to 1, will look for a background image to display at the showcomplete screen
409 s_loadingbar        loadingbg[2] = {{0,0,0,0,0,0,0},{0,0,0,0,0,0,0}};  // If set to 1, will look for a background image to display at the loading screen
410 int					loadingmusic        = 0;
411 int                 unlockbg            = 0;         			// If set to 1, will look for a different background image after defeating the game
412 int                 pause               = 0;
413 int					nofadeout			= 0;
414 int					nosave				= 0;
415 int                 nopause             = 0;                    // OX. If set to 1 , pausing the game will be disabled.
416 int                 noscreenshot        = 0;                    // OX. If set to 1 , taking screenshots is disabled.
417 int                 endgame             = 0;
418 int                 forcecheatsoff      = 0;
419 int                 cheats              = 0;
420 int                 livescheat          = 0;
421 int                 keyscriptrate       = 0;
422 int                 creditscheat        = 0;
423 int                 healthcheat         = 0;
424 int                 showtimeover        = 0;
425 int                 sameplayer          = 0;            		// 7-1-2005  flag to determine if players can use the same character
426 int                 PLAYER_LIVES        = 3;					// 7-1-2005  default setting for Lives
427 int                 CONTINUES           = 5;					// 7-1-2005  default setting for continues
428 int                 colourselect		= 0;					// 6-2-2005 Colour select is optional
429 int                 autoland			= 0;					// Default set to no autoland and landing is valid with u j combo
430 int                 ajspecial			= 0;					// Flag to determine if holding down attack and pressing jump executes special
431 int                 nolost				= 0;					// variable to control if drop weapon when grab a enemy by tails
432 int                 nocost				= 0;					// If set, special will not cost life unless an enemy is hit
433 int                 mpstrict			= 0;					// If current system will check all animation's energy cost when set new animations
434 int                 magic_type			= 0;					// use for restore mp by time by tails
435 entity*             textbox				= NULL;
436 entity*             smartbomber			= NULL;
437 entity*				stalker				= NULL;					// an enemy (usually) tries to go behind the player
438 entity*				firstplayer			= NULL;
439 int					stalking			= 0;
440 int					nextplan			= 0;
441 int                 plife[4][2]         = {{0,0},{0,0},{0,0},{0,0}};// Used for customizable player lifebar
442 int                 plifeX[4][3]        = {{0,0,-1},{0,0,-1},{0,0,-1},{0,0,-1}};// Used for customizable player lifebar 'x'
443 int                 plifeN[4][3]        = {{0,0,-1},{0,0,-1},{0,0,-1},{0,0,-1}};// Used for customizable player lifebar number of lives
444 int                 picon[4][2]         = {{0,0},{0,0},{0,0},{0,0}};// Used for customizable player icon
445 int                 piconw[4][2]        = {{0,0},{0,0},{0,0},{0,0}};// Used for customizable player weapon icons
446 int                 mpicon[4][2]        = {{0,0},{0,0},{0,0},{0,0}};// Used for customizable magicbar player icon
447 int                 pnameJ[4][7]        = {{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1}};// Used for customizable player name, Select Hero, (Credits, Press Start, Game Over) when joining
448 int                 pscore[4][7]        = {{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1}};// Used for customizable player name, dash, score
449 int                 pshoot[4][3]        = {{0,0,-1},{0,0,-1},{0,0,-1},{0,0,-1}};// Used for customizable player shootnum
450 int                 prush[4][8]         = {{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}};// Used for customizable player combo/rush system
451 int                 psmenu[4][4]        = {{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}};// Used for customizable player placement in select menu
452 int                 mpcolourtable[11]   = {0,0,0,0,0,0,0,0,0,0,0};
453 int                 hpcolourtable[11]   = {0,0,0,0,0,0,0,0,0,0,0};
454 int                 ldcolourtable[11]   = {0,0,0,0,0,0,0,0,0,0,0};
455 char                musicname[128]      = {""};
456 char                currentmusic[128]    = {""};
457 float               musicfade[2]        = {0,0};
458 int                 musicloop           = 0;
459 u32                 musicoffset         = 0;
460 int					alwaysupdate		= 0; //execute update/updated scripts whenever it has a chance
461 
462 s_barstatus         loadingbarstatus =
463 {
464 	0,                          //int          offsetx:16;
465 	0,                          //int          offsety:16;
466 	0,                          //int          sizex:16;
467 	10,                          //int          sizey:16;
468 	percentagebar,                   //bartype      type:8;
469 	horizontalbar,              //barorient    orientation:8;
470 	0,                          //int          noborder:8;
471 	0,                          //int          direction:8;
472 	0,                          //int          barlayer;
473 	0,                          //int          backlayer;
474 	0,                          //int          borderlayer;
475 	0,                          //int          shadowlayer;
476 	&ldcolourtable
477 };
478 s_barstatus         lbarstatus =                                // Used for customizable lifebar size
479 {
480 	0,                          //int          offsetx:16;
481 	0,                          //int          offsety:16;
482 	0,                          //int          sizex:16;
483 	0,                          //int          sizey:16;
484 	valuebar,                   //bartype      type:8;
485 	horizontalbar,              //barorient    orientation:8;
486 	0,                          //int          noborder:8;
487 	0,                          //int          direction:8;
488 	0,                          //int          barlayer;
489 	0,                          //int          backlayer;
490 	0,                          //int          borderlayer;
491 	0,                          //int          shadowlayer;
492 	&hpcolourtable
493 };
494 s_barstatus         olbarstatus =                               // Used for customizable opponent lifebar size
495 {
496 	0,                          //int          offsetx:16;
497 	0,                          //int          offsety:16;
498 	0,                          //int          sizex:16;
499 	0,                          //int          sizey:16;
500 	valuebar,                   //bartype      type:8;
501 	horizontalbar,              //barorient    orientation:8;
502 	0,                          //int          noborder:8;
503 	0,                          //int          direction:8;
504 	0,                          //int          barlayer;
505 	0,                          //int          backlayer;
506 	0,                          //int          borderlayer;
507 	0,                          //int          shadowlayer;
508 	&hpcolourtable
509 };
510 int                 timeloc[6]			= {0,0,0,0,0,-1};		// Used for customizable timeclock location/size
511 int                 timeicon			= -1;
512 short               timeicon_offsets[2] = {0,0};
513 char                timeicon_path[128]  = {""};
514 int                 bgicon   			= -1;
515 short               bgicon_offsets[3]	= {0,0,0};
516 char                bgicon_path[128]    = {""};
517 int                 olicon    			= -1;
518 short               olicon_offsets[3]	= {0,0,0};
519 char                olicon_path[128]    = {""};
520 int                 elife[4][2]         = {{0,0},{0,0},{0,0},{0,0}};// Used for customizable enemy lifebar
521 int                 ename[4][3]         = {{0,0,-1},{0,0,-1},{0,0,-1},{0,0,-1}};// Used for customizable enemy name
522 int                 eicon[4][2]         = {{0,0},{0,0},{0,0},{0,0}};// Used for customizable enemy icon
523 int                 scomplete[6]		= {0,0,0,0,0,0};		// Used for customizable Stage # Complete
524 int                 cbonus[10]          = {0,0,0,0,0,0,0,0,0,0};// Used for customizable clear bonus
525 int                 lbonus[10]          = {0,0,0,0,0,0,0,0,0,0};// Used for customizable life bonus
526 int                 rbonus[10]          = {0,0,0,0,0,0,0,0,0,0};// Used for customizable rush bonus
527 int                 tscore[10]          = {0,0,0,0,0,0,0,0,0,0};// Used for customizable total score
528 int                 scbonuses[4]        = {10000, 1000, 100, 0};//Stage complete bonus multipliers
529 int                 showrushbonus       = 0;
530 int                 noshare				= 0;					// Used for when you want to keep p1 & p2 credits separate
531 int                 nodropen			= 0;					// Drop or not when spawning is now a modder option
532 int					nodropspawn			= 0;					// don't spawn from the sky if the modder doesn't set it
533 int                 gfx_x_offset		= 0;                    //2011_04_03, DC: Enable X offset adjustment by modders.
534 int                 gfx_y_offset		= 0;
535 int                 gfx_y_offset_adj    = 0;                    //2011_04_03, DC: Enable Y offset adjustment by modders.
536 
537 // 2011/10/22 UT: temporary solution for custom viewport
538 int					viewportx			= 0;
539 int					viewporty			= 0;
540 int					viewportw			= 0;
541 int					viewporth			= 0;
542 
543 
544 int                 timeleft			= 0;
545 int                 oldtime             = 0;                    // One second back from time left.
546 int                 holez				= 0;					// Used for setting spawn points
547 int                 allow_secret_chars	= 0;
548 unsigned int        lifescore			= 50000;				// Number of points needed to earn a 1-up
549 unsigned int        credscore			= 0;					// Number of points needed to earn a credit
550 int                 mpblock				= 0;					// Take chip damage from health or MP first?
551 int                 blockratio			= 0;					// Take half-damage while blocking?
552 int                 nochipdeath			= 0;					// Prevents entities from dying due to chip damage (damage while blocking)
553 int                 noaircancel         = 0;					// Now, you can make jumping attacks uncancellable!
554 int                 nomaxrushreset[5]   = {0,0,0,0,0};
555 s_barstatus         mpbarstatus =                               // Used for customizable lifebar size
556 {
557 	0,                          //int          offsetx:16;
558 	0,                          //int          offsety:16;
559 	0,                          //int          sizex:16;
560 	0,                          //int          sizey:16;
561 	valuebar,                   //bartype      type:8;
562 	horizontalbar,              //barorient    orientation:8;
563 	0,                          //int          noborder:8;
564 	0,                          //int          direction:8;
565 	0,                          //int          barlayer;
566 	0,                          //int          backlayer;
567 	0,                          //int          borderlayer;
568 	0,                          //int          shadowlayer;
569 	&mpcolourtable
570 };
571 int			        mpbartext[4]		= {-1,0,0,0};			// Array for adjusting MP status text (font, Xpos, Ypos, Display type).
572 int			        lbartext[4]			= {-1,0,0,0};			// Array for adjusting HP status text (font, Xpos, Ypos, Display type).
573 int                 pmp[4][2]			= {{0,0},{0,0},{0,0},{0,0}};// Used for customizable player mpbar
574 int                 spdirection[4]		= {1,0,1,0};			// Used for Select Player Direction for select player screen
575 int                 bonus				= 0;					// Used for unlocking Bonus difficulties
576 int                 versusdamage		= 2;					// Used for setting mode. (ability to hit other players)
577 int                 z_coords[3]			= {0,0,0};				// Used for setting customizable walkable area
578 int                 rush[6]				= {0,2,3,3,3,3};
579 int                 color_black			= 0;
580 int                 color_red			= 0;
581 int                 color_orange		= 0;
582 int                 color_yellow		= 0;
583 int                 color_white			= 0;
584 int                 color_blue			= 0;
585 int                 color_green			= 0;
586 int                 color_pink			= 0;
587 int                 color_purple		= 0;
588 int                 color_magic			= 0;
589 int                 color_magic2		= 0;
590 int                 lifebarfgalpha      = 0;
591 int                 lifebarbgalpha      = 2;
592 int                 shadowsprites[6]	= {-1,-1,-1,-1,-1,-1};
593 int                 gosprite			= -1;
594 int                 golsprite			= -1;
595 int                 holesprite			= -1;
596 int                 videoMode			= 0;
597 int                 scoreformat			= 0;					// If set fill score values with 6 Zeros
598 
599 // Funny neon lights
600 unsigned char       neontable[MAX_PAL_SIZE];
601 unsigned int        neon_time			= 0;
602 
603 int                 panel_width			= 0;
604 int                 panel_height		= 0;
605 int                 frontpanels_loaded	= 0;
606 
607 unsigned int        sprites_loaded		= 0;
608 unsigned int        anims_loaded		= 0;
609 
610 unsigned int        models_loaded		= 0;
611 unsigned int        models_cached		= 0;
612 
613 entity**            ent_list;
614 entity*             self;
615 int                 ent_count			= 0;					// log count of entites
616 int                 ent_max				= 0;
617 
618 s_player            player[4];
619 u32                 bothkeys, bothnewkeys;
620 
621 s_playercontrols    playercontrols1;
622 s_playercontrols    playercontrols2;
623 s_playercontrols    playercontrols3;
624 s_playercontrols    playercontrols4;
625 s_playercontrols*   playercontrolpointers[] = {&playercontrols1, &playercontrols2, &playercontrols3, &playercontrols4};
626 
627 
628 //global script
629 Script level_script;    //execute when level start
630 Script endlevel_script; //execute when level finished
631 Script update_script;   //execute when ingame update
632 Script updated_script;  //execute when ingame update finished
633 Script loading_script;	// in loading screen
634 Script key_script_all;  //keyscript for all players
635 Script timetick_script; //time tick script.
636 
637 //player script
638 Script score_script[4];     //execute when add score, 4 players
639 Script key_script[4];       //key listeners, lol
640 Script join_script[4];      //player join scripts
641 Script respawn_script[4];   //player respawn scripts
642 Script pdie_script[4];      //player death scripts
643 
644 extern Script* pcurrentscript;//used by local script functions
645 //-------------------------methods-------------------------------
646 
setDrawMethod(s_anim * a,ptrdiff_t index,s_drawmethod * m)647 void setDrawMethod(s_anim* a, ptrdiff_t index, s_drawmethod* m) {
648 	assert(index >= 0);
649 	assert(a != NULL);
650 	assert(m != NULL);
651 	assert(index < a->numframes);
652 	a->drawmethods[index] = m;
653 }
654 
getDrawMethod(s_anim * a,ptrdiff_t index)655 s_drawmethod* getDrawMethod(s_anim* a, ptrdiff_t index) {
656 	assert(index >= 0);
657 	assert(a != NULL);
658 	assert(index < a->numframes);
659 	return a->drawmethods[index];
660 }
661 
isLoadingScreenTypeBg(loadingScreenType what)662 int isLoadingScreenTypeBg(loadingScreenType what) {
663 	return (what & LSTYPE_BACKGROUND) == LSTYPE_BACKGROUND;
664 }
665 
isLoadingScreenTypeBar(loadingScreenType what)666 int isLoadingScreenTypeBar(loadingScreenType what) {
667 	return (what & LSTYPE_BAR) == LSTYPE_BAR;
668 }
669 
fill_s_loadingbar(s_loadingbar * s,char set,short bx,short by,short bsize,short tx,short ty,char tf,int ms)670 char* fill_s_loadingbar(s_loadingbar* s, char set, short bx, short by, short bsize, short tx, short ty, char tf, int ms) {
671 	switch (set) {
672 		case 1: s->set = (LSTYPE_BACKGROUND | LSTYPE_BAR); break;
673 		case 2: s->set = LSTYPE_BACKGROUND; break;
674 		case 3: s->set = LSTYPE_BAR; break;
675 		case 0: s->set = LSTYPE_NONE; break;
676 		default:
677 			s->set = LSTYPE_NONE;
678 			printf("invalid loadingbg type %d!\n", set);
679 	}
680 	s->tf = tf;
681 	s->bx = bx;
682 	s->by = by;
683 	s->bsize = bsize;
684 	s->tx = tx;
685 	s->ty = ty;
686 	s->refreshMs = (ms ? ms : 100);
687 	return NULL;
688 }
689 
690 
691 // returns: 1 - succeeded 0 - failed
buffer_pakfile(char * filename,char ** pbuffer,size_t * psize)692 int buffer_pakfile(char* filename, char** pbuffer, size_t* psize)
693 {
694 	int handle;
695 	*psize = 0;
696 	*pbuffer = NULL;
697 	// Read file
698 #ifdef VERBOSE
699 	printf("pakfile requested: %s.\n", filename); //ASDF
700 #endif
701 
702 	if((handle=openpackfile(filename,packfile)) < 0) {
703 #ifdef VERBOSE
704 		printf("couldnt get handle!\n");
705 #endif
706 		return 0;
707 	}
708 	*psize = seekpackfile(handle,0,SEEK_END);
709 	seekpackfile(handle,0,SEEK_SET);
710 
711 	*pbuffer = (char*)malloc(*psize+1);
712 	if(*pbuffer == NULL){
713 		*psize = 0;
714 		closepackfile(handle);
715 		shutdown(1, "Can't create buffer for packfile '%s'", filename);
716 		return 0;
717 	}
718 	if(readpackfile(handle, *pbuffer, *psize) != *psize){
719 		if(*pbuffer != NULL){
720 			free(*pbuffer);
721 			*pbuffer = NULL;
722 			*psize = 0;
723 		}
724 		closepackfile(handle);
725 		shutdown(1, "Can't read from packfile '%s'", filename);
726 		return 0;
727 	}
728 	(*pbuffer)[*psize] = 0;        // Terminate string (important!)
729 	closepackfile(handle);
730 	return 1;
731 }
732 
buffer_append(char ** buffer,const char * str,size_t n,size_t * bufferlen,size_t * len)733 int buffer_append(char** buffer, const char* str, size_t n, size_t* bufferlen, size_t *len)
734 {
735 	size_t appendlen = strlen(str);
736 	if(appendlen>n) appendlen = n;
737 	if(appendlen+*len+1>*bufferlen)
738 	{
739 		printf("*Debug* reallocating buffer...\n");
740 		*buffer = realloc(*buffer, *bufferlen=appendlen+*len+1024);
741 		if(*buffer==NULL) shutdown(1, "Unalbe to resize buffer.\n");
742 	}
743 	strncpy(*buffer+*len, str, appendlen);
744 	*len = *len + appendlen;
745 	(*buffer)[*len] = 0;
746 	return *len;
747 }
748 
handle_txt_include(char * command,ArgList * arglist,char ** fn,char * namebuf,char ** buf,ptrdiff_t * pos,size_t * len)749 int handle_txt_include(char* command, ArgList *arglist, char** fn, char* namebuf, char** buf, ptrdiff_t* pos, size_t* len)
750 {
751 	char* incfile, *filename=*fn, *buf2, *endstr="\r\n@end";
752 	size_t size, t;
753 	if(stricmp(command, "@include")==0){
754 		incfile = GET_ARGP(1);
755 		buffer_pakfile(incfile, &buf2, &size) ;
756 		if(buf2){
757 			*buf = realloc(*buf, *len+size+strlen(incfile)+strlen(filename)+100); //leave enough memory for jump command
758 			if(*buf==NULL) {
759 				shutdown(1, "Unalbe to resize buffer. (handle_txt_include)\n");
760 				free(buf2);
761 				return 0;
762 			}
763 			sprintf((*buf)+*len-1, "%s\r\n@filename %s\r\n", endstr, incfile);
764 			strcat((*buf)+*len, buf2);
765 			t = strlen(*buf);
766 			sprintf((*buf)+t, "\r\n@filename %s\r\n@jump %d\r\n", filename, (int)(*pos));
767 			(*buf)[*pos] = '#';
768 			*pos = *len + strlen(endstr); //continue from the new file position
769 			*len = strlen(*buf);
770 			free(buf2);
771 			//printf(*buf);
772 			return 1;
773 		}
774 		shutdown(1, "Can't find file '%s' to include.\n", incfile);
775 	}else if(stricmp(command, "@jump")==0){
776 		*pos = GET_INT_ARGP(1);
777 		return 2;
778 	}else if(stricmp(command, "@end")==0){
779 		*pos = *len;
780 		return 3;
781 	}else if(stricmp(command, "@filename")==0){
782 		strcpy(namebuf, GET_ARGP(1));
783 		*fn = namebuf;
784 		return 4;
785 	}
786 	return 0;
787 }
788 
789 //this method is used by script engine, we move it here
790 // it will get a system property, put it in the ScriptVariant
791 // if failed return 0, otherwise return 1
getsyspropertybyindex(ScriptVariant * var,int index)792 int getsyspropertybyindex(ScriptVariant* var, int index)
793 {
794 	if(!var) return 0;
795 
796 	switch(index)
797 	{
798 	case _sv_count_enemies:
799 		ScriptVariant_ChangeType(var, VT_INTEGER);
800 		var->lVal = (LONG)count_ents(TYPE_ENEMY);
801 		break;
802 	case _sv_count_players:
803 		ScriptVariant_ChangeType(var, VT_INTEGER);
804 		var->lVal = (LONG)count_ents(TYPE_PLAYER);
805 		break;
806 	case _sv_count_npcs:
807 		ScriptVariant_ChangeType(var, VT_INTEGER);
808 		var->lVal = (LONG)count_ents(TYPE_NPC);
809 		break;
810 	case _sv_count_entities:
811 		ScriptVariant_ChangeType(var, VT_INTEGER);
812 		var->lVal = (LONG)ent_count;
813 		break;
814 	case _sv_ent_max:
815 		ScriptVariant_ChangeType(var, VT_INTEGER);
816 		var->lVal = (LONG)ent_max;
817 		break;
818 	case _sv_in_level:
819 		ScriptVariant_ChangeType(var, VT_INTEGER);
820 		var->lVal = (LONG)(level != NULL);
821 		break;
822 	case _sv_in_gameoverscreen:
823 		ScriptVariant_ChangeType(var, VT_INTEGER);
824 		var->lVal = (LONG)(gameOver);
825 		break;
826 	case _sv_in_menuscreen:
827 		ScriptVariant_ChangeType(var, VT_INTEGER);
828 		if(selectScreen || titleScreen || hallOfFame || gameOver || showComplete || currentScene || level)
829 			var->lVal = (LONG)0;
830 		else var->lVal = (LONG)(menuScreen);
831 		break;
832 	case _sv_in_showcomplete:
833 		ScriptVariant_ChangeType(var, VT_INTEGER);
834 		var->lVal = (LONG)(showComplete);
835 		break;
836 	case _sv_in_titlescreen:
837 		ScriptVariant_ChangeType(var, VT_INTEGER);
838 		var->lVal = (LONG)(titleScreen);
839 		break;
840 	case _sv_in_halloffamescreen:
841 		ScriptVariant_ChangeType(var, VT_INTEGER);
842 		var->lVal = (LONG)(hallOfFame);
843 		break;
844 	case _sv_effectvol:
845 		ScriptVariant_ChangeType(var, VT_INTEGER);
846 		var->lVal = (LONG)savedata.effectvol;
847 		break;
848 	case _sv_elapsed_time:
849 		ScriptVariant_ChangeType(var, VT_INTEGER);
850 		var->lVal = (LONG)time;
851 		break;
852 	case _sv_game_speed:
853 		if(!level) return 0;
854 		ScriptVariant_ChangeType(var, VT_INTEGER);
855 		var->lVal = (LONG)GAME_SPEED;
856 		break;
857 	case _sv_pause:
858 		ScriptVariant_ChangeType(var, VT_INTEGER);
859 		var->lVal = (LONG)pause;
860 		break;
861     case _sv_gfx_x_offset:
862 		if(!level) return 0;
863 		ScriptVariant_ChangeType(var, VT_INTEGER);
864 		var->lVal = (LONG)gfx_x_offset;
865 		break;
866 	case _sv_gfx_y_offset:
867 		if(!level) return 0;
868 		ScriptVariant_ChangeType(var, VT_INTEGER);
869 		var->lVal = (LONG)gfx_y_offset;
870 		break;
871     case _sv_gfx_y_offset_adj:
872 		if(!level) return 0;
873 		ScriptVariant_ChangeType(var, VT_INTEGER);
874 		var->lVal = (LONG)gfx_y_offset_adj;
875 		break;
876 	case _sv_in_selectscreen:
877 		ScriptVariant_ChangeType(var, VT_INTEGER);
878 		var->lVal = (LONG)(selectScreen);
879 		break;
880 	case _sv_lasthita:
881 		ScriptVariant_ChangeType(var, VT_DECIMAL);
882 		var->dblVal = (DOUBLE)(lasthita);
883 		break;
884 	case _sv_lasthitc:
885 		ScriptVariant_ChangeType(var, VT_INTEGER);
886 		var->lVal = (LONG)(lasthitc);
887 		break;
888 	case _sv_lasthitt:
889 		ScriptVariant_ChangeType(var, VT_INTEGER);
890 		var->lVal = (LONG)(lasthitt);
891 		break;
892 	case _sv_lasthitx:
893 		ScriptVariant_ChangeType(var, VT_DECIMAL);
894 		var->dblVal = (DOUBLE)(lasthitx);
895 		break;
896 	case _sv_lasthitz:
897 		ScriptVariant_ChangeType(var, VT_DECIMAL);
898 		var->dblVal = (DOUBLE)(lasthitz);
899 		break;
900 	case _sv_xpos:
901 		if(!level) return 0;
902 		ScriptVariant_ChangeType(var, VT_DECIMAL);
903 		var->dblVal = (DOUBLE)advancex;
904 		break;
905 	case _sv_ypos:
906 		if(!level) return 0;
907 		ScriptVariant_ChangeType(var, VT_DECIMAL);
908 		var->dblVal = (DOUBLE)advancey;
909 		break;
910 	case _sv_hResolution:
911 		ScriptVariant_ChangeType(var, VT_INTEGER);
912 		var->lVal = (LONG)videomodes.hRes;
913 		break;
914 	case _sv_vResolution:
915 		ScriptVariant_ChangeType(var, VT_INTEGER);
916 		var->lVal = (LONG)videomodes.vRes;
917 		break;
918 	case _sv_current_scene:
919 		if(currentScene){
920 			ScriptVariant_ChangeType(var, VT_STR);
921 			strcpy(StrCache_Get(var->strVal), currentScene);
922 		}else ScriptVariant_Clear(var);
923 		break;
924 	case _sv_current_set:
925 		ScriptVariant_ChangeType(var, VT_INTEGER);
926 		var->lVal = (LONG)(current_set);
927 		break;
928 	case _sv_current_level:
929 		ScriptVariant_ChangeType(var, VT_INTEGER);
930 		var->lVal = (LONG)(current_level);
931 		break;
932 	case _sv_current_palette:
933 		ScriptVariant_ChangeType(var, VT_INTEGER);
934 		var->lVal = (LONG)(current_palette);
935 		break;
936 	case _sv_current_stage:
937 		ScriptVariant_ChangeType(var, VT_INTEGER);
938 		var->lVal = (LONG)(current_stage);
939 		break;
940 	case _sv_levelwidth:
941 		if(!level) return 0;
942 		ScriptVariant_ChangeType(var, VT_INTEGER);
943 		var->lVal = (LONG)(level->width);
944 		break;
945 	case _sv_levelheight:
946 		if(!level) return 0;
947 		ScriptVariant_ChangeType(var, VT_INTEGER);
948 		var->lVal = (LONG)(panel_height);
949 		break;
950 	case _sv_branchname:
951 		ScriptVariant_ChangeType(var, VT_STR);
952 		strcpy(StrCache_Get(var->strVal), branch_name);
953 		break;
954 	case _sv_current_branch:
955 		ScriptVariant_ChangeType(var, VT_STR);
956 		if(levelsets[current_set].levelorder[current_level].branchname)
957 			strcpy(StrCache_Get(var->strVal), levelsets[current_set].levelorder[current_level].branchname);
958 		else ScriptVariant_Clear(var);
959 		break;
960 	case _sv_pakname:
961 		ScriptVariant_ChangeType(var, VT_STR);
962 		getPakName(StrCache_Get(var->strVal), -1);
963 		break;
964 	case _sv_maxentityvars:
965 		ScriptVariant_ChangeType(var, VT_INTEGER);
966 		var->lVal = (LONG)max_entity_vars;
967 		break;
968 	case _sv_maxglobalvars:
969 		ScriptVariant_ChangeType(var, VT_INTEGER);
970 		var->lVal = (LONG)max_global_vars;
971 		break;
972 	case _sv_maxindexedvars:
973 		ScriptVariant_ChangeType(var, VT_INTEGER);
974 		var->lVal = (LONG)max_indexed_vars;
975 		break;
976 	case _sv_maxplayers:
977 		ScriptVariant_ChangeType(var, VT_INTEGER);
978 		var->lVal = (LONG)levelsets[current_set].maxplayers;
979 		break;
980 	case _sv_maxscriptvars:
981 		ScriptVariant_ChangeType(var, VT_INTEGER);
982 		var->lVal = (LONG)max_script_vars;
983 		break;
984 	case _sv_models_cached:
985 		ScriptVariant_ChangeType(var, VT_INTEGER);
986 		var->lVal = (LONG)models_cached;
987 		break;
988 	case _sv_models_loaded:
989 		ScriptVariant_ChangeType(var, VT_INTEGER);
990 		var->lVal = (LONG)models_loaded;
991 		break;
992 	case _sv_musicvol:
993 		ScriptVariant_ChangeType(var, VT_INTEGER);
994 		var->lVal = (LONG)savedata.musicvol;
995 		break;
996 	case _sv_nofadeout:
997 		ScriptVariant_ChangeType(var, VT_INTEGER);
998 		var->lVal = (LONG)nofadeout;
999 		break;
1000 	case _sv_nopause:
1001 		ScriptVariant_ChangeType(var, VT_INTEGER);
1002 		var->lVal = (LONG)nopause;
1003 		break;
1004 	case _sv_nosave:
1005 		ScriptVariant_ChangeType(var, VT_INTEGER);
1006 		var->lVal = (LONG)nosave;
1007 		break;
1008 	case _sv_noscreenshot:
1009 		ScriptVariant_ChangeType(var, VT_INTEGER);
1010 		var->lVal = (LONG)noscreenshot;
1011 		break;
1012 	case _sv_numpalettes:
1013 		ScriptVariant_ChangeType(var, VT_INTEGER);
1014 		var->lVal = (LONG)(level->numpalettes);
1015 		break;
1016 	case _sv_pixelformat:
1017 		ScriptVariant_ChangeType(var, VT_INTEGER);
1018 		var->lVal = (LONG)pixelformat;
1019 		break;
1020 	case _sv_player:
1021 	case _sv_player1:
1022 		ScriptVariant_ChangeType(var, VT_PTR);
1023 		var->ptrVal = (VOID*)player;
1024 		break;
1025 	case _sv_player2:
1026 		ScriptVariant_ChangeType(var, VT_PTR);
1027 		var->ptrVal = (VOID*)(player+1);
1028 		break;
1029 	case _sv_player3:
1030 		ScriptVariant_ChangeType(var, VT_PTR);
1031 		var->ptrVal = (VOID*)(player+2);
1032 		break;
1033 	case _sv_player4:
1034 		ScriptVariant_ChangeType(var, VT_PTR);
1035 		var->ptrVal = (VOID*)(player+3);
1036 		break;
1037 	case _sv_player_max_z:
1038 		ScriptVariant_ChangeType(var, VT_INTEGER);
1039 		var->lVal = (LONG)(PLAYER_MAX_Z);
1040 		break;
1041 	case _sv_player_min_z:
1042 		ScriptVariant_ChangeType(var, VT_INTEGER);
1043 		var->lVal = (LONG)(PLAYER_MIN_Z);
1044 		break;
1045 	case _sv_lightx:
1046 		ScriptVariant_ChangeType(var, VT_INTEGER);
1047 		var->lVal = (LONG)(light[0]);
1048 		break;
1049 	case _sv_lightz:
1050 		ScriptVariant_ChangeType(var, VT_INTEGER);
1051 		var->lVal = (LONG)(light[1]);
1052 		break;
1053 	case _sv_self:
1054 		ScriptVariant_ChangeType(var, VT_PTR);
1055 		var->ptrVal = (VOID*)self;
1056 		break;
1057 	case _sv_shadowalpha:
1058 		ScriptVariant_ChangeType(var, VT_INTEGER);
1059 		var->lVal = (LONG)shadowalpha;
1060 		break;
1061 	case _sv_shadowcolor:
1062 		ScriptVariant_ChangeType(var, VT_INTEGER);
1063 		var->lVal = (LONG)shadowcolor;
1064 		break;
1065 	case _sv_skiptoset:
1066 		ScriptVariant_ChangeType(var, VT_INTEGER);
1067 		var->lVal = (LONG)skiptoset;
1068 		break;
1069 	case _sv_slowmotion:
1070 		ScriptVariant_ChangeType(var, VT_INTEGER);
1071 		var->lVal = (LONG)slowmotion[0];
1072 		break;
1073 	case _sv_slowmotion_duration:
1074 		ScriptVariant_ChangeType(var, VT_INTEGER);
1075 		var->lVal = (LONG)slowmotion[1];
1076 		break;
1077 	case _sv_soundvol:
1078 		ScriptVariant_ChangeType(var, VT_INTEGER);
1079 		var->lVal = (LONG)savedata.soundvol;
1080 		break;
1081 	case _sv_game_paused:
1082 		ScriptVariant_ChangeType(var, VT_INTEGER);
1083 		var->lVal = (LONG)pause;
1084 		break;
1085 	case _sv_totalram:
1086 		 ScriptVariant_ChangeType(var, VT_INTEGER);
1087 		 var->lVal = (LONG)getSystemRam(KBYTES);
1088 		break;
1089 	case _sv_freeram:
1090 		ScriptVariant_ChangeType(var, VT_INTEGER);
1091 		var->lVal = (LONG)getFreeRam(KBYTES);
1092 		break;
1093 	case _sv_usedram:
1094 		 ScriptVariant_ChangeType(var, VT_INTEGER);
1095 		 var->lVal = (LONG)getUsedRam(KBYTES);
1096 		break;
1097 	case _sv_usesave:
1098 		 ScriptVariant_ChangeType(var, VT_INTEGER);
1099 		 var->lVal = (LONG)useSave;
1100 		break;
1101 	case _sv_background:
1102 		ScriptVariant_ChangeType(var, VT_PTR);
1103 		var->ptrVal = (VOID*)background;
1104 		break;
1105 	case _sv_vscreen:
1106 		ScriptVariant_ChangeType(var, VT_PTR);
1107 		var->ptrVal = (VOID*)vscreen;
1108 		break;
1109 	case _sv_viewportx:
1110 		ScriptVariant_ChangeType(var, VT_INTEGER);
1111 		var->lVal = (LONG)viewportx;
1112 		break;
1113 	case _sv_viewporty:
1114 		ScriptVariant_ChangeType(var, VT_INTEGER);
1115 		var->lVal = (LONG)viewporty;
1116 		break;
1117 	case _sv_viewportw:
1118 		ScriptVariant_ChangeType(var, VT_INTEGER);
1119 		var->lVal = (LONG)viewportw;
1120 		break;
1121 	case _sv_viewporth:
1122 		ScriptVariant_ChangeType(var, VT_INTEGER);
1123 		var->lVal = (LONG)viewporth;
1124 		break;
1125 	case _sv_waiting:
1126 		ScriptVariant_ChangeType(var, VT_INTEGER);
1127 		var->lVal = level?(LONG)level->waiting:0;
1128 	case _sv_maxattacktypes:
1129 		ScriptVariant_ChangeType(var, VT_INTEGER);
1130 		var->lVal = (LONG)max_attack_types;
1131 		break;
1132 	case _sv_maxanimations:
1133 		ScriptVariant_ChangeType(var, VT_INTEGER);
1134 		var->lVal = (LONG)max_animations;
1135 		break;
1136 	case _sv_ticks:
1137 		ScriptVariant_ChangeType(var, VT_INTEGER);
1138 		var->lVal = (LONG)timer_gettick();
1139 		break;
1140 	default:
1141 		// We use indices now, but players/modders don't need to be exposed
1142 		// to that implementation detail, so we write "name" and not "index".
1143 		printf("Unknown system property name.\n");
1144 		return 0;
1145 	}
1146 	return 1;
1147 }
1148 
1149 // change a system variant, used by script
changesyspropertybyindex(int index,ScriptVariant * value)1150 int changesyspropertybyindex(int index, ScriptVariant* value)
1151 {
1152 	//char* tempstr = NULL;
1153 	LONG ltemp;
1154 	//DOUBLE dbltemp;
1155 
1156 	switch(index)
1157 	{
1158 	case _sv_elapsed_time:
1159 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1160 			time = (int)ltemp;
1161 		break;
1162 	case _sv_current_stage:
1163 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1164 			current_stage = (int)ltemp;
1165 		break;
1166 	case _sv_current_set:
1167 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1168 			current_set = (int)ltemp;
1169 		break;
1170 	case _sv_current_level:
1171 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1172 			current_level = (int)ltemp;
1173 		break;
1174     case _sv_gfx_x_offset:
1175 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1176 			gfx_x_offset = (int)ltemp;
1177 		break;
1178     case _sv_gfx_y_offset:
1179 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1180 			gfx_y_offset = (int)ltemp;
1181 		break;
1182     case _sv_gfx_y_offset_adj:
1183 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1184 			gfx_y_offset_adj = (int)ltemp;
1185 		break;
1186 	case _sv_levelpos:
1187 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1188 			level->pos = (int)ltemp;
1189 		break;
1190 	case _sv_xpos:
1191 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1192 			advancex = (float)ltemp;
1193 		break;
1194 	case _sv_ypos:
1195 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1196 			advancey = (float)ltemp;
1197 		break;
1198 	case _sv_scrollminz:
1199 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1200 			scrollminz = (float)ltemp;
1201 		break;
1202 	case _sv_scrollmaxz:
1203 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1204 			scrollmaxz = (float)ltemp;
1205 		break;
1206 	case _sv_blockade:
1207 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1208 			shadowalpha = (float)ltemp;
1209 		break;
1210 	case _sv_shadowcolor:
1211 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1212 			shadowcolor = (int)ltemp;
1213 		break;
1214 	case _sv_shadowalpha:
1215 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1216 			skiptoset = (int)ltemp;
1217 		break;
1218 	case _sv_skiptoset:
1219 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1220 			skiptoset = (int)ltemp;
1221 		break;
1222 	case _sv_slowmotion:
1223 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1224 			slowmotion[0] = (unsigned char)ltemp;
1225 		break;
1226 	case _sv_slowmotion_duration:
1227 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1228 			slowmotion[1] = (unsigned char)ltemp;
1229 		break;
1230 	case _sv_lasthitx:
1231 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1232 			lasthitx = (float)ltemp;
1233 		break;
1234 	case _sv_lasthita:
1235 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1236 			lasthita = (float)ltemp;
1237 		break;
1238 	 case _sv_lasthitc:
1239 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1240 			lasthitc = (int)ltemp;
1241 		break;
1242 	case _sv_lasthitz:
1243 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1244 			lasthitz = (float)ltemp;
1245 		break;
1246 	case _sv_lasthitt:
1247 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1248 			lasthitt = (int)ltemp;
1249 		break;
1250 	case _sv_smartbomber:
1251 		smartbomber = (entity*)value->ptrVal;
1252 		break;
1253 	case _sv_textbox:
1254 		textbox = (entity*)value->ptrVal;
1255 		break;
1256 	case _sv_nofadeout:
1257 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1258 			nofadeout = (int)ltemp;
1259 		break;
1260 	case _sv_nopause:
1261 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1262 			nopause = (int)ltemp;
1263 		break;
1264 	case _sv_nosave:
1265 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1266 			nosave = (int)ltemp;
1267 		break;
1268 	case _sv_noscreenshot:
1269 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1270 			noscreenshot = (int)ltemp;
1271 		break;
1272 	case _sv_usesave:
1273 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1274 			useSave = (int)ltemp;
1275 		break;
1276 	case _sv_viewportx:
1277 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1278 			viewportx = (int)ltemp;
1279 		break;
1280 	case _sv_viewporty:
1281 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1282 			viewporty = (int)ltemp;
1283 		break;
1284 	case _sv_viewportw:
1285 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1286 			viewportw = (int)ltemp;
1287 		break;
1288 	case _sv_viewporth:
1289 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1290 			viewporth = (int)ltemp;
1291 		break;
1292 	case _sv_waiting:
1293 		if(!level) break;
1294 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1295 			level->waiting = (int)ltemp;
1296 		break;
1297 	default:
1298 		return 0;
1299 	}
1300 
1301 	return 1;
1302 }
1303 
1304 
load_script(Script * script,char * file)1305 int load_script(Script* script, char* file)
1306 {
1307 	size_t size = 0;
1308 	int failed = 0;
1309 	char* buf = NULL;
1310 
1311 	if(buffer_pakfile(file, &buf, &size)!=1) return 0;
1312 
1313 	failed = !Script_AppendText(script, buf, file);
1314 
1315 	if(buf != NULL)
1316 	{
1317 		free(buf);
1318 		buf = NULL;
1319 	}
1320 
1321 	// text loaded but parsing failed, shutdown
1322 	if(failed) shutdown(1, "Failed to parse script file: '%s'!\n", file);
1323 	return !failed;
1324 }
1325 
1326 // this method is used by load_scripts, don't call it
init_scripts()1327 void init_scripts()
1328 {
1329 	int i;
1330 	Script_Global_Init();
1331 	Script_Init(&update_script,     "update",  NULL,  1);
1332 	Script_Init(&updated_script,    "updated",  NULL, 1);
1333 	Script_Init(&level_script,      "level",    NULL,  1);
1334 	Script_Init(&endlevel_script,   "endlevel",  NULL, 1);
1335 	Script_Init(&key_script_all,    "keyall",   NULL,  1);
1336 	Script_Init(&timetick_script,   "timetick",  NULL, 1);
1337 	Script_Init(&loading_script,    "loading",   NULL, 1);
1338 	for(i=0; i<4; i++) Script_Init(&score_script[i],    "score",    NULL,  1);
1339 	for(i=0; i<4; i++) Script_Init(&key_script[i],      "key",      NULL,  1);
1340 	for(i=0; i<4; i++) Script_Init(&join_script[i],     "join",      NULL, 1);
1341 	for(i=0; i<4; i++) Script_Init(&respawn_script[i],  "respawn",   NULL, 1);
1342 	for(i=0; i<4; i++) Script_Init(&pdie_script[i],     "die",       NULL, 1);
1343 }
1344 
1345 // This method is called once when the engine starts, do not use it multiple times
1346 // It should be calld after load_script_setting
load_scripts()1347 void load_scripts()
1348 {
1349 	int i;
1350 	init_scripts();
1351 	//Script_Clear's second parameter set to 2, because the script fails to load,
1352 	//and will never have another chance to be loaded, so just clear the variable list in it
1353 	if(!load_script(&update_script,     "data/scripts/update.c"))   Script_Clear(&update_script,        2);
1354 	if(!load_script(&updated_script,    "data/scripts/updated.c"))  Script_Clear(&updated_script,       2);
1355 	if(!load_script(&level_script,      "data/scripts/level.c"))    Script_Clear(&level_script,         2);
1356 	if(!load_script(&endlevel_script,   "data/scripts/endlevel.c")) Script_Clear(&endlevel_script,      2);
1357 	if(!load_script(&key_script_all,    "data/scripts/keyall.c"))   Script_Clear(&key_script_all,       2);
1358 	if(!load_script(&timetick_script,   "data/scripts/timetick.c")) Script_Clear(&timetick_script,      2);
1359 	if(!load_script(&loading_script,    "data/scripts/loading.c"))  Script_Clear(&loading_script,       2);
1360 	if(!load_script(&score_script[0],   "data/scripts/score1.c"))   Script_Clear(&score_script[0],      2);
1361 	if(!load_script(&score_script[1],   "data/scripts/score2.c"))   Script_Clear(&score_script[1],      2);
1362 	if(!load_script(&score_script[2],   "data/scripts/score3.c"))   Script_Clear(&score_script[2],      2);
1363 	if(!load_script(&score_script[3],   "data/scripts/score4.c"))   Script_Clear(&score_script[3],      2);
1364 	if(!load_script(&key_script[0],     "data/scripts/key1.c"))     Script_Clear(&key_script[0],        2);
1365 	if(!load_script(&key_script[1],     "data/scripts/key2.c"))     Script_Clear(&key_script[1],        2);
1366 	if(!load_script(&key_script[2],     "data/scripts/key3.c"))     Script_Clear(&key_script[2],        2);
1367 	if(!load_script(&key_script[3],     "data/scripts/key4.c"))     Script_Clear(&key_script[3],        2);
1368 	if(!load_script(&join_script[0],    "data/scripts/join1.c"))    Script_Clear(&join_script[0],       2);
1369 	if(!load_script(&join_script[1],    "data/scripts/join2.c"))    Script_Clear(&join_script[1],       2);
1370 	if(!load_script(&join_script[2],    "data/scripts/join3.c"))    Script_Clear(&join_script[2],       2);
1371 	if(!load_script(&join_script[3],    "data/scripts/join4.c"))    Script_Clear(&join_script[3],       2);
1372 	if(!load_script(&respawn_script[0], "data/scripts/respawn1.c")) Script_Clear(&respawn_script[0],    2);
1373 	if(!load_script(&respawn_script[1], "data/scripts/respawn2.c")) Script_Clear(&respawn_script[1],    2);
1374 	if(!load_script(&respawn_script[2], "data/scripts/respawn3.c")) Script_Clear(&respawn_script[2],    2);
1375 	if(!load_script(&respawn_script[3], "data/scripts/respawn4.c")) Script_Clear(&respawn_script[3],    2);
1376 	if(!load_script(&pdie_script[0],    "data/scripts/die1.c"))     Script_Clear(&pdie_script[0],       2);
1377 	if(!load_script(&pdie_script[1],    "data/scripts/die2.c"))     Script_Clear(&pdie_script[1],       2);
1378 	if(!load_script(&pdie_script[2],    "data/scripts/die3.c"))     Script_Clear(&pdie_script[2],       2);
1379 	if(!load_script(&pdie_script[3],    "data/scripts/die4.c"))     Script_Clear(&pdie_script[3],       2);
1380 	Script_Compile(&update_script);
1381 	Script_Compile(&updated_script);
1382 	Script_Compile(&level_script);
1383 	Script_Compile(&endlevel_script);
1384 	Script_Compile(&key_script_all);
1385 	Script_Compile(&timetick_script);
1386 	Script_Compile(&loading_script);
1387 	for(i=0; i<4; i++) Script_Compile(&score_script[i]);
1388 	for(i=0; i<4; i++) Script_Compile(&key_script[i]);
1389 	for(i=0; i<4; i++) Script_Compile(&join_script[i]);
1390 	for(i=0; i<4; i++) Script_Compile(&respawn_script[i]);
1391 	for(i=0; i<4; i++) Script_Compile(&pdie_script[i]);
1392 }
1393 
1394 // This method is called once when the engine is shutting down, do not use it multiple times
clear_scripts()1395 void clear_scripts()
1396 {
1397 	int i;
1398 	//Script_Clear's second parameter set to 2, because the script fails to load,
1399 	//and will never have another chance to be loaded, so just clear the variable list in it
1400 	Script_Clear(&update_script,    2);
1401 	Script_Clear(&updated_script,   2);
1402 	Script_Clear(&level_script,     2);
1403 	Script_Clear(&endlevel_script,  2);
1404 	Script_Clear(&key_script_all,   2);
1405 	Script_Clear(&timetick_script,  2);
1406 	for(i=0; i<4; i++)
1407 		Script_Clear(&score_script[i],      2);
1408 	for(i=0; i<4; i++)
1409 		Script_Clear(&key_script[i],        2);
1410 	for(i=0; i<4; i++)
1411 		Script_Clear(&join_script[i],       2);
1412 	for(i=0; i<4; i++)
1413 		Script_Clear(&respawn_script[i],    2);
1414 	for(i=0; i<4; i++)
1415 		Script_Clear(&pdie_script[i],       2);
1416 	Script_Global_Clear();
1417 }
1418 
1419 #define scripts_membercount (sizeof(s_scripts) / sizeof(Script*))
1420 
alloc_all_scripts(s_scripts ** s)1421 void alloc_all_scripts(s_scripts** s) {
1422 	size_t i;
1423 
1424 	if(!(*s))
1425 	{
1426 		*s = (s_scripts*)malloc(sizeof(s_scripts));
1427 		for (i = 0; i < scripts_membercount; i++) {
1428 			(((Script**) (*s))[i]) = alloc_script();
1429 		}
1430 	}
1431 }
1432 
clear_all_scripts(s_scripts * s,int method)1433 void clear_all_scripts(s_scripts* s, int method) {
1434 	size_t i;
1435 	Script** ps = (Script**) s;
1436 
1437 	for (i = 0; i < scripts_membercount; i++) {
1438 		Script_Clear(ps[i],   method);
1439 	}
1440 }
1441 
free_all_scripts(s_scripts ** s)1442 void free_all_scripts(s_scripts** s) {
1443 	size_t i;
1444 	Script** ps = (Script**) (*s);
1445 
1446 	for (i = 0; i < scripts_membercount; i++) {
1447 		if (ps[i]) {
1448 			free(ps[i]);
1449 			ps[i] = NULL;
1450 		}
1451 	}
1452 	free(*s);
1453 	*s = NULL;
1454 }
1455 
copy_all_scripts(s_scripts * src,s_scripts * dest,int method)1456 void copy_all_scripts(s_scripts* src, s_scripts* dest, int method) {
1457 	size_t i;
1458 	Script** ps = (Script**) src;
1459 	Script** pd = (Script**) dest;
1460 
1461 	for (i = 0; i < scripts_membercount; i++) {
1462 			Script_Copy(pd[i], ps[i], method);
1463 	}
1464 }
1465 
execute_animation_script(entity * ent)1466 void execute_animation_script(entity* ent)
1467 {
1468 	ScriptVariant tempvar;
1469 	Script* cs = ent->scripts->animation_script;
1470 	Script* s1 = ent->model->scripts->animation_script;
1471 	Script* s2 = ent->defaultmodel->scripts->animation_script;
1472 	if(Script_IsInitialized(s1) || Script_IsInitialized(s2))
1473 	{
1474 		ScriptVariant_Init(&tempvar);
1475 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1476 		tempvar.ptrVal = (VOID*)ent;
1477 		Script_Set_Local_Variant(cs, "self",    &tempvar);
1478 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1479 		tempvar.lVal = (LONG)ent->animnum;
1480 		Script_Set_Local_Variant(cs, "animnum", &tempvar);
1481 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1482 		tempvar.lVal = (LONG)ent->animpos;
1483 		Script_Set_Local_Variant(cs, "frame",   &tempvar);
1484 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1485 		tempvar.lVal = (LONG)ent->animation->index;
1486 		Script_Set_Local_Variant(cs, "animhandle",   &tempvar);
1487 		if(Script_IsInitialized(s1)){
1488 			Script_Copy(cs, s1, 0);
1489 			Script_Execute(cs);
1490 		}
1491 		if(ent->model!=ent->defaultmodel && Script_IsInitialized(s2)){
1492 			Script_Copy(cs, s2, 0);
1493 			Script_Execute(cs);
1494 		}
1495 		//clear to save variant space
1496 		ScriptVariant_Clear(&tempvar);
1497 		Script_Set_Local_Variant(cs, "self",    &tempvar);
1498 		Script_Set_Local_Variant(cs, "animnum", &tempvar);
1499 		Script_Set_Local_Variant(cs, "frame",   &tempvar);
1500 		Script_Set_Local_Variant(cs, "animhandle",   &tempvar);
1501 	}
1502 }
1503 
execute_takedamage_script(entity * ent,entity * other,int force,int drop,int type,int noblock,int guardcost,int jugglecost,int pauseadd)1504 void execute_takedamage_script(entity* ent, entity* other, int force, int drop, int type, int noblock, int guardcost, int jugglecost, int pauseadd)
1505 {
1506 	ScriptVariant tempvar;
1507 	Script* cs = ent->scripts->takedamage_script;
1508 	if(Script_IsInitialized(cs))
1509 	{
1510 		ScriptVariant_Init(&tempvar);
1511 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1512 		tempvar.ptrVal = (VOID*)ent;
1513 		Script_Set_Local_Variant(cs, "self",        &tempvar);
1514 		tempvar.ptrVal = (VOID*)other;
1515 		Script_Set_Local_Variant(cs, "attacker",    &tempvar);
1516 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1517 		tempvar.lVal = (LONG)force;
1518 		Script_Set_Local_Variant(cs, "damage",      &tempvar);
1519 		tempvar.lVal = (LONG)drop;
1520 		Script_Set_Local_Variant(cs, "drop",        &tempvar);
1521 		tempvar.lVal = (LONG)type;
1522 		Script_Set_Local_Variant(cs, "attacktype",  &tempvar);
1523 		tempvar.lVal = (LONG)noblock;
1524 		Script_Set_Local_Variant(cs, "noblock",     &tempvar);
1525 		tempvar.lVal = (LONG)guardcost;
1526 		Script_Set_Local_Variant(cs, "guardcost",   &tempvar);
1527 		tempvar.lVal = (LONG)jugglecost;
1528 		Script_Set_Local_Variant(cs, "jugglecost",  &tempvar);
1529 		tempvar.lVal = (LONG)pauseadd;
1530 		Script_Set_Local_Variant(cs, "pauseadd",    &tempvar);
1531 		Script_Execute(cs);
1532 		//clear to save variant space
1533 		ScriptVariant_Clear(&tempvar);
1534 		Script_Set_Local_Variant(cs, "self",        &tempvar);
1535 		Script_Set_Local_Variant(cs, "attacker",    &tempvar);
1536 		Script_Set_Local_Variant(cs, "damage",      &tempvar);
1537 		Script_Set_Local_Variant(cs, "drop",        &tempvar);
1538 		Script_Set_Local_Variant(cs, "attacktype",  &tempvar);
1539 		Script_Set_Local_Variant(cs, "noblock",     &tempvar);
1540 		Script_Set_Local_Variant(cs, "guardcost",   &tempvar);
1541 		Script_Set_Local_Variant(cs, "jugglecost",  &tempvar);
1542 		Script_Set_Local_Variant(cs, "pauseadd",    &tempvar);
1543 	}
1544 }
1545 
execute_onpain_script(entity * ent,int iType,int iReset)1546 void execute_onpain_script(entity* ent, int iType, int iReset)
1547 {
1548 	ScriptVariant tempvar;
1549 	Script* cs = ent->scripts->onpain_script;
1550 	if(Script_IsInitialized(cs))
1551 	{
1552 		ScriptVariant_Init(&tempvar);
1553 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1554 		tempvar.ptrVal = (VOID*)ent;
1555 		Script_Set_Local_Variant(cs, "self",        &tempvar);
1556 		tempvar.lVal = (LONG)iType;
1557 		Script_Set_Local_Variant(cs, "attacktype",   &tempvar);
1558 		tempvar.lVal = (LONG)iReset;
1559 		Script_Set_Local_Variant(cs, "reset",       &tempvar);
1560 		Script_Execute(cs);
1561 		//clear to save variant space
1562 		ScriptVariant_Clear(&tempvar);
1563 		Script_Set_Local_Variant(cs, "self",        &tempvar);
1564 		Script_Set_Local_Variant(cs, "type",        &tempvar);
1565 		Script_Set_Local_Variant(cs, "reset",       &tempvar);
1566 	}
1567 }
1568 
execute_onfall_script(entity * ent,entity * other,int force,int drop,int type,int noblock,int guardcost,int jugglecost,int pauseadd)1569 void execute_onfall_script(entity* ent, entity* other, int force, int drop, int type, int noblock, int guardcost, int jugglecost, int pauseadd)
1570 {
1571 	ScriptVariant tempvar;
1572 	Script* cs = ent->scripts->onfall_script;
1573 	if(Script_IsInitialized(cs))
1574 	{
1575 		ScriptVariant_Init(&tempvar);
1576 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1577 		tempvar.ptrVal = (VOID*)ent;
1578 		Script_Set_Local_Variant(cs, "self",        &tempvar);
1579 		tempvar.ptrVal = (VOID*)other;
1580 		Script_Set_Local_Variant(cs, "attacker",    &tempvar);
1581 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1582 		tempvar.lVal = (LONG)force;
1583 		Script_Set_Local_Variant(cs, "damage",      &tempvar);
1584 		tempvar.lVal = (LONG)drop;
1585 		Script_Set_Local_Variant(cs, "drop",        &tempvar);
1586 		tempvar.lVal = (LONG)type;
1587 		Script_Set_Local_Variant(cs, "attacktype",  &tempvar);
1588 		tempvar.lVal = (LONG)noblock;
1589 		Script_Set_Local_Variant(cs, "noblock",     &tempvar);
1590 		tempvar.lVal = (LONG)guardcost;
1591 		Script_Set_Local_Variant(cs, "guardcost",   &tempvar);
1592 		tempvar.lVal = (LONG)jugglecost;
1593 		Script_Set_Local_Variant(cs, "jugglecost",  &tempvar);
1594 		tempvar.lVal = (LONG)pauseadd;
1595 		Script_Set_Local_Variant(cs, "pauseadd",    &tempvar);
1596 		Script_Execute(cs);
1597 		//clear to save variant space
1598 		ScriptVariant_Clear(&tempvar);
1599 		Script_Set_Local_Variant(cs, "self",        &tempvar);
1600 		Script_Set_Local_Variant(cs, "attacker",    &tempvar);
1601 		Script_Set_Local_Variant(cs, "damage",      &tempvar);
1602 		Script_Set_Local_Variant(cs, "drop",        &tempvar);
1603 		Script_Set_Local_Variant(cs, "attacktype",  &tempvar);
1604 		Script_Set_Local_Variant(cs, "noblock",     &tempvar);
1605 		Script_Set_Local_Variant(cs, "guardcost",   &tempvar);
1606 		Script_Set_Local_Variant(cs, "jugglecost",  &tempvar);
1607 		Script_Set_Local_Variant(cs, "pauseadd",    &tempvar);
1608 	}
1609 }
1610 
execute_onblocks_script(entity * ent)1611 void execute_onblocks_script(entity* ent)
1612 {
1613 	ScriptVariant tempvar;
1614 	Script* cs = ent->scripts->onblocks_script;
1615 	if(Script_IsInitialized(cs))
1616 	{
1617 		ScriptVariant_Init(&tempvar);
1618 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1619 		tempvar.ptrVal = (VOID*)ent;
1620 		Script_Set_Local_Variant(cs, "self", &tempvar);
1621 		Script_Execute(cs);
1622 
1623 		//clear to save variant space
1624 		ScriptVariant_Clear(&tempvar);
1625 		Script_Set_Local_Variant(cs, "self", &tempvar);
1626 	}
1627 }
1628 
execute_onblockw_script(entity * ent,int plane,float height)1629 void execute_onblockw_script(entity* ent, int plane, float height)
1630 {
1631 	ScriptVariant tempvar;
1632 	Script* cs = ent->scripts->onblockw_script;
1633 	if(Script_IsInitialized(cs))
1634 	{
1635 		ScriptVariant_Init(&tempvar);
1636 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1637 		tempvar.ptrVal = (VOID*)ent;
1638 		Script_Set_Local_Variant(cs, "self", &tempvar);
1639 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1640 		tempvar.lVal = (LONG)plane;
1641 		Script_Set_Local_Variant(cs, "plane",      &tempvar);
1642 		ScriptVariant_ChangeType(&tempvar, VT_DECIMAL);
1643 		tempvar.dblVal = (DOUBLE)height;
1644 		Script_Set_Local_Variant(cs, "height",      &tempvar);
1645 		Script_Execute(cs);
1646 
1647 		//clear to save variant space
1648 		ScriptVariant_Clear(&tempvar);
1649 		Script_Set_Local_Variant(cs, "self", &tempvar);
1650 		ScriptVariant_Clear(&tempvar);
1651 		Script_Set_Local_Variant(cs, "plane", &tempvar);
1652 		ScriptVariant_Clear(&tempvar);
1653 		Script_Set_Local_Variant(cs, "height", &tempvar);
1654 	}
1655 }
1656 
execute_onblocko_script(entity * ent,entity * other)1657 void execute_onblocko_script(entity* ent, entity* other)
1658 {
1659 	ScriptVariant tempvar;
1660 	Script* cs = ent->scripts->onblocko_script;
1661 	if(Script_IsInitialized(cs))
1662 	{
1663 		ScriptVariant_Init(&tempvar);
1664 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1665 		tempvar.ptrVal = (VOID*)ent;
1666 		Script_Set_Local_Variant(cs, "self",        &tempvar);
1667 		tempvar.ptrVal = (VOID*)other;
1668 		Script_Set_Local_Variant(cs, "obstacle",    &tempvar);
1669 		Script_Execute(cs);
1670 
1671 		//clear to save variant space
1672 		ScriptVariant_Clear(&tempvar);
1673 		Script_Set_Local_Variant(cs, "self",        &tempvar);
1674 		Script_Set_Local_Variant(cs, "obstacle",    &tempvar);
1675 	}
1676 }
1677 
execute_onblockz_script(entity * ent)1678 void execute_onblockz_script(entity* ent)
1679 {
1680 	ScriptVariant tempvar;
1681 	Script* cs = ent->scripts->onblockz_script;
1682 	if(Script_IsInitialized(cs))
1683 	{
1684 		ScriptVariant_Init(&tempvar);
1685 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1686 		tempvar.ptrVal = (VOID*)ent;
1687 		Script_Set_Local_Variant(cs, "self", &tempvar);
1688 		Script_Execute(cs);
1689 
1690 		//clear to save variant space
1691 		ScriptVariant_Clear(&tempvar);
1692 		Script_Set_Local_Variant(cs, "self", &tempvar);
1693 	}
1694 }
1695 
execute_onblocka_script(entity * ent,entity * other)1696 void execute_onblocka_script(entity* ent, entity* other)
1697 {
1698 	ScriptVariant tempvar;
1699 	Script* cs = ent->scripts->onblocka_script;
1700 	if(Script_IsInitialized(cs))
1701 	{
1702 		ScriptVariant_Init(&tempvar);
1703 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1704 		tempvar.ptrVal = (VOID*)ent;
1705 		Script_Set_Local_Variant(cs, "self",        &tempvar);
1706 		tempvar.ptrVal = (VOID*)other;
1707 		Script_Set_Local_Variant(cs, "obstacle",    &tempvar);
1708 		Script_Execute(cs);
1709 		//clear to save variant space
1710 		ScriptVariant_Clear(&tempvar);
1711 		Script_Set_Local_Variant(cs, "self",        &tempvar);
1712 		Script_Set_Local_Variant(cs, "obstacle",    &tempvar);
1713 	}
1714 }
1715 
execute_onmovex_script(entity * ent)1716 void execute_onmovex_script(entity* ent)
1717 {
1718 	ScriptVariant tempvar;
1719 	Script* cs = ent->scripts->onmovex_script;
1720 	if(Script_IsInitialized(cs))
1721 	{
1722 		ScriptVariant_Init(&tempvar);
1723 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1724 		tempvar.ptrVal = (VOID*)ent;
1725 		Script_Set_Local_Variant(cs, "self", &tempvar);
1726 		Script_Execute(cs);
1727 
1728 		//clear to save variant space
1729 		ScriptVariant_Clear(&tempvar);
1730 		Script_Set_Local_Variant(cs, "self", &tempvar);
1731 	}
1732 }
1733 
execute_onmovez_script(entity * ent)1734 void execute_onmovez_script(entity* ent)
1735 {
1736 	ScriptVariant tempvar;
1737 	Script* cs = ent->scripts->onmovez_script;
1738 	if(Script_IsInitialized(cs))
1739 	{
1740 		ScriptVariant_Init(&tempvar);
1741 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1742 		tempvar.ptrVal = (VOID*)ent;
1743 		Script_Set_Local_Variant(cs, "self", &tempvar);
1744 		Script_Execute(cs);
1745 
1746 		//clear to save variant space
1747 		ScriptVariant_Clear(&tempvar);
1748 		Script_Set_Local_Variant(cs, "self", &tempvar);
1749 	}
1750 }
1751 
execute_onmovea_script(entity * ent)1752 void execute_onmovea_script(entity* ent)
1753 {
1754 	ScriptVariant tempvar;
1755 	Script* cs = ent->scripts->onmovea_script;
1756 	if(Script_IsInitialized(cs))
1757 	{
1758 		ScriptVariant_Init(&tempvar);
1759 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1760 		tempvar.ptrVal = (VOID*)ent;
1761 		Script_Set_Local_Variant(cs, "self", &tempvar);
1762 		Script_Execute(cs);
1763 
1764 		//clear to save variant space
1765 		ScriptVariant_Clear(&tempvar);
1766 		Script_Set_Local_Variant(cs, "self", &tempvar);
1767 	}
1768 }
1769 
execute_ondeath_script(entity * ent,entity * other,int force,int drop,int type,int noblock,int guardcost,int jugglecost,int pauseadd)1770 void execute_ondeath_script(entity* ent, entity* other, int force, int drop, int type, int noblock, int guardcost, int jugglecost, int pauseadd)
1771 {
1772 	ScriptVariant tempvar;
1773 	Script* cs = ent->scripts->ondeath_script;
1774 	if(Script_IsInitialized(cs))
1775 	{
1776 		ScriptVariant_Init(&tempvar);
1777 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1778 		tempvar.ptrVal = (VOID*)ent;
1779 		Script_Set_Local_Variant(cs, "self",        &tempvar);
1780 		tempvar.ptrVal = (VOID*)other;
1781 		Script_Set_Local_Variant(cs, "attacker",    &tempvar);
1782 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1783 		tempvar.lVal = (LONG)force;
1784 		Script_Set_Local_Variant(cs, "damage",      &tempvar);
1785 		tempvar.lVal = (LONG)drop;
1786 		Script_Set_Local_Variant(cs, "drop",        &tempvar);
1787 		tempvar.lVal = (LONG)type;
1788 		Script_Set_Local_Variant(cs, "attacktype",  &tempvar);
1789 		tempvar.lVal = (LONG)noblock;
1790 		Script_Set_Local_Variant(cs, "noblock",     &tempvar);
1791 		tempvar.lVal = (LONG)guardcost;
1792 		Script_Set_Local_Variant(cs, "guardcost",   &tempvar);
1793 		tempvar.lVal = (LONG)jugglecost;
1794 		Script_Set_Local_Variant(cs, "jugglecost",  &tempvar);
1795 		tempvar.lVal = (LONG)pauseadd;
1796 		Script_Set_Local_Variant(cs, "pauseadd",    &tempvar);
1797 		Script_Execute(cs);
1798 		//clear to save variant space
1799 		ScriptVariant_Clear(&tempvar);
1800 		Script_Set_Local_Variant(cs, "self",        &tempvar);
1801 		Script_Set_Local_Variant(cs, "attacker",    &tempvar);
1802 		Script_Set_Local_Variant(cs, "damage",      &tempvar);
1803 		Script_Set_Local_Variant(cs, "drop",        &tempvar);
1804 		Script_Set_Local_Variant(cs, "attacktype",  &tempvar);
1805 		Script_Set_Local_Variant(cs, "noblock",     &tempvar);
1806 		Script_Set_Local_Variant(cs, "guardcost",   &tempvar);
1807 		Script_Set_Local_Variant(cs, "jugglecost",  &tempvar);
1808 		Script_Set_Local_Variant(cs, "pauseadd",    &tempvar);
1809 	}
1810 }
1811 
execute_onkill_script(entity * ent)1812 void execute_onkill_script(entity* ent)
1813 {
1814 	ScriptVariant tempvar;
1815 	Script* cs = ent->scripts->onkill_script;
1816 	if(Script_IsInitialized(cs))
1817 	{
1818 		ScriptVariant_Init(&tempvar);
1819 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1820 		tempvar.ptrVal = (VOID*)ent;
1821 		Script_Set_Local_Variant(cs, "self", &tempvar);
1822 		Script_Execute(cs);
1823 		//clear to save variant space
1824 		ScriptVariant_Clear(&tempvar);
1825 		Script_Set_Local_Variant(cs, "self", &tempvar);
1826 	}
1827 }
1828 
execute_didblock_script(entity * ent,entity * other,int force,int drop,int type,int noblock,int guardcost,int jugglecost,int pauseadd)1829 void execute_didblock_script(entity* ent, entity* other, int force, int drop, int type, int noblock, int guardcost, int jugglecost, int pauseadd)
1830 {
1831 	ScriptVariant tempvar;
1832 	Script* cs = ent->scripts->didblock_script;
1833 	if(Script_IsInitialized(cs))
1834 	{
1835 		ScriptVariant_Init(&tempvar);
1836 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1837 		tempvar.ptrVal = (VOID*)ent;
1838 		Script_Set_Local_Variant(cs, "self",        &tempvar);
1839 		tempvar.ptrVal = (VOID*)other;
1840 		Script_Set_Local_Variant(cs, "attacker",    &tempvar);
1841 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1842 		tempvar.lVal = (LONG)force;
1843 		Script_Set_Local_Variant(cs, "damage",      &tempvar);
1844 		tempvar.lVal = (LONG)drop;
1845 		Script_Set_Local_Variant(cs, "drop",        &tempvar);
1846 		tempvar.lVal = (LONG)type;
1847 		Script_Set_Local_Variant(cs, "attacktype",  &tempvar);
1848 		tempvar.lVal = (LONG)noblock;
1849 		Script_Set_Local_Variant(cs, "noblock",     &tempvar);
1850 		tempvar.lVal = (LONG)guardcost;
1851 		Script_Set_Local_Variant(cs, "guardcost",   &tempvar);
1852 		tempvar.lVal = (LONG)jugglecost;
1853 		Script_Set_Local_Variant(cs, "jugglecost",  &tempvar);
1854 		tempvar.lVal = (LONG)pauseadd;
1855 		Script_Set_Local_Variant(cs, "pauseadd",    &tempvar);
1856 		Script_Execute(cs);
1857 		//clear to save variant space
1858 		ScriptVariant_Clear(&tempvar);
1859 		Script_Set_Local_Variant(cs, "self",        &tempvar);
1860 		Script_Set_Local_Variant(cs, "attacker",    &tempvar);
1861 		Script_Set_Local_Variant(cs, "damage",      &tempvar);
1862 		Script_Set_Local_Variant(cs, "drop",        &tempvar);
1863 		Script_Set_Local_Variant(cs, "attacktype",  &tempvar);
1864 		Script_Set_Local_Variant(cs, "noblock",     &tempvar);
1865 		Script_Set_Local_Variant(cs, "guardcost",   &tempvar);
1866 		Script_Set_Local_Variant(cs, "jugglecost",  &tempvar);
1867 		Script_Set_Local_Variant(cs, "pauseadd",    &tempvar);
1868 	}
1869 }
1870 
execute_ondoattack_script(entity * ent,entity * other,int force,int drop,int type,int noblock,int guardcost,int jugglecost,int pauseadd,int iWhich,int iAtkID)1871 void execute_ondoattack_script(entity* ent, entity* other, int force, int drop, int type, int noblock, int guardcost, int jugglecost, int pauseadd, int iWhich, int iAtkID)
1872 {
1873 	ScriptVariant tempvar;
1874 	Script* cs = ent->scripts->ondoattack_script;
1875 	if(Script_IsInitialized(cs))
1876 	{
1877 		ScriptVariant_Init(&tempvar);
1878 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1879 		tempvar.ptrVal = (VOID*)ent;
1880 		Script_Set_Local_Variant(cs, "self",        &tempvar);
1881 		tempvar.ptrVal = (VOID*)other;
1882 		Script_Set_Local_Variant(cs, "other",    &tempvar);
1883 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1884 		tempvar.lVal = (LONG)force;
1885 		Script_Set_Local_Variant(cs, "damage",      &tempvar);
1886 		tempvar.lVal = (LONG)drop;
1887 		Script_Set_Local_Variant(cs, "drop",        &tempvar);
1888 		tempvar.lVal = (LONG)type;
1889 		Script_Set_Local_Variant(cs, "attacktype",  &tempvar);
1890 		tempvar.lVal = (LONG)noblock;
1891 		Script_Set_Local_Variant(cs, "noblock",     &tempvar);
1892 		tempvar.lVal = (LONG)guardcost;
1893 		Script_Set_Local_Variant(cs, "guardcost",   &tempvar);
1894 		tempvar.lVal = (LONG)jugglecost;
1895 		Script_Set_Local_Variant(cs, "jugglecost",  &tempvar);
1896 		tempvar.lVal = (LONG)pauseadd;
1897 		Script_Set_Local_Variant(cs, "pauseadd",    &tempvar);
1898 		tempvar.lVal = (LONG)iWhich;
1899 		Script_Set_Local_Variant(cs, "which",    &tempvar);
1900 		tempvar.lVal = (LONG)iAtkID;
1901 		Script_Set_Local_Variant(cs, "attackid",    &tempvar);
1902 		Script_Execute(cs);
1903 		//clear to save variant space
1904 		ScriptVariant_Clear(&tempvar);
1905 		Script_Set_Local_Variant(cs, "self",        &tempvar);
1906 		Script_Set_Local_Variant(cs, "other",		&tempvar);
1907 		Script_Set_Local_Variant(cs, "damage",      &tempvar);
1908 		Script_Set_Local_Variant(cs, "drop",        &tempvar);
1909 		Script_Set_Local_Variant(cs, "attacktype",  &tempvar);
1910 		Script_Set_Local_Variant(cs, "noblock",     &tempvar);
1911 		Script_Set_Local_Variant(cs, "guardcost",   &tempvar);
1912 		Script_Set_Local_Variant(cs, "jugglecost",  &tempvar);
1913 		Script_Set_Local_Variant(cs, "pauseadd",    &tempvar);
1914 		Script_Set_Local_Variant(cs, "which",		&tempvar);
1915 		Script_Set_Local_Variant(cs, "attackid",	&tempvar);
1916 	}
1917 }
1918 
execute_updateentity_script(entity * ent)1919 void execute_updateentity_script(entity* ent)
1920 {
1921 	ScriptVariant tempvar;
1922 	Script* cs = ent->scripts->update_script;
1923 	if(Script_IsInitialized(cs))
1924 	{
1925 		ScriptVariant_Init(&tempvar);
1926 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1927 		tempvar.ptrVal = (VOID*)ent;
1928 		Script_Set_Local_Variant(cs, "self", &tempvar);
1929 		Script_Execute(cs);
1930 		//clear to save variant space
1931 		ScriptVariant_Clear(&tempvar);
1932 		Script_Set_Local_Variant(cs, "self", &tempvar);
1933 	}
1934 }
1935 
execute_think_script(entity * ent)1936 void execute_think_script(entity* ent)
1937 {
1938 	ScriptVariant tempvar;
1939 	Script* cs = ent->scripts->think_script;
1940 	if(Script_IsInitialized(cs))
1941 	{
1942 		ScriptVariant_Init(&tempvar);
1943 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1944 		tempvar.ptrVal = (VOID*)ent;
1945 		Script_Set_Local_Variant(cs, "self", &tempvar);
1946 		Script_Execute(cs);
1947 		//clear to save variant space
1948 		ScriptVariant_Clear(&tempvar);
1949 		Script_Set_Local_Variant(cs, "self", &tempvar);
1950 	}
1951 }
1952 
execute_didhit_script(entity * ent,entity * other,int force,int drop,int type,int noblock,int guardcost,int jugglecost,int pauseadd,int blocked)1953 void execute_didhit_script(entity* ent, entity* other, int force, int drop, int type, int noblock, int guardcost, int jugglecost, int pauseadd, int blocked)
1954 {
1955 	ScriptVariant tempvar;
1956 	Script* cs = ent->scripts->didhit_script;
1957 	if(Script_IsInitialized(cs))
1958 	{
1959 		ScriptVariant_Init(&tempvar);
1960 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1961 		tempvar.ptrVal = (VOID*)ent;
1962 		Script_Set_Local_Variant(cs, "self",        &tempvar);
1963 		tempvar.ptrVal = (VOID*)other;
1964 		Script_Set_Local_Variant(cs, "damagetaker", &tempvar);
1965 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1966 		tempvar.lVal = (LONG)force;
1967 		Script_Set_Local_Variant(cs, "damage",      &tempvar);
1968 		tempvar.lVal = (LONG)drop;
1969 		Script_Set_Local_Variant(cs, "drop",        &tempvar);
1970 		tempvar.lVal = (LONG)type;
1971 		Script_Set_Local_Variant(cs, "attacktype",  &tempvar);
1972 		tempvar.lVal = (LONG)noblock;
1973 		Script_Set_Local_Variant(cs, "noblock",     &tempvar);
1974 		tempvar.lVal = (LONG)guardcost;
1975 		Script_Set_Local_Variant(cs, "guardcost",   &tempvar);
1976 		tempvar.lVal = (LONG)jugglecost;
1977 		Script_Set_Local_Variant(cs, "jugglecost",  &tempvar);
1978 		tempvar.lVal = (LONG)pauseadd;
1979 		Script_Set_Local_Variant(cs, "pauseadd",    &tempvar);
1980 		tempvar.lVal = (LONG)blocked;
1981 		Script_Set_Local_Variant(cs, "blocked",     &tempvar);
1982 		Script_Execute(cs);
1983 		//clear to save variant space
1984 		ScriptVariant_Clear(&tempvar);
1985 		Script_Set_Local_Variant(cs, "self",        &tempvar);
1986 		Script_Set_Local_Variant(cs, "damagetaker", &tempvar);
1987 		Script_Set_Local_Variant(cs, "damage",      &tempvar);
1988 		Script_Set_Local_Variant(cs, "drop",        &tempvar);
1989 		Script_Set_Local_Variant(cs, "attacktype",  &tempvar);
1990 		Script_Set_Local_Variant(cs, "noblock",     &tempvar);
1991 		Script_Set_Local_Variant(cs, "guardcost",   &tempvar);
1992 		Script_Set_Local_Variant(cs, "jugglecost",  &tempvar);
1993 		Script_Set_Local_Variant(cs, "pauseadd",    &tempvar);
1994 		Script_Set_Local_Variant(cs, "blocked",     &tempvar);
1995 	}
1996 }
1997 
execute_onspawn_script(entity * ent)1998 void execute_onspawn_script(entity* ent)
1999 {
2000 	ScriptVariant tempvar;
2001 	Script* cs = ent->scripts->onspawn_script;
2002 	if(Script_IsInitialized(cs))
2003 	{
2004 		ScriptVariant_Init(&tempvar);
2005 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
2006 		tempvar.ptrVal = (VOID*)ent;
2007 		Script_Set_Local_Variant(cs, "self", &tempvar);
2008 		Script_Execute(cs);
2009 		//clear to save variant space
2010 		ScriptVariant_Clear(&tempvar);
2011 		Script_Set_Local_Variant(cs, "self", &tempvar);
2012 	}
2013 }
2014 
execute_entity_key_script(entity * ent)2015 void execute_entity_key_script(entity* ent)
2016 {
2017 	ScriptVariant tempvar;
2018 	Script* cs ;
2019 	if(!ent) return;
2020 	cs = ent->scripts->key_script;
2021 	if(Script_IsInitialized(cs))
2022 	{
2023 		ScriptVariant_Init(&tempvar);
2024 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
2025 		tempvar.ptrVal = (VOID*)ent;
2026 		Script_Set_Local_Variant(cs, "self",    &tempvar);
2027 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
2028 		tempvar.lVal = (LONG)ent->playerindex;
2029 		Script_Set_Local_Variant(cs, "player",  &tempvar);
2030 		Script_Execute(cs);
2031 		//clear to save variant space
2032 		ScriptVariant_Clear(&tempvar);
2033 		Script_Set_Local_Variant(cs, "self",    &tempvar);
2034 		Script_Set_Local_Variant(cs, "player",  &tempvar);
2035 	}
2036 }
2037 
execute_spawn_script(s_spawn_entry * p,entity * e)2038 void execute_spawn_script(s_spawn_entry* p, entity* e)
2039 {
2040 	s_spawn_script_list_node* tempnode = p->spawn_script_list_head;
2041 	ScriptVariant tempvar;
2042 	Script* cs;
2043 	while(tempnode)
2044 	{
2045 		cs = tempnode->spawn_script;
2046 		if(e)
2047 		{
2048 			ScriptVariant_Init(&tempvar);
2049 			ScriptVariant_ChangeType(&tempvar, VT_PTR);
2050 			tempvar.ptrVal = (VOID*)e;
2051 			Script_Set_Local_Variant(cs, "self", &tempvar);
2052 		}
2053 		Script_Execute(cs);
2054 		if(e)
2055 		{
2056 			ScriptVariant_Clear(&tempvar);
2057 			Script_Set_Local_Variant(cs, "self", &tempvar);
2058 		}
2059 		tempnode = tempnode->next;
2060 	}
2061 }
2062 
execute_level_key_script(int player)2063 void execute_level_key_script(int player)
2064 {
2065 	ScriptVariant tempvar;
2066 	Script* cs = &(level->key_script);
2067 	if(Script_IsInitialized(cs))
2068 	{
2069 		ScriptVariant_Init(&tempvar);
2070 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
2071 		tempvar.lVal = (LONG)player;
2072 		Script_Set_Local_Variant(cs, "player", &tempvar);
2073 		Script_Execute(cs);
2074 		//clear to save variant space
2075 		ScriptVariant_Clear(&tempvar);
2076 		Script_Set_Local_Variant(cs, "player", &tempvar);
2077 	}
2078 }
2079 
execute_key_script_all(int player)2080 void execute_key_script_all(int player)
2081 {
2082 	ScriptVariant tempvar;
2083 	Script* cs = &key_script_all;
2084 	if(Script_IsInitialized(cs))
2085 	{
2086 		ScriptVariant_Init(&tempvar);
2087 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
2088 		tempvar.lVal = (LONG)player;
2089 		Script_Set_Local_Variant(cs, "player", &tempvar);
2090 		Script_Execute(cs);
2091 		//clear to save variant space
2092 		ScriptVariant_Clear(&tempvar);
2093 		Script_Set_Local_Variant(cs, "player", &tempvar);
2094 	}
2095 }
2096 
execute_timetick_script(int time,int gotime)2097 void execute_timetick_script(int time, int gotime)
2098 {
2099 	ScriptVariant tempvar;
2100 	Script* cs = &timetick_script;
2101 	if(Script_IsInitialized(cs))
2102 	{
2103 		ScriptVariant_Init(&tempvar);
2104 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
2105 		tempvar.lVal = (LONG)time;
2106 		Script_Set_Local_Variant(cs, "time",    &tempvar);
2107 		tempvar.lVal = (LONG)gotime;
2108 		Script_Set_Local_Variant(cs, "gotime", &tempvar);
2109 		Script_Execute(cs);
2110 		//clear to save variant space
2111 		ScriptVariant_Clear(&tempvar);
2112 		Script_Set_Local_Variant(cs, "time",    &tempvar);
2113 		Script_Set_Local_Variant(cs, "gotime",  &tempvar);
2114 	}
2115 }
2116 
execute_loading_script(int value,int max)2117 void execute_loading_script(int value, int max)
2118 {
2119 	ScriptVariant tempvar;
2120 	Script* cs = &loading_script;
2121 	if(Script_IsInitialized(cs))
2122 	{
2123 		ScriptVariant_Init(&tempvar);
2124 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
2125 		tempvar.lVal = (LONG)value;
2126 		Script_Set_Local_Variant(cs, "value",    &tempvar);
2127 		tempvar.lVal = (LONG)max;
2128 		Script_Set_Local_Variant(cs, "max", &tempvar);
2129 		Script_Execute(cs);
2130 		//clear to save variant space
2131 		ScriptVariant_Clear(&tempvar);
2132 		Script_Set_Local_Variant(cs, "value",    &tempvar);
2133 		Script_Set_Local_Variant(cs, "max",  &tempvar);
2134 	}
2135 }
2136 
execute_key_script(int index)2137 void execute_key_script(int index)
2138 {
2139 	if(Script_IsInitialized(&key_script[index]))
2140 	{
2141 		Script_Execute(&key_script[index]);
2142 	}
2143 }
2144 
execute_join_script(int index)2145 void execute_join_script(int index)
2146 {
2147 	if(Script_IsInitialized(&join_script[index]))
2148 	{
2149 		Script_Execute(&join_script[index]);
2150 	}
2151 }
2152 
execute_respawn_script(int index)2153 void execute_respawn_script(int index)
2154 {
2155 	if(Script_IsInitialized(&respawn_script[index]))
2156 	{
2157 		Script_Execute(&respawn_script[index]);
2158 	}
2159 }
2160 
execute_pdie_script(int index)2161 void execute_pdie_script(int index)
2162 {
2163 	if(Script_IsInitialized(&pdie_script[index]))
2164 	{
2165 		Script_Execute(&pdie_script[index]);
2166 	}
2167 }
2168 
2169 // ------------------------ Save/load -----------------------------
2170 
clearsettings()2171 void clearsettings()
2172 {
2173 	savedata.compatibleversion = COMPATIBLEVERSION;
2174 	savedata.gamma = 0;
2175 	savedata.brightness = 0;
2176 	savedata.usesound = 1;
2177 	savedata.soundrate = 44100;
2178 	savedata.soundbits = 16;
2179 	savedata.soundvol = 15;
2180 	savedata.usemusic = 1;
2181 	savedata.musicvol = 100;
2182 	savedata.effectvol = 120;
2183 	savedata.usejoy = 1;
2184 	savedata.mode = 0;
2185 	savedata.showtitles = 0;
2186 	savedata.windowpos = 0;
2187 	savedata.logo = 0;
2188 	savedata.uselog = 1;
2189 	savedata.debuginfo = 0;
2190 	savedata.fullscreen = 0;
2191 	savedata.stretch = 0;
2192 
2193 #ifdef SDL
2194 	savedata.usegl[0] = 0;
2195 	savedata.usegl[1] = 1;
2196 	savedata.glscale = 1.0;
2197 	savedata.glfilter[0] = 1;
2198 	savedata.glfilter[1] = 0;
2199 #endif
2200 
2201 	savedata.screen[0][0] = 0; savedata.screen[0][1] = 0;
2202 	savedata.screen[1][0] = 0; savedata.screen[1][1] = 0;
2203 	savedata.screen[2][0] = 0; savedata.screen[2][1] = 0;
2204 	savedata.screen[3][0] = 0; savedata.screen[3][1] = 0;
2205 	savedata.screen[4][0] = 0; savedata.screen[4][1] = 0;
2206 	savedata.screen[5][0] = 0; savedata.screen[5][1] = 0;
2207 	savedata.screen[6][0] = 0; savedata.screen[6][1] = 0;
2208 
2209 #ifdef PSP
2210 	savedata.screen[1][0] = 3;
2211 	savedata.pspcpuspeed = 2;
2212 	savedata.overscan[0] = 0;
2213 	savedata.overscan[1] = 0;
2214 	savedata.overscan[2] = 0;
2215 	savedata.overscan[3] = 0;
2216 #endif
2217 
2218 	savedata.keys[0][SDID_MOVEUP]    = CONTROL_DEFAULT1_UP;
2219 	savedata.keys[0][SDID_MOVEDOWN]  = CONTROL_DEFAULT1_DOWN;
2220 	savedata.keys[0][SDID_MOVELEFT]  = CONTROL_DEFAULT1_LEFT;
2221 	savedata.keys[0][SDID_MOVERIGHT] = CONTROL_DEFAULT1_RIGHT;
2222 	savedata.keys[0][SDID_ATTACK]    = CONTROL_DEFAULT1_FIRE1;
2223 	savedata.keys[0][SDID_ATTACK2]   = CONTROL_DEFAULT1_FIRE2;
2224 	savedata.keys[0][SDID_ATTACK3]   = CONTROL_DEFAULT1_FIRE3;
2225 	savedata.keys[0][SDID_ATTACK4]   = CONTROL_DEFAULT1_FIRE4;
2226 	savedata.keys[0][SDID_JUMP]      = CONTROL_DEFAULT1_FIRE5;
2227 	savedata.keys[0][SDID_SPECIAL]   = CONTROL_DEFAULT1_FIRE6;
2228 	savedata.keys[0][SDID_START]     = CONTROL_DEFAULT1_START;
2229 	savedata.keys[0][SDID_SCREENSHOT]= CONTROL_DEFAULT1_SCREENSHOT;
2230 
2231 	savedata.keys[1][SDID_MOVEUP]    = CONTROL_DEFAULT2_UP;
2232 	savedata.keys[1][SDID_MOVEDOWN]  = CONTROL_DEFAULT2_DOWN;
2233 	savedata.keys[1][SDID_MOVELEFT]  = CONTROL_DEFAULT2_LEFT;
2234 	savedata.keys[1][SDID_MOVERIGHT] = CONTROL_DEFAULT2_RIGHT;
2235 	savedata.keys[1][SDID_ATTACK]    = CONTROL_DEFAULT2_FIRE1;
2236 	savedata.keys[1][SDID_ATTACK2]   = CONTROL_DEFAULT2_FIRE2;
2237 	savedata.keys[1][SDID_ATTACK3]   = CONTROL_DEFAULT2_FIRE3;
2238 	savedata.keys[1][SDID_ATTACK4]   = CONTROL_DEFAULT2_FIRE4;
2239 	savedata.keys[1][SDID_JUMP]      = CONTROL_DEFAULT2_FIRE5;
2240 	savedata.keys[1][SDID_SPECIAL]   = CONTROL_DEFAULT2_FIRE6;
2241 	savedata.keys[1][SDID_START]     = CONTROL_DEFAULT2_START;
2242 	savedata.keys[1][SDID_SCREENSHOT]= CONTROL_DEFAULT2_SCREENSHOT;
2243 
2244 	savedata.keys[2][SDID_MOVEUP]    = CONTROL_DEFAULT3_UP;
2245 	savedata.keys[2][SDID_MOVEDOWN]  = CONTROL_DEFAULT3_DOWN;
2246 	savedata.keys[2][SDID_MOVELEFT]  = CONTROL_DEFAULT3_LEFT;
2247 	savedata.keys[2][SDID_MOVERIGHT] = CONTROL_DEFAULT3_RIGHT;
2248 	savedata.keys[2][SDID_ATTACK]    = CONTROL_DEFAULT3_FIRE1;
2249 	savedata.keys[2][SDID_ATTACK2]   = CONTROL_DEFAULT3_FIRE2;
2250 	savedata.keys[2][SDID_ATTACK3]   = CONTROL_DEFAULT3_FIRE3;
2251 	savedata.keys[2][SDID_ATTACK4]   = CONTROL_DEFAULT3_FIRE4;
2252 	savedata.keys[2][SDID_JUMP]      = CONTROL_DEFAULT3_FIRE5;
2253 	savedata.keys[2][SDID_SPECIAL]   = CONTROL_DEFAULT3_FIRE6;
2254 	savedata.keys[2][SDID_START]     = CONTROL_DEFAULT3_START;
2255 	savedata.keys[2][SDID_SCREENSHOT]= CONTROL_DEFAULT3_SCREENSHOT;
2256 
2257 	savedata.keys[3][SDID_MOVEUP]    = CONTROL_DEFAULT4_UP;
2258 	savedata.keys[3][SDID_MOVEDOWN]  = CONTROL_DEFAULT4_DOWN;
2259 	savedata.keys[3][SDID_MOVELEFT]  = CONTROL_DEFAULT4_LEFT;
2260 	savedata.keys[3][SDID_MOVERIGHT] = CONTROL_DEFAULT4_RIGHT;
2261 	savedata.keys[3][SDID_ATTACK]    = CONTROL_DEFAULT4_FIRE1;
2262 	savedata.keys[3][SDID_ATTACK2]   = CONTROL_DEFAULT4_FIRE2;
2263 	savedata.keys[3][SDID_ATTACK3]   = CONTROL_DEFAULT4_FIRE3;
2264 	savedata.keys[3][SDID_ATTACK4]   = CONTROL_DEFAULT4_FIRE4;
2265 	savedata.keys[3][SDID_JUMP]      = CONTROL_DEFAULT4_FIRE5;
2266 	savedata.keys[3][SDID_SPECIAL]   = CONTROL_DEFAULT4_FIRE6;
2267 	savedata.keys[3][SDID_START]     = CONTROL_DEFAULT4_START;
2268 	savedata.keys[3][SDID_SCREENSHOT]= CONTROL_DEFAULT4_SCREENSHOT;
2269 }
2270 
2271 
savesettings()2272 void savesettings(){
2273 #ifndef DC
2274 	FILE *handle = NULL;
2275 	char path[128] = {""};
2276 	char tmpname[128] = {""};
2277 	getBasePath(path, "Saves", 0);
2278 	getPakName(tmpname, 4);
2279 	strcat(path, tmpname);
2280 	handle = fopen(path, "wb");
2281 	if(handle==NULL) return;
2282     fwrite(&savedata, 1, sizeof(s_savedata), handle);
2283 	fclose(handle);
2284 #endif
2285 }
2286 
saveasdefault()2287 void saveasdefault(){
2288 #ifndef DC
2289 	FILE *handle = NULL;
2290 	char path[128] = {""};
2291 	getBasePath(path, "Saves", 0);
2292 	strncat(path, "default.cfg", 128);
2293 	handle = fopen(path, "wb");
2294 	if(handle==NULL) return;
2295     fwrite(&savedata, 1, sizeof(s_savedata), handle);
2296 	fclose(handle);
2297 #endif
2298 }
2299 
2300 
loadsettings()2301 void loadsettings(){
2302 #ifndef DC
2303 	FILE *handle = NULL;
2304 	char path[128] = {""};
2305 	char tmpname[128] = {""};
2306 	getBasePath(path, "Saves", 0);
2307 	getPakName(tmpname, 4);
2308 	strcat(path, tmpname);
2309 	if(!(fileExists(path)))
2310 	{
2311 		loadfromdefault();
2312 		return;
2313 	}
2314 	clearsettings();
2315 	handle = fopen(path, "rb");
2316 	if(handle == NULL) return;
2317     fread(&savedata, 1, sizeof(s_savedata), handle);
2318 	fclose(handle);
2319 	if(savedata.compatibleversion != COMPATIBLEVERSION) clearsettings();
2320 #else
2321 	clearsettings();
2322 #endif
2323 }
2324 
loadfromdefault()2325 void loadfromdefault(){
2326 #ifndef DC
2327 	FILE *handle = NULL;
2328 	char path[128] = {""};
2329 	getBasePath(path, "Saves", 0);
2330 	strncat(path, "default.cfg", 128);
2331 	clearsettings();
2332 	handle = fopen(path, "rb");
2333 	if(handle == NULL) return;
2334     fread(&savedata, 1, sizeof(s_savedata), handle);
2335 	fclose(handle);
2336 	if(savedata.compatibleversion != COMPATIBLEVERSION) clearsettings();
2337 #else
2338 	clearsettings();
2339 #endif
2340 }
2341 
2342 
2343 
2344 
clearSavedGame()2345 void clearSavedGame(){
2346 	memset(savelevel, 0, sizeof(s_savelevel)*num_difficulties);
2347 }
2348 
2349 
2350 
clearHighScore()2351 void clearHighScore(){
2352 	int i;
2353 	savescore.compatibleversion = CV_HIGH_SCORE;
2354 	for(i=0; i<10; i++) {
2355 		savescore.highsc[i] = 0;    // Resets all the highscores to 0
2356 		strcpy(savescore.hscoren[i], "None");    // Resets all the highscore names to "None"
2357 	}
2358 }
2359 
2360 
2361 
saveGameFile()2362 int saveGameFile(){
2363 #ifndef DC
2364 	FILE *handle = NULL;
2365 	char path[256] = {""};
2366 	char tmpname[256] = {""};
2367 	getBasePath(path, "Saves", 0);
2368 	getPakName(tmpname, 0);
2369 	strcat(path, tmpname);
2370 	//if(!savelevel[saveslot].level) return;
2371 	handle = fopen(path, "wb");
2372 	if(handle == NULL) return 0;
2373     fwrite(savelevel, sizeof(s_savelevel), num_difficulties, handle);
2374 	fclose(handle);
2375 	return 1;
2376 #else
2377 	return 1;
2378 #endif
2379 }
2380 
2381 
loadGameFile()2382 int loadGameFile(){
2383 #ifndef DC
2384 	int result = 1;
2385 	FILE *handle = NULL;
2386 	char path[256] = {""};
2387 	char tmpname[256] = {""};
2388 	getBasePath(path, "Saves", 0);
2389 	getPakName(tmpname, 0);
2390 	strcat(path,tmpname);
2391 	handle = fopen(path, "rb");
2392 	if(handle == NULL) return 0;
2393     if(fread(savelevel, sizeof(s_savelevel), num_difficulties, handle)>=sizeof(s_savelevel) && savelevel[0].compatibleversion!=CV_SAVED_GAME){ //TODO: check file length
2394 		clearSavedGame();
2395 		result = 0;
2396 	}
2397 	fclose(handle);
2398 	return result;
2399 #else
2400 	clearSavedGame();
2401 	return 0;
2402 #endif
2403 }
2404 
2405 
saveHighScoreFile()2406 int saveHighScoreFile(){
2407 #ifndef DC
2408 	FILE *handle = NULL;
2409 	char path[256] = {""};
2410 	char tmpname[256] = {""};
2411 	getBasePath(path, "Saves", 0);
2412 	getPakName(tmpname, 1);
2413 	strcat(path, tmpname);
2414 	handle = fopen(path, "wb");
2415 	if(handle == NULL) return 0;
2416     fwrite(&savescore, 1, sizeof(s_savescore), handle);
2417 	fclose(handle);
2418 	return 1;
2419 #else
2420 	return 1;
2421 #endif
2422 }
2423 
2424 
loadHighScoreFile()2425 int loadHighScoreFile(){
2426 #ifndef DC
2427 	FILE *handle = NULL;
2428 	char path[256] = {""};
2429 	char tmpname[256] = {""};
2430 	getBasePath(path, "Saves", 0);
2431 	getPakName(tmpname, 1);
2432 	strcat(path,tmpname);
2433 	clearHighScore();
2434 	handle = fopen(path, "rb");
2435 	if(handle == NULL) return 0;
2436     fread(&savescore, 1, sizeof(s_savescore), handle);
2437 	fclose(handle);
2438 	if(savescore.compatibleversion != CV_HIGH_SCORE) {
2439 		clearHighScore();
2440 		return 0;
2441 	}
2442 	return 1;
2443 #else
2444 	clearHighScore();
2445 	return 0;
2446 #endif
2447 }
2448 
2449 
2450 #ifndef DC
vardump(ScriptVariant * var,char buffer[])2451 static void vardump(ScriptVariant *var, char buffer[])
2452 {
2453 	char* tmpstr;
2454 	int l, t, c;
2455 	buffer[0] = 0;
2456 	switch(var->vt)
2457 	{
2458 
2459 	case VT_STR:
2460 		strcpy(buffer, "\"");
2461 		tmpstr = StrCache_Get(var->strVal);
2462 		l = strlen(tmpstr);
2463 		for(c=0; c<l; c++){
2464 			if(tmpstr[c]=='\n'){
2465 				strcat(buffer, "\\n");
2466 			}else if(tmpstr[c]=='\r'){
2467 				strcat(buffer, "\\r");
2468 			}else if(tmpstr[c]=='\\'){
2469 				strcat(buffer, "\\\\");
2470 			}else{
2471 				t = strlen(buffer);
2472 				buffer[t] = tmpstr[c];
2473 				buffer[t+1] = 0;
2474 			}
2475 		}
2476 		strcat(buffer, "\"");
2477 		break;
2478 	case VT_DECIMAL:
2479 		sprintf(buffer, "%lf", (double)var->dblVal);
2480 		break;
2481 	case VT_INTEGER:
2482 		sprintf(buffer, "%ld", (long)var->lVal);
2483 		break;
2484 	default:
2485 		strcpy(buffer, "NULL()");
2486 		break;
2487 	}
2488 }
2489 
2490 #endif
2491 
2492 
saveScriptFile()2493 int saveScriptFile()
2494 {
2495 #ifndef DC
2496 	#define _writestr(v) fwrite(v, strlen(v), 1, handle);
2497 	#define _writetmp  _writestr(tmpvalue)
2498 	#define _writeconst(s) strcpy(tmpvalue,s);_writetmp
2499 	FILE *handle = NULL;
2500 	int i, l;
2501 	char path[256] = {""};
2502 	char tmpvalue[256] = {""};
2503 	//named list
2504 	//if(max_global_vars<=0) return ;
2505 	getBasePath(path, "Saves", 0);
2506 	getPakName(tmpvalue, 2);//.scr
2507 	strcat(path, tmpvalue);
2508 	l = strlen(path); //s00, s01, s02 etc
2509 	path[l-2] = '0'+(current_set/10);
2510 	path[l-1] = '0'+(current_set%10);
2511 	handle = fopen(path, "wb");
2512 	if(handle == NULL) return 0;
2513 
2514 	_writeconst("void main() {\n");
2515 	for(i=0; i<=max_global_var_index; i++)
2516 	{
2517 		if(!global_var_list[i]->owner &&
2518 			global_var_list[i]->key[0] &&
2519 			global_var_list[i]->value.vt!=VT_EMPTY &&
2520 			global_var_list[i]->value.vt!=VT_PTR){
2521 			_writeconst("\tsetglobalvar(\"")
2522 			_writestr(global_var_list[i]->key)
2523 			_writeconst("\",")
2524 			vardump(&(global_var_list[i]->value), tmpvalue);
2525 			_writetmp
2526 			_writeconst(");\n")
2527 		}
2528 	}
2529 	// indexed list
2530 	for(i=0; i<max_indexed_vars; i++) {
2531 		if(indexed_var_list[i].vt != VT_PTR && indexed_var_list[i].vt!=VT_EMPTY){
2532 			_writeconst("\tsetindexedvar(")
2533 			sprintf(tmpvalue, "%d", i);
2534 			_writetmp
2535 			_writeconst(",")
2536 			vardump(indexed_var_list+i, tmpvalue);
2537 			_writetmp
2538 			_writeconst(");\n")
2539 		}
2540 
2541 	}
2542 	_writeconst("}\n");
2543 
2544 	fclose(handle);
2545 	return 1;
2546 	#undef _writestr
2547 	#undef _writetmp
2548 	#undef _writeconst
2549 #else
2550 	return 1;
2551 #endif
2552 }
2553 
2554 
loadScriptFile()2555 int loadScriptFile(){
2556 #ifndef DC
2557 	Script script;
2558 	int result = 0;
2559 	char* buf = NULL;
2560 	ptrdiff_t l;
2561 	size_t len;
2562 	FILE *handle = NULL;
2563 
2564 	char path[256] = {""};
2565 	char tmpname[256] = {""};
2566 	//named list
2567 	//if(max_global_vars<=0) return ;
2568 	getBasePath(path, "Saves", 0);
2569 	getPakName(tmpname, 2);//.scr
2570 	strcat(path,tmpname);
2571 	l = strlen(path); //s00, s01, s02 etc
2572 	path[l-2] = '0'+(current_set/10);
2573 	path[l-1] = '0'+(current_set%10);
2574 
2575 	handle = fopen(path, "rb");
2576 	if(handle == NULL) return 0;
2577 
2578 	fseek(handle, 0, SEEK_END);
2579 	len = ftell(handle);
2580 	fseek(handle, 0, SEEK_SET);
2581 	buf = malloc(len+1);
2582 
2583 	if(!buf) return 0;
2584 
2585 	fread(buf, 1, len, handle);
2586 	buf[len-1] = 0;
2587 
2588 	Script_Init(&script, "loadScriptFile",  NULL, 1);
2589 
2590 	result = (Script_AppendText(&script, buf, path) &&
2591 		Script_Compile(&script) &&
2592 		Script_Execute(&script) );
2593 
2594 	Script_Clear(&script, 2);
2595 	free(buf);
2596 	return result;
2597 #else
2598 	return 0;
2599 #endif
2600 }
2601 
2602 // ----------------------- Sound ------------------------------
2603 
music(char * filename,int loop,long offset)2604 int music(char *filename, int loop, long offset)
2605 {
2606 	char t[64];
2607 	char a[64];
2608 	int res = 1;
2609 	if(!savedata.usemusic) return 0;
2610 	if(!sound_open_music(filename, packfile, savedata.musicvol, loop, offset)) {
2611 		printf("\nCan't play music file '%s'\n", filename);
2612 		res = 0;
2613 	}
2614 	if(savedata.showtitles && sound_query_music(a,t))
2615 	{
2616 		if(a[0] && t[0]) debug_printf("Playing \"%s\" by %s", t, a);
2617 		else if(a[0]) debug_printf("Playing unknown song by %s", a);
2618 		else if(t[0]) debug_printf("Playing \"%s\" by unknown artist", t);
2619 		else debug_printf("");
2620 	}
2621 	strncpy(currentmusic, filename, sizeof(currentmusic)-1);
2622 	return res;
2623 }
2624 
check_music()2625 void check_music(){
2626 	if(musicfade[1] > 0)
2627 	{
2628 		musicfade[1] -= musicfade[0];
2629 		sound_volume_music((int)musicfade[1], (int)musicfade[1]);
2630 	}
2631 	else if(musicname[0])
2632 	{
2633 		music(musicname, musicloop, musicoffset);
2634 		sound_volume_music(savedata.musicvol, savedata.musicvol);
2635 		musicname[0] = 0;
2636 	}
2637 }
2638 
2639 // ----------------------- General ------------------------------
2640 // atof and atoi return a valid number, if only the first char is one.
2641 // so we only check that.
isNumeric(char * text)2642 int isNumeric(char* text) {
2643 	char* p = text;
2644 	assert(p);
2645 	if(!*p) return 0;
2646 	switch(*p) {
2647 		case '-': case '+':
2648 			p++;
2649 			break;
2650 		default:
2651 			break;
2652 	}
2653 	switch (*p) {
2654 		case '0': case '1': case '2': case '3': case '4':
2655 		case '5': case '6': case '7': case '8': case '9':
2656 			return 1;
2657 		default:
2658 			return 0;
2659 	}
2660 	return 1;
2661 }
2662 
2663 
getValidInt(char * text,char * file,char * cmd)2664 int getValidInt(char* text, char* file, char* cmd)  {
2665 	static const char* WARN_NUMBER_EXPECTED = "WARNING: %s tries to load a nonnumeric value at %s, where a number is expected!\nerroneus string: %s\n";
2666 	if(!text || !*text) return 0;
2667 	if(isNumeric(text)) {
2668 		return atoi(text);
2669 	} else {
2670 		printf(WARN_NUMBER_EXPECTED, file, cmd, text);
2671 		return 0;
2672 	}
2673 
2674 }
2675 
getValidFloat(char * text,char * file,char * cmd)2676 float getValidFloat(char* text, char* file, char* cmd)  {
2677 	static const char* WARN_NUMBER_EXPECTED = "WARNING: %s tries to load a nonnumeric value at %s, where a number is expected!\nerroneus string: %s\n";
2678 	if(!text || !*text) return 0.0f;
2679 	if(isNumeric(text)) {
2680 		if(text[strlen(text)-1]=='%')
2681 			return atof(text)/100.0f;
2682 		return atof(text);
2683 	} else {
2684 		printf(WARN_NUMBER_EXPECTED, file, cmd, text);
2685 		return 0.0f;
2686 	}
2687 }
2688 
ParseArgs(ArgList * list,char * input,char * output)2689 size_t ParseArgs(ArgList* list, char* input, char* output) {
2690 	assert(list);
2691 	assert(input);
2692 	assert(output);
2693 	//static const char diff = 'a' - 'A';
2694 
2695 	size_t pos = 0;
2696 	size_t wordstart = 0;
2697 	size_t item = 0;
2698 	int done = 0;
2699 	int space = 0;
2700 	//int makelower = 0;
2701 
2702 	while(pos < MAX_ARG_LEN-1 && item < MAX_ARG_COUNT) {
2703 		switch(input[pos]) {
2704 			case '\r': case '\n': case '#': case '\0':
2705 				done = 1;
2706 			case ' ': case '\t':
2707 				output[pos] = '\0';
2708 				if(!space && wordstart != pos) {
2709 					list->args[item] = output + wordstart;
2710 					list->arglen[item] = pos - wordstart;
2711 					item++;
2712 				}
2713 				space = 1;
2714 				break; /*
2715 			case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I':
2716 			case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
2717 			case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
2718 				makelower = 1; */
2719 
2720 			default:
2721 				if(space)
2722 					wordstart = pos;
2723 				/*output[pos] = makelower ? input[pos] + diff : input[pos];*/
2724 				output[pos] = input[pos];
2725 				space = 0;
2726 				//makelower = 0;
2727 		}
2728 		if(done)
2729 			break;
2730 		pos++;
2731 	}
2732 	list->count = item;
2733 	return item;
2734 }
2735 
findarg(char * command,int which)2736 char *findarg(char *command, int which){
2737 	static const char* comment_mark = "#";
2738 	int d;
2739 	int argc;
2740 	int inarg;
2741 	int argstart;
2742 	static char arg[MAX_ARG_LEN];
2743 
2744 
2745 	// Copy the command line, replacing spaces by zeroes,
2746 	// finally returning a pointer to the requested arg.
2747 	d = 0;
2748 	inarg = 0;
2749 	argstart = 0;
2750 	argc = -1;
2751 
2752 	while(d<MAX_ARG_LEN-1 && command[d]){
2753 		// Zero out whitespace
2754 		if(command[d]==' ' || command[d]=='\t'){
2755 			arg[d] = 0;
2756 			inarg = 0;
2757 			if(argc == which) return arg + argstart;
2758 		}
2759 		else if(command[d]==0 || command[d]=='\n' || command[d]=='\r' ||
2760 			strncmp(command+d, comment_mark, strlen(comment_mark))==0){
2761 				// End of line
2762 				arg[d] = 0;
2763 				if(argc == which) return arg + argstart;
2764 				return arg + d;
2765 			}
2766 		else{
2767 			if(!inarg){
2768 				// if(argc==-1 && command[d]=='#') return arg;
2769 				inarg = 1;
2770 				argstart = d;
2771 				argc++;
2772 			}
2773 			arg[d] = command[d];
2774 		}
2775 		++d;
2776 	}
2777 
2778 	return arg;
2779 }
2780 
2781 
2782 
2783 
diff(float a,float b)2784 float diff(float a, float b){
2785 	if(a<b) return b-a;
2786 	return a-b;
2787 }
2788 
2789 
2790 
inair(entity * e)2791 int inair(entity *e)
2792 {
2793 	return (diff(e->a, e->base) >= 0.1);
2794 }
2795 
2796 
2797 
randf(float max)2798 float randf(float max){
2799 	float f;
2800 	if(max==0) return 0;
2801 	f = (float)(rand32()%10000);
2802 	f /= (10000/max);
2803 	return f;
2804 }
2805 
2806 
2807 
2808 // ----------------------- Loaders ------------------------------
2809 
2810 
2811 // Creates a remapping table from two images
load_colourmap(s_model * model,char * image1,char * image2)2812 int load_colourmap(s_model * model, char *image1, char *image2)
2813 {
2814 	int i, j, k;
2815 	unsigned char *map = NULL;
2816 	s_bitmap *bitmap1 = NULL;
2817 	s_bitmap *bitmap2 = NULL;
2818 
2819 	// Can't use same image twice!
2820 	if(stricmp(image1,image2)==0) return 0;
2821 
2822 	// Find an empty slot... ;)
2823 	for(k=0; k<MAX_COLOUR_MAPS && model->colourmap[k]; k++);
2824 	if(k>=MAX_COLOUR_MAPS) return -1;
2825 
2826 	if((map = malloc(MAX_PAL_SIZE/4)) == NULL)
2827 	{
2828 		return -2;
2829 	}
2830 	if((bitmap1 = loadbitmap(image1, packfile, PIXEL_8)) == NULL)
2831 	{
2832 		free(map);
2833 		map = NULL;
2834 		return -3;
2835 	}
2836 	if((bitmap2 = loadbitmap(image2, packfile, PIXEL_8)) == NULL)
2837 	{
2838 		freebitmap(bitmap1);
2839 		free(map);
2840 		map = NULL;
2841 		return -4;
2842 	}
2843 
2844 	// Create the colour map
2845 	for(i=0;i<MAX_PAL_SIZE/4;i++) map[i] = i;
2846 	for(j=0; j<bitmap1->height && j<bitmap2->height; j++)
2847 	{
2848 		for(i=0; i<bitmap1->width && i<bitmap2->width; i++)
2849 		{
2850 			map[(unsigned)(bitmap1->data[j*bitmap1->width+i])] = bitmap2->data[j*bitmap2->width+i];
2851 		}
2852 	}
2853 
2854 	freebitmap(bitmap1);
2855 	freebitmap(bitmap2);
2856 
2857 	model->colourmap[k] = map;
2858 	model->maps_loaded = k + 1;
2859 	return 1;
2860 }
2861 
2862 //PIXEL_x8
2863 // This function is used to enable remap command in 24bit mode
2864 // So old mods can still run under 16/24/32bit color system
2865 // This function should be called when all colourmaps are loaded, e.g.,
2866 // at the end of load_cached_model
2867 // map flag is used to determine whether a colourmap is a real colourmap
convert_map_to_palette(s_model * model,unsigned char mapflag[])2868 int convert_map_to_palette(s_model* model, unsigned char mapflag[])
2869 {
2870 	int i, c;
2871 	unsigned char *newmap, *oldmap;
2872 	unsigned char *p1, *p2;
2873 	unsigned pb = pixelbytes[(int)screenformat];
2874 	if(model->palette==NULL) return 0;
2875 	for(c=0; c<model->maps_loaded; c++)
2876 	{
2877 		if(mapflag[c]==0) continue;
2878 		if((newmap = malloc(PAL_BYTES)) == NULL)
2879 		{
2880 			shutdown(1, "Error convert_map_to_palette for model: %s\n", model->name);
2881 		}
2882 		// Create new colour map
2883 		memcpy(newmap, model->palette, PAL_BYTES);
2884 		oldmap = model->colourmap[c];
2885 		for(i=0; i<MAX_PAL_SIZE/4; i++)
2886 		{
2887 			if(oldmap[i]==i) continue;
2888 			p1 = newmap + i*pb;
2889 			p2 = model->palette + oldmap[i]*pb;
2890 			memcpy(p1, p2, pb);
2891 		}
2892 		model->colourmap[c] = newmap;
2893 		free(oldmap); oldmap = NULL;
2894 	}
2895 	return 1;
2896 }
2897 
_load_palette16(unsigned char * palette,char * filename)2898 static int _load_palette16(unsigned char* palette, char* filename)
2899 {
2900 	int handle, i;
2901 	unsigned char tp[3];
2902 	handle = openpackfile(filename, packfile);
2903 	if(handle <0) return 0;
2904 	memset(palette, 0, MAX_PAL_SIZE/2);
2905 	for(i=0; i<MAX_PAL_SIZE/4; i++)
2906 	{
2907 		if(readpackfile(handle, tp, 3) != 3)
2908 		{
2909 			closepackfile(handle);
2910 			return 0;
2911 		}
2912 		((unsigned short*)palette)[i] = colour16(tp[0], tp[1], tp[2]);
2913 	}
2914 	closepackfile(handle);
2915 	*(unsigned short*)palette = 0;
2916 
2917 	return 1;
2918 }
2919 
2920 
_load_palette32(unsigned char * palette,char * filename)2921 static int _load_palette32(unsigned char* palette, char* filename)
2922 {
2923 	int handle, i;
2924 	unsigned* dp;
2925 	unsigned char tpal[3];
2926 	handle = openpackfile(filename, packfile);
2927 	if(handle <0) return 0;
2928 	memset(palette, 0, MAX_PAL_SIZE);
2929 	dp = (unsigned*)palette;
2930 	for(i=0; i<MAX_PAL_SIZE/4; i++)
2931 	{
2932 		if(readpackfile(handle, tpal, 3) != 3)
2933 		{
2934 			closepackfile(handle);
2935 			return 0;
2936 		}
2937 		dp[i] = colour32(tpal[0],tpal[1],tpal[2]);
2938 
2939 	}
2940 	closepackfile(handle);
2941 	dp[0] = 0;
2942 
2943 	return 1;
2944 }
2945 
2946 //load a 256 colors' palette
load_palette(unsigned char * palette,char * filename)2947 int load_palette(unsigned char* palette, char* filename)
2948 {
2949 	int handle;
2950 	if(screenformat==PIXEL_32)
2951 		return _load_palette32(palette, filename);
2952 	else if(screenformat==PIXEL_16)
2953 		return _load_palette16(palette, filename);
2954 
2955 	handle = openpackfile(filename, packfile);
2956 	if(handle <0) return 0;
2957 	if(readpackfile(handle, palette, 768) != 768){
2958 		closepackfile(handle);
2959 		return 0;
2960 	}
2961 	closepackfile(handle);
2962 	palette[0] = palette[1] = palette[2] = 0;
2963 
2964 	return 1;
2965 }
2966 
2967 // create blending tables for the palette
create_blending_tables(unsigned char * palette,unsigned char * tables[],int usemap[])2968 int create_blending_tables(unsigned char* palette, unsigned char* tables[], int usemap[])
2969 {
2970 	int i;
2971 	if(pixelformat!=PIXEL_8) return 1;
2972 	if(!palette || !tables) return 0;
2973 
2974 	memset(tables, 0, MAX_BLENDINGS*sizeof(unsigned char*));
2975 	for(i=0; i<MAX_BLENDINGS; i++)
2976 	{
2977 		if(!usemap || usemap[i])
2978 		{
2979 			tables[i] = (blending_table_functions[i])(palette);
2980 			if(!tables[i]) return 0;
2981 		}
2982 	}
2983 
2984 	return 1;
2985 }
2986 
create_blend_tables_x8(unsigned char * tables[])2987 void create_blend_tables_x8(unsigned char* tables[]){
2988 	int i;
2989 	for(i=0; i<MAX_BLENDINGS; i++){
2990 		switch(screenformat){
2991 		case PIXEL_16:
2992 			tables[i] = (blending_table_functions16[i])();
2993 			break;
2994 		case PIXEL_32:
2995 			tables[i] = (blending_table_functions32[i])();
2996 			break;
2997 		}
2998 	}
2999 
3000 }
3001 
3002 
3003 //change system palette by index
change_system_palette(int palindex)3004 void change_system_palette(int palindex)
3005 {
3006 	if(palindex < 0) palindex = 0;
3007 	//if(current_palette == palindex ) return;
3008 
3009 
3010 	if(!level || palindex == 0 || palindex > level->numpalettes)
3011 	{
3012 		current_palette = 0;
3013 		if(screenformat==PIXEL_8)
3014 		{
3015 			palette_set_corrected(pal, savedata.gamma,savedata.gamma,savedata.gamma, savedata.brightness,savedata.brightness,savedata.brightness);
3016 			set_blendtables(blendings); // set global blending tables
3017 		}
3018 	}
3019 	else if(level)
3020 	{
3021 		current_palette = palindex;
3022 		if(screenformat==PIXEL_8)
3023 		{
3024 			palette_set_corrected(level->palettes[palindex-1], savedata.gamma,savedata.gamma,savedata.gamma, savedata.brightness,savedata.brightness,savedata.brightness);
3025 			set_blendtables(level->blendings[palindex-1]);
3026 		}
3027 	}
3028 }
3029 
3030 // Load colour 0-127 from data/pal.act
standard_palette(int immediate)3031 void standard_palette(int immediate){
3032 	unsigned char* pp[MAX_PAL_SIZE] = {0};
3033 	if(load_palette((unsigned char*)pp, "data/pal.act"))
3034 	{
3035 		memcpy(pal, pp, (PAL_BYTES)/2);
3036 	}
3037 	if(immediate)
3038 	{
3039 	   change_system_palette(0);
3040 	}
3041 }
3042 
3043 
unload_background()3044 void unload_background(){
3045 	int i;
3046 	if (background)	clearscreen(background);
3047 	for(i=0; i<MAX_BLENDINGS; i++)
3048 	{
3049 		if(blendings[i]) free(blendings[i]);
3050 		blendings[i] = NULL;
3051 	}
3052 }
3053 
3054 
_makecolour(int r,int g,int b)3055 int _makecolour(int r, int g, int b)
3056 {
3057 	switch(screenformat)
3058 	{
3059 	case PIXEL_8:
3060 		return palette_find(pal, r, g, b);
3061 	case PIXEL_16:
3062 		 return colour16(r,g,b);
3063 	case PIXEL_32:
3064 		return colour32(r,g,b);
3065 	}
3066 	return 0;
3067 }
3068 
3069 // parses a color string in the format "R_G_B" or as a raw integer
parsecolor(const char * string)3070 int parsecolor(const char* string)
3071 {
3072 	int r, g, b;
3073 	if(strchr(string, '_') != strrchr(string, '_'))
3074 	{ // 2 underscores; color is in "R_G_B" format
3075 		r = atoi(string);
3076 		g = atoi(strchr(string, '_')+1);
3077 		b = atoi(strrchr(string, '_')+1);
3078 		return _makecolour(r,g,b);
3079 	} else return atoi(string); // raw integer
3080 }
3081 
3082 // ltb 1-17-05   new function for lifebar colors
lifebar_colors()3083 void lifebar_colors()
3084 {
3085 	char * filename = "data/lifebar.txt";
3086 	char *buf;
3087 	size_t size;
3088 	int pos;
3089 	ArgList arglist;
3090 	char argbuf[MAX_ARG_LEN+1] = "";
3091 
3092 
3093 	char * command;
3094 
3095 	if(buffer_pakfile(filename, &buf, &size)!=1)
3096 	{
3097 		color_black = 0;
3098 		color_red = 0;
3099 		color_orange = 0;
3100 		color_yellow = 0;
3101 		color_white = 0;
3102 		color_blue = 0;
3103 		color_green = 0;
3104 		color_pink = 0;
3105 		color_purple = 0;
3106 		color_magic = 0;
3107 		color_magic2 = 0;
3108 		shadowcolor = 0;
3109 		shadowalpha = BLEND_MULTIPLY+1;
3110 		return;
3111 	}
3112 
3113 	pos = 0;
3114 	colorbars=1;
3115 	while(pos<size){
3116 	    if(ParseArgs(&arglist,buf+pos,argbuf)){
3117 			command = GET_ARG(0);
3118 			if(command && command[0])
3119 			{
3120 				if(stricmp(command, "blackbox")==0)
3121 					color_black = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
3122 				else if(stricmp(command, "whitebox")==0)
3123 					color_white = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
3124 				else if(stricmp(command, "color300")==0)
3125 					color_orange = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
3126 				else if(stricmp(command, "color25")==0)
3127 					color_red = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
3128 				else if(stricmp(command, "color50")==0)
3129 					color_yellow = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
3130 				else if(stricmp(command, "color100")==0)
3131 					color_green = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
3132 				else if(stricmp(command, "color200")==0)
3133 					color_blue = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
3134 				else if(stricmp(command, "color400")==0)
3135 					color_pink = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
3136 				else if(stricmp(command, "color500")==0)
3137 					color_purple = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
3138 				//magic bars color declarations by tails
3139 				else if(stricmp(command, "colormagic")==0)
3140 					color_magic = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
3141 				else if(stricmp(command, "colormagic2")==0)
3142 					color_magic2 = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
3143 				//end of magic bars color declarations by tails
3144 				else if(stricmp(command, "shadowcolor")==0)
3145 					shadowcolor = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
3146 				else if(stricmp(command, "shadowalpha")==0) //gfxshadow alpha
3147 					shadowalpha = GET_INT_ARG(1);
3148 				else
3149 					if(command && command[0])
3150 						printf("Warning: Unknown command in lifebar.txt: '%s'.\n", command);
3151 			}
3152 		}
3153 
3154 		// Go to next line
3155 	pos += getNewLineStart(buf + pos);
3156 	}
3157 	if(buf != NULL){
3158 		free(buf);
3159 		buf = NULL;
3160 	}
3161 }
3162 // ltb 1-17-05 end new lifebar colors
3163 
3164 
init_colourtable()3165 void init_colourtable()
3166 {
3167 	mpcolourtable[0]  = color_magic2;
3168 	mpcolourtable[1]  = color_magic;
3169 	mpcolourtable[2]  = color_magic;
3170 	mpcolourtable[3]  = color_magic;
3171 	mpcolourtable[4]  = color_magic2;
3172 	mpcolourtable[5]  = color_magic;
3173 	mpcolourtable[6]  = color_magic2;
3174 	mpcolourtable[7]  = color_magic;
3175 	mpcolourtable[8]  = color_magic2;
3176 	mpcolourtable[9]  = color_magic;
3177 	mpcolourtable[10] = color_magic2;
3178 
3179 	hpcolourtable[0]  = color_purple;
3180 	hpcolourtable[1]  = color_red;
3181 	hpcolourtable[2]  = color_yellow;
3182 	hpcolourtable[3]  = color_green;
3183 	hpcolourtable[4]  = color_blue;
3184 	hpcolourtable[5]  = color_orange;
3185 	hpcolourtable[6]  = color_pink;
3186 	hpcolourtable[7]  = color_purple;
3187 	hpcolourtable[8]  = color_black;
3188 	hpcolourtable[9]  = color_white;
3189 	hpcolourtable[10] = color_white;
3190 
3191 	memcpy(ldcolourtable, hpcolourtable, 11*sizeof(int));
3192 }
3193 
load_background(char * filename,int createtables)3194 void load_background(char *filename, int createtables)
3195 {
3196 	//if(pixelformat!=PIXEL_8) createtables = 0;
3197 	unload_background();
3198 
3199 	if(pixelformat==PIXEL_8)
3200 	{
3201 		if(!loadscreen(filename, packfile, pal, PIXEL_8, &background))
3202 		{
3203 			shutdown(1, "Error loading background (PIXEL_8) file '%s'", filename);
3204 		}
3205 	}
3206 	else if(pixelformat==PIXEL_x8)
3207 	{
3208 		if(!loadscreen(filename, packfile, NULL, PIXEL_x8, &background))
3209 		{
3210 			shutdown(1, "Error loading background (PIXEL_x8) file '%s'", filename);
3211 		}
3212 		memcpy(pal, background->palette, PAL_BYTES);
3213 		memcpy(neontable, pal, PAL_BYTES);
3214 	}
3215 	else
3216 	{
3217 		shutdown(1, "Error loading background, Unknown Pixel Format!\n");
3218 	}
3219 
3220 	if(createtables)
3221 	{
3222 		standard_palette(0);
3223 		if(!create_blending_tables(pal, blendings, blendfx))
3224 			shutdown(1, "Failed to create colour conversion tables! (Out of memory?)");
3225 	}
3226 
3227 	lifebar_colors();
3228 	if(!color_black)  color_black = _makecolour(0,0,0);           // black boxes 500-600HP
3229 	if(!color_red)    color_red = _makecolour(255,0,0);           // 1% - 25% Full Health
3230 	if(!color_orange) color_orange = _makecolour(255,150,0);      // 200-300HP
3231 	if(!color_yellow) color_yellow = _makecolour(0xF8,0xB8,0x40); // 26%-50% Full health
3232 	if(!color_white)  color_white = _makecolour(255,255,255);     // white boxes 600+ HP
3233 	if(!color_blue)   color_blue = _makecolour(0,0,255);          // 100-200 HP
3234 	if(!color_green)  color_green = _makecolour(0,255,0);         // 51% - 100% full health
3235 	if(!color_pink)   color_pink = _makecolour(255,0,255);        // 300-400HP
3236 	if(!color_purple) color_purple = _makecolour(128,48,208);     // transbox 400-500HP
3237 	if(!color_magic)  color_magic = _makecolour(98,180,255);      // 1st magic bar color by tails
3238 	if(!color_magic2) color_magic2 = _makecolour(24,48,143);      // 2sec magic bar color by tails
3239 	if(!shadowcolor)  shadowcolor =  _makecolour(64,64,64);
3240 	init_colourtable();
3241 
3242 	video_clearscreen();
3243 	pal[0] = pal[1] = pal[2] = 0;
3244 	//palette_set_corrected(pal, savedata.gamma,savedata.gamma,savedata.gamma, savedata.brightness,savedata.brightness,savedata.brightness);
3245 	change_system_palette(0);
3246 }
3247 
load_cached_background(char * filename,int createtables)3248 void load_cached_background(char *filename, int createtables)
3249 {
3250 #if !WII
3251 	load_background(filename, createtables);
3252 #else
3253 	int index = -1;
3254 	unload_background();
3255 
3256 	if(strcmp(filename, "data/bgs/logo")==0)
3257 		index = 0;
3258 	else if(strcmp(filename, "data/bgs/title")==0)
3259 		index = 1;
3260 	else if(strcmp(filename, "data/bgs/titleb")==0)
3261 		index = 2;
3262 	else if(strcmp(filename, "data/bgs/loading")==0)
3263 		index = 3;
3264 	else if(strcmp(filename, "data/bgs/loading2")==0)
3265 		index = 4;
3266 	else if(strcmp(filename, "data/bgs/hiscore")==0)
3267 		index = 5;
3268 	else if(strcmp(filename, "data/bgs/complete")==0)
3269 		index = 6;
3270 	else if(strcmp(filename, "data/bgs/unlockbg")==0)
3271 		index = 7;
3272 	else if(strcmp(filename, "data/bgs/select")==0)
3273 		index = 8;
3274 
3275 	if((index==-1) || (bg_cache[index]==NULL))
3276 		shutdown(1, "Error: can't load cached background '%s'", filename);
3277 
3278 	if(background) freescreen(&background);
3279 	background = allocscreen(videomodes.hRes, videomodes.vRes, pixelformat);
3280 	copyscreen(background, bg_cache[index]);
3281 
3282 	if(pixelformat==PIXEL_8)
3283 		memcpy(pal, bg_palette_cache[index], PAL_BYTES);
3284 	else if(pixelformat==PIXEL_x8)
3285 	{
3286 		memcpy(background->palette, bg_cache[index]->palette, PAL_BYTES);
3287 		memcpy(pal, background->palette, PAL_BYTES);
3288 	}
3289 
3290 
3291 	if(createtables)
3292 	{
3293 		standard_palette(0);
3294 		if(!create_blending_tables(pal, blendings, blendfx))
3295 			shutdown(1, "Failed to create colour conversion tables! (Out of memory?)");
3296 	}
3297 
3298 	video_clearscreen();
3299 	pal[0] = pal[1] = pal[2] = 0;
3300 	//palette_set_corrected(pal, savedata.gamma,savedata.gamma,savedata.gamma, savedata.brightness,savedata.brightness,savedata.brightness);
3301 	change_system_palette(0);
3302 #endif
3303 }
3304 
3305 #if WII
cache_background(char * filename)3306 void cache_background(char *filename)
3307 {
3308 	s_screen *bg = allocscreen(videomodes.hRes, videomodes.vRes, pixelformat);
3309 	int index = -1;
3310 
3311 	if(pixelformat==PIXEL_8)
3312 	{
3313 		if(!loadscreen(filename, packfile, pal, pixelformat, &bg))
3314 		{
3315 			freescreen(&bg);
3316 			bg = NULL;
3317 		}
3318 	}
3319 	else if(pixelformat==PIXEL_x8)
3320 	{
3321 		if(!loadscreen(filename, packfile, NULL, pixelformat, &bg))
3322 		{
3323 			freescreen(&bg);
3324 			bg = NULL;
3325 		}
3326 	}
3327 	else
3328 	{
3329 		shutdown(1, "Error caching background, Unknown Pixel Format!\n");
3330 	}
3331 
3332 	if(strcmp(filename, "data/bgs/logo")==0)
3333 		index = 0;
3334 	else if(strcmp(filename, "data/bgs/title")==0)
3335 		index = 1;
3336 	else if(strcmp(filename, "data/bgs/titleb")==0)
3337 		index = 2;
3338 	else if(strcmp(filename, "data/bgs/loading")==0)
3339 		index = 3;
3340 	else if(strcmp(filename, "data/bgs/loading2")==0)
3341 		index = 4;
3342 	else if(strcmp(filename, "data/bgs/hiscore")==0)
3343 		index = 5;
3344 	else if(strcmp(filename, "data/bgs/complete")==0)
3345 		index = 6;
3346 	else if(strcmp(filename, "data/bgs/unlockbg")==0)
3347 		index = 7;
3348 	else if(strcmp(filename, "data/bgs/select")==0)
3349 		index = 8;
3350 	else shutdown(1, "Error: unknown cached background '%s'", filename);
3351 
3352 	bg_cache[index] = bg;
3353 
3354 	if(pixelformat==PIXEL_8)
3355 		memcpy(bg_palette_cache[index], pal, PAL_BYTES);
3356 
3357 	change_system_palette(0);
3358 }
3359 
cache_all_backgrounds()3360 void cache_all_backgrounds()
3361 {
3362 	cache_background("data/bgs/logo");
3363 	cache_background("data/bgs/title");
3364 	cache_background("data/bgs/titleb");
3365 	cache_background("data/bgs/loading2");
3366 	cache_background("data/bgs/hiscore");
3367 	cache_background("data/bgs/complete");
3368 	cache_background("data/bgs/unlockbg");
3369 	cache_background("data/bgs/select");
3370 }
3371 #endif
3372 
load_layer(char * filename,int index)3373 void load_layer(char *filename, int index)
3374 {
3375 	if(!level) return;
3376 
3377 	if(filename && level->layers[index].gfx.handle ==NULL){
3378 
3379 		if ((level->layers[index].drawmethod.alpha>0 || level->layers[index].drawmethod.transbg) && !level->layers[index].drawmethod.water.watermode)
3380 		{
3381 		// assume sprites are faster than screen when transparency or alpha are specified
3382 			level->layers[index].gfx.sprite = loadsprite2(filename, &(level->layers[index].width),&(level->layers[index].height));
3383 		}
3384 		else
3385 		{
3386 		// use screen for water effect for now, it should be faster than sprite
3387 		// otherwise, a screen should be fine, especially in 8bit mode, it is super fast,
3388 		//            or, at least it is not slower than a sprite
3389 			if(loadscreen(filename, packfile, NULL, pixelformat, &level->layers[index].gfx.screen))
3390 			{
3391 				level->layers[index].height = level->layers[index].gfx.screen->height;
3392 				level->layers[index].width = level->layers[index].gfx.screen->width;
3393 			}
3394 		}
3395 	}
3396 
3397 	if(filename && level->layers[index].gfx.handle ==NULL) shutdown(1, "Error loading file '%s'", filename);
3398 	else{
3399 		if(level->layers[index].drawmethod.xrepeat<0) {
3400 			level->layers[index].xoffset -= level->layers[index].width*20000;
3401 			level->layers[index].drawmethod.xrepeat = 40000;
3402 		}
3403 		if(level->layers[index].drawmethod.yrepeat<0) {
3404 			level->layers[index].zoffset -= level->layers[index].height*20000;
3405 			level->layers[index].drawmethod.yrepeat = 40000;
3406 		}
3407 		//printf("bglayer width=%d height=%d xoffset=%d zoffset=%d xrepeat=%d zrepeat%d\n", level->layers[index].width, level->layers[index].height, level->layers[index].xoffset, level->layers[index].zoffset, level->layers[index].xrepeat, level->layers[index].zrepeat);
3408 	}
3409 
3410 }
3411 
3412 
loadsprite2(char * filename,int * width,int * height)3413 s_sprite* loadsprite2(char *filename, int* width, int* height)
3414 {
3415 	size_t size;
3416 	s_bitmap *bitmap = NULL;
3417 	s_sprite *sprite = NULL;
3418 	int clipl, clipr, clipt, clipb;
3419 
3420 	bitmap = loadbitmap(filename, packfile, pixelformat);
3421 	if(!bitmap) return NULL;
3422 	if(width) *width = bitmap->width;
3423 	if(height) *height = bitmap->height;
3424 	clipbitmap(bitmap, &clipl, &clipr, &clipt, &clipb);
3425 	size = fakey_encodesprite(bitmap);
3426 	sprite = (s_sprite*)malloc(size);
3427 	if(!sprite){
3428 		freebitmap(bitmap);
3429 		return NULL;
3430 	}
3431 	encodesprite(-clipl, -clipt, bitmap, sprite);
3432 	sprite->offsetx = clipl;
3433 	sprite->offsety = clipt;
3434 	sprite->srcwidth = bitmap->width;
3435 	sprite->srcheight = bitmap->height;
3436 	freebitmap(bitmap);
3437 
3438 	return sprite;
3439 }
3440 
3441 
3442 // Added to conserve memory
resourceCleanUp()3443 void resourceCleanUp(){
3444 	freesprites();
3445 	free_models();
3446 	free_modelcache();
3447 	load_special_sounds();
3448 	load_script_setting();
3449 	load_special_sprites();
3450 	load_levelorder();
3451 	load_models();
3452 }
3453 
freesprites()3454 void freesprites()
3455 {
3456 	unsigned short i;
3457 	s_sprite_list *head;
3458 	for(i=0; i<=sprites_loaded; i++)
3459 	{
3460 		if(sprite_list != NULL)
3461 		{
3462 			free(sprite_list->sprite);
3463 			sprite_list->sprite = NULL;
3464 			free(sprite_list->filename);
3465 			sprite_list->filename = NULL;
3466 			head = sprite_list->next;
3467 			free(sprite_list);
3468 			sprite_list = head;
3469 		}
3470 	}
3471 	if(sprite_map != NULL)
3472 	{
3473 		free(sprite_map);
3474 		sprite_map = NULL;
3475 	}
3476 	sprites_loaded = 0;
3477 }
3478 
3479 // allocate enough members for sprite_map
prepare_sprite_map(size_t size)3480 void prepare_sprite_map(size_t size)
3481 {
3482 	if(sprite_map == NULL || size + 1 > sprite_map_max_items )
3483 	{
3484 #ifdef VERBOSE
3485 		printf("%s %p\n", "prepare_sprite_map was", sprite_map);
3486 #endif
3487 		sprite_map_max_items = (((size+1)>>8)+1)<<8;
3488 		sprite_map = realloc(sprite_map, sizeof(s_sprite_map) * sprite_map_max_items);
3489 		if(sprite_map == NULL) shutdown(1, "Out Of Memory!  Failed to create a new sprite_map\n");
3490 	}
3491 }
3492 
cachesprite(int index,int load)3493 void cachesprite(int index, int load){
3494 	if(sprite_map && index>=0 && index<sprites_loaded){
3495 		if(!load && sprite_map[index].node->sprite){
3496 			free(sprite_map[index].node->sprite);
3497 			sprite_map[index].node->sprite = NULL;
3498 			//printf("uncached sprite: %s\n", sprite_map[index].node->filename);
3499 		}else if(load && !sprite_map[index].node->sprite){
3500 			sprite_map[index].node->sprite = loadsprite2(sprite_map[index].node->filename, NULL, NULL);
3501 		}
3502 	}
3503 }
3504 
3505 // Returns sprite index.
3506 // Does not return on error, as it would shut the program down.
3507 // UT:
3508 // bmpformat - In 24bit mode, a sprite can have a 24bit palette(e.g., panel),
3509 //             so add this paramter to let sprite encoding function know.
3510 //             Actually the sprite pixel encoding method is the same, but a
3511 //             24bit palettte sprite should have a palette allocated at the end of
3512 //             pixel data, and the information is carried by the bitmap paramter.
loadsprite(char * filename,int ofsx,int ofsy,int bmpformat)3513 int loadsprite(char *filename, int ofsx, int ofsy, int bmpformat)
3514 {
3515 	ptrdiff_t i, size, len;
3516 	s_bitmap *bitmap = NULL;
3517 	int clipl, clipr, clipt, clipb;
3518 	s_sprite_list *curr = NULL, *head = NULL, *toshare = NULL;
3519 
3520 	for(i=0; i<sprites_loaded; i++) {
3521 		if(sprite_map && sprite_map[i].node) {
3522 			if(stricmp(sprite_map[i].node->filename, filename) == 0) {
3523 				if(!sprite_map[i].node->sprite){
3524 					sprite_map[i].node->sprite = loadsprite2(filename, NULL, NULL);
3525 				}
3526 				if(sprite_map[i].centerx+sprite_map[i].node->sprite->offsetx == ofsx &&
3527 					sprite_map[i].centery+sprite_map[i].node->sprite->offsety == ofsy) {
3528 					return i;
3529 				} else {
3530 					toshare = sprite_map[i].node;
3531 				}
3532 			}
3533 		}
3534 	}
3535 
3536 	if(toshare){
3537 		prepare_sprite_map(sprites_loaded+1);
3538 		sprite_map[sprites_loaded].node = toshare;
3539 		sprite_map[sprites_loaded].centerx = ofsx-toshare->sprite->offsetx;
3540 		sprite_map[sprites_loaded].centery = ofsy-toshare->sprite->offsety;
3541 		++sprites_loaded;
3542 		return sprites_loaded-1;
3543 	}
3544 
3545 	bitmap = loadbitmap(filename, packfile, bmpformat);
3546 	if(bitmap == NULL) shutdown(1, "Unable to load file '%s'\n", filename);
3547 
3548 	clipbitmap(bitmap, &clipl, &clipr, &clipt, &clipb);
3549 
3550 	len = strlen(filename);
3551 	size = fakey_encodesprite(bitmap);
3552 	curr = malloc(sizeof(s_sprite_list));
3553 	curr->sprite = malloc(size);
3554 	curr->filename = malloc(len + 1);
3555 	if(curr == NULL || curr->sprite == NULL || curr->filename == NULL){
3556 		freebitmap(bitmap);
3557 		shutdown(1, "loadsprite() Out of memory!\n");
3558 	}
3559 	memcpy(curr->filename, filename,len);
3560 	curr->filename[len] = 0;
3561 	encodesprite(ofsx-clipl, ofsy-clipt, bitmap, curr->sprite);
3562 	if(sprite_list == NULL){
3563 		sprite_list = curr;
3564 		sprite_list->next = NULL;
3565 	}
3566 	else{
3567 		head = sprite_list;
3568 		sprite_list = curr;
3569 		sprite_list->next = head;
3570 	}
3571 	prepare_sprite_map(sprites_loaded+1);
3572 	sprite_map[sprites_loaded].node = sprite_list;
3573 	sprite_map[sprites_loaded].centerx = ofsx-clipl;
3574 	sprite_map[sprites_loaded].centery = ofsy-clipt;
3575 	sprite_list->sprite->offsetx = clipl;
3576 	sprite_list->sprite->offsety = clipt;
3577 	sprite_list->sprite->srcwidth = bitmap->width;
3578 	sprite_list->sprite->srcheight = bitmap->height;
3579 	freebitmap(bitmap);
3580 	++sprites_loaded;
3581 	return sprites_loaded-1;
3582 }
3583 
load_special_sprites()3584 void load_special_sprites()
3585 {
3586 	memset(shadowsprites, -1, sizeof(shadowsprites[0])*6);
3587 	golsprite = gosprite = -1;
3588 	if(testpackfile("data/sprites/shadow1.gif", packfile) >=0) shadowsprites[0] = loadsprite("data/sprites/shadow1",9,3,pixelformat);
3589 	if(testpackfile("data/sprites/shadow2.gif", packfile) >=0) shadowsprites[1] = loadsprite("data/sprites/shadow2",14,5,pixelformat);
3590 	if(testpackfile("data/sprites/shadow3.gif", packfile) >=0) shadowsprites[2] = loadsprite("data/sprites/shadow3",19,6,pixelformat);
3591 	if(testpackfile("data/sprites/shadow4.gif", packfile) >=0) shadowsprites[3] = loadsprite("data/sprites/shadow4",24,8,pixelformat);
3592 	if(testpackfile("data/sprites/shadow5.gif", packfile) >=0) shadowsprites[4] = loadsprite("data/sprites/shadow5",29,9,pixelformat);
3593 	if(testpackfile("data/sprites/shadow6.gif", packfile) >=0) shadowsprites[5] = loadsprite("data/sprites/shadow6",34,11,pixelformat);
3594 	if(testpackfile("data/sprites/arrow.gif", packfile) >=0) gosprite  = loadsprite("data/sprites/arrow",35,23,pixelformat);
3595 	if(testpackfile("data/sprites/arrowl.gif", packfile) >=0) golsprite = loadsprite("data/sprites/arrowl",35,23,pixelformat);
3596 	if(timeicon_path[0]) timeicon = loadsprite(timeicon_path,0,0,pixelformat);
3597 	if(bgicon_path[0]) bgicon = loadsprite(bgicon_path,0,0,pixelformat);
3598 	if(olicon_path[0]) olicon = loadsprite(olicon_path,0,0,pixelformat);
3599 }
3600 
unload_all_fonts()3601 void unload_all_fonts()
3602 {
3603 	int i;
3604 	for(i=0; i<MAX_FONTS; i++)
3605 	{
3606 		font_unload(i);
3607 	}
3608 }
3609 
load_all_fonts()3610 void load_all_fonts()
3611 {
3612 	char path[256];
3613 	int i;
3614 
3615 	for(i=0; i<MAX_FONTS; i++){
3616 		if(i==0) strcpy(path, "data/sprites/font");
3617 		else sprintf(path, "%s%d", "data/sprites/font", i+1);
3618 		if(font_load(i, path, packfile, fontmonospace[i]|fontmbs[i]))
3619 			printf("%d ", i+1);
3620 	}
3621 }
3622 
load_menu_txt()3623 void load_menu_txt()
3624 {
3625 	char * filename = "data/menu.txt";
3626 	int pos, i;
3627 	char *buf, *command;
3628 	size_t size;
3629 	ArgList arglist;
3630 	char argbuf[MAX_ARG_LEN+1] = "";
3631 
3632 	// Read file
3633 	if(buffer_pakfile(filename, &buf, &size)!=1)
3634 	{
3635 		return;
3636 	}
3637 
3638 	// Now interpret the contents of buf line by line
3639 	pos = 0;
3640 	while(pos<size){
3641 		if(ParseArgs(&arglist,buf+pos,argbuf)){
3642 			command = GET_ARG(0);
3643 			if(command && command[0]){
3644 				if(stricmp(command, "disablekey")==0){
3645 					// here to keep from crashing
3646 				}
3647 				else if(stricmp(command, "renamekey")==0){
3648 					// here to keep from crashing
3649 				}
3650 				else if(stricmp(command, "fontmonospace")==0)
3651 				{
3652 					for(i=0; i<MAX_FONTS; i++)
3653 						fontmonospace[i] = GET_INT_ARG((i+1))?FONT_MONO:0;
3654 				}
3655 				else if(stricmp(command, "fontmbs")==0)
3656 				{
3657 					for(i=0; i<MAX_FONTS; i++)
3658 						fontmbs[i] = GET_INT_ARG((i+1))?FONT_MBS:0;
3659 				}
3660 				else
3661 					if(command && command[0])
3662 						printf("Command '%s' not understood in file '%s'!", command, filename);
3663 			}
3664 		}
3665 
3666 		// Go to next line
3667 		pos += getNewLineStart(buf + pos);
3668 	}
3669 
3670 	if(buf != NULL){
3671 		free(buf);
3672 		buf = NULL;
3673 	}
3674 }
3675 
load_special_sounds()3676 int load_special_sounds()
3677 {
3678 	sound_unload_all_samples();
3679 	SAMPLE_GO		= sound_load_sample("data/sounds/go.wav",		packfile,	0);
3680 	SAMPLE_BEAT		= sound_load_sample("data/sounds/beat1.wav",	packfile,	0);
3681 	SAMPLE_BLOCK	= sound_load_sample("data/sounds/block.wav",	packfile,	0);
3682 	SAMPLE_FALL		= sound_load_sample("data/sounds/fall.wav",		packfile,	0);
3683 	SAMPLE_GET		= sound_load_sample("data/sounds/get.wav",		packfile,	0);
3684 	SAMPLE_GET2		= sound_load_sample("data/sounds/money.wav",	packfile,	0);
3685 	SAMPLE_JUMP		= sound_load_sample("data/sounds/jump.wav",		packfile,	0);
3686 	SAMPLE_INDIRECT	= sound_load_sample("data/sounds/indirect.wav",	packfile,	0);
3687 	SAMPLE_PUNCH	= sound_load_sample("data/sounds/punch.wav",	packfile,	0);
3688 	SAMPLE_1UP		= sound_load_sample("data/sounds/1up.wav",		packfile,	0);
3689 	SAMPLE_TIMEOVER = sound_load_sample("data/sounds/timeover.wav", packfile,	0);
3690 	SAMPLE_BEEP		= sound_load_sample("data/sounds/beep.wav",		packfile,	0);
3691 	SAMPLE_BEEP2	= sound_load_sample("data/sounds/beep2.wav",	packfile,	0);
3692 	SAMPLE_BIKE		= sound_load_sample("data/sounds/bike.wav",		packfile,	0);
3693 	if(SAMPLE_GO < 0 || SAMPLE_BEAT < 0 || SAMPLE_BLOCK < 0 ||
3694 	   SAMPLE_FALL < 0 || SAMPLE_GET < 0 || SAMPLE_GET2 < 0 ||
3695 	   SAMPLE_JUMP < 0 || SAMPLE_INDIRECT < 0 || SAMPLE_PUNCH < 0 ||
3696 	   SAMPLE_1UP < 0 || SAMPLE_TIMEOVER < 0 || SAMPLE_BEEP < 0 ||
3697 	   SAMPLE_BEEP2 < 0 || SAMPLE_BIKE < 0) return 0;
3698 	return 1;
3699 }
3700 
3701 // Use by player select menus
nextplayermodel(s_model * current)3702 s_model* nextplayermodel(s_model *current){
3703 	int i;
3704 	int curindex = -1;
3705 	int loops;
3706 	if(current){
3707 		// Find index of current player model
3708 		for(i=0; i<models_cached; i++){
3709 			if(model_cache[i].model == current){
3710 				curindex = i;
3711 				break;
3712 			}
3713 		}
3714 	}
3715 	// Find next player model (first one after current index)
3716 	for(i=curindex+1, loops=0; loops<models_cached; i++, loops++){
3717 		if(i >= models_cached) i = 0;
3718 		if(model_cache[i].model && model_cache[i].model->type==TYPE_PLAYER &&
3719 		  (allow_secret_chars || !model_cache[i].model->secret) &&
3720 			model_cache[i].model->clearcount<=bonus && model_cache[i].selectable){
3721 			//printf("next %s\n", model_cache[i].model->name);
3722 			return model_cache[i].model;
3723 		}
3724 	}
3725 	shutdown(1, "Fatal: can't find any player models!");
3726 	return NULL;
3727 }
3728 
3729 // Use by player select menus
prevplayermodel(s_model * current)3730 s_model* prevplayermodel(s_model *current){
3731 	int i;
3732 	int curindex = -1;
3733 	int loops;
3734 	if(current){
3735 		// Find index of current player model
3736 		for(i=0; i<models_cached; i++){
3737 			if(model_cache[i].model == current){
3738 				curindex = i;
3739 				break;
3740 			}
3741 		}
3742 	}
3743 	// Find next player model (first one after current index)
3744 	for(i=curindex-1, loops=0; loops<models_cached; i--, loops++){
3745 		if(i < 0) i = models_cached-1;
3746 		if(model_cache[i].model && model_cache[i].model->type==TYPE_PLAYER &&
3747 		  (allow_secret_chars || !model_cache[i].model->secret) &&
3748 			model_cache[i].model->clearcount<=bonus && model_cache[i].selectable){
3749 			//printf("prev %s\n", model_cache[i].model->name);
3750 			return model_cache[i].model;
3751 		}
3752 	}
3753 	shutdown(1, "Fatal: can't find any player models!");
3754 	return NULL;
3755 }
3756 
3757 // Reset All Player Models to on/off for Select Screen.
reset_playable_list(char which)3758 static void reset_playable_list(char which)
3759 {
3760 	int i;
3761 	for(i=0;i<models_cached;i++)
3762 	{
3763 		if(!which || (model_cache[i].model && model_cache[i].model->type == TYPE_PLAYER))
3764 		{
3765 			model_cache[i].selectable = which;
3766 		}
3767 	}
3768 }
3769 
3770 // Specify which Player Models are allowable for selecting
load_playable_list(char * buf)3771 static void load_playable_list(char* buf)
3772 {
3773 	int i, index;
3774 	char* value;
3775 	s_model *playermodels = NULL;
3776 	ArgList arglist;
3777 	char argbuf[MAX_ARG_LEN+1] = "";
3778 
3779 	reset_playable_list(0);
3780 	ParseArgs(&arglist,buf,argbuf);
3781 
3782 	for(i=1;(value=GET_ARG(i))[0];i++)
3783 	{
3784 		playermodels = findmodel(value);
3785 		//if(playermodels == NULL) shutdown(1, "Player model '%s' is not loaded.\n", value);
3786 		index = get_cached_model_index(playermodels->name);
3787 		if(index == -1) shutdown(1, "Player model '%s' is not cached.\n", value);
3788 		model_cache[index].selectable = 1;
3789 	}
3790 }
3791 
alloc_specials(s_model * newchar)3792 void alloc_specials(s_model* newchar){
3793 	newchar->special = realloc(newchar->special, sizeof(s_com)*(newchar->specials_loaded+1));
3794 }
3795 
alloc_frames(s_anim * anim,int fcount)3796 void alloc_frames(s_anim * anim, int fcount)
3797 {
3798 	anim->sprite = malloc(fcount * sizeof(anim->sprite));
3799 	anim->delay = malloc(fcount * sizeof(anim->delay));
3800 	anim->vulnerable = malloc(fcount * sizeof(anim->vulnerable));
3801 	memset(anim->sprite, 0, fcount*sizeof(anim->sprite));
3802 	memset(anim->delay, 0, fcount*sizeof(anim->delay));
3803 	memset(anim->vulnerable, 0, fcount*sizeof(anim->vulnerable));
3804 }
3805 
free_frames(s_anim * anim)3806 void free_frames(s_anim * anim)
3807 {
3808 	int i;
3809 	if(anim->idle)			{free(anim->idle);			 anim->idle = NULL;}
3810 	if(anim->seta)          {free(anim->seta);          anim->seta = NULL;}
3811 	if(anim->move)          {free(anim->move);          anim->move = NULL;}
3812 	if(anim->movez)         {free(anim->movez);         anim->movez = NULL;}
3813 	if(anim->movea)         {free(anim->movea);         anim->movea = NULL;}
3814 	if(anim->delay)         {free(anim->delay);         anim->delay = NULL;}
3815 	if(anim->sprite)        {free(anim->sprite);        anim->sprite = NULL;}
3816 	if(anim->platform)      {free(anim->platform);      anim->platform = NULL;}
3817 	if(anim->vulnerable)    {free(anim->vulnerable);    anim->vulnerable = NULL;}
3818 	if(anim->bbox_coords)   {free(anim->bbox_coords);   anim->bbox_coords = NULL;}
3819 	if(anim->shadow)        {free(anim->shadow);        anim->shadow = NULL;}
3820 	if(anim->shadow_coords) {free(anim->shadow_coords); anim->shadow_coords = NULL;}
3821 	if(anim->soundtoplay)   {free(anim->soundtoplay);   anim->soundtoplay = NULL;}
3822 	if(anim->attacks)
3823 	{
3824 		for(i=0; i<anim->numframes; i++)
3825 		{
3826 			if(anim->attacks[i])
3827 			{
3828 				free(anim->attacks[i]);
3829 				anim->attacks[i] = NULL;
3830 			}
3831 		}
3832 		free(anim->attacks);
3833 		anim->attacks = NULL;
3834 	}
3835 	if(anim->drawmethods)
3836 	{
3837 		for(i=0; i<anim->numframes; i++)
3838 		{
3839 			if(anim->drawmethods[i])
3840 			{
3841 				free(anim->drawmethods[i]);
3842 				anim->drawmethods[i] = NULL;
3843 			}
3844 		}
3845 		free(anim->drawmethods);
3846 		anim->drawmethods = NULL;
3847 	}
3848 }
3849 
3850 #if 0
3851 s_anim_list *anim_list_delete(s_anim_list *list, int index)
3852 {
3853 	if(list == NULL) return NULL;
3854 	if(list->anim->model_index == index)
3855 	{
3856 		s_anim_list *next;
3857 		next = list->next;
3858 		free_anim(list->anim);
3859 		free(list);
3860 		--anims_loaded;
3861 		return next;
3862 	}
3863 	list->next = anim_list_delete(list->next, index);
3864 	return list;
3865 }
3866 #endif
3867 
anim_list_delete(int index)3868 void anim_list_delete(int index)
3869 {
3870 	s_anim_list head;
3871 	head.next = anim_list;
3872 	s_anim_list* list = &head;
3873 	while(list && list->next)
3874 	{
3875 		if(list->next->anim->model_index == index)
3876 		{
3877 			s_anim_list *next = list->next->next;
3878 			free_anim(list->next->anim);
3879 			if(list->next==anim_list)
3880 				anim_list = next;
3881 			free(list->next);
3882 			--anims_loaded;
3883 			list->next = next;
3884 		}else list = list->next;
3885 	}
3886 }
3887 
free_anim(s_anim * anim)3888 void free_anim(s_anim * anim)
3889 {
3890 	if(!anim) return;
3891 	free_frames(anim);
3892 	if(anim->weaponframe)
3893 	{
3894 		free(anim->weaponframe);
3895 		anim->weaponframe = NULL;
3896 	}
3897 	if(anim->spawnframe)
3898 	{
3899 		free(anim->spawnframe);
3900 		anim->spawnframe = NULL;
3901 	}
3902 	if(anim->summonframe)
3903 	{
3904 		free(anim->summonframe);
3905 		anim->summonframe = NULL;
3906 	}
3907 	free(anim);
3908 }
3909 
hasFreetype(s_model * m,ModelFreetype t)3910 int hasFreetype(s_model* m, ModelFreetype t) {
3911 	assert(m);
3912 	return (m->freetypes & t) == t;
3913 }
3914 
addFreeType(s_model * m,ModelFreetype t)3915 void addFreeType(s_model* m, ModelFreetype t) {
3916 	assert(m);
3917 	m->freetypes |= t;
3918 }
3919 
cache_model_sprites(s_model * m,int ld)3920 void cache_model_sprites(s_model* m, int ld){
3921 	int i, f;
3922 	s_anim* anim;
3923 	cachesprite(m->icon.def, ld);
3924 	cachesprite(m->icon.die, ld);
3925 	cachesprite(m->icon.get, ld);
3926 	cachesprite(m->icon.mphigh, ld);
3927 	cachesprite(m->icon.mplow, ld);
3928 	cachesprite(m->icon.mpmed, ld);
3929 	cachesprite(m->icon.pain, ld);
3930 	cachesprite(m->icon.weapon, ld);
3931 	for(i=0; i<MAX_PLAYERS; i++)
3932 		cachesprite(m->parrow[i][0], ld);
3933 
3934 	//if(hasFreetype(model, MF_ANIMLIST)){
3935 	for(i=0; i<max_animations; i++){
3936 		anim = m->animation[i];
3937 		if(anim){
3938 			for(f=0;f<anim->numframes;f++){
3939 				cachesprite(anim->sprite[f], ld);
3940 			}
3941 		}
3942 	}
3943 }
3944 
3945 // Unload single model from memory
free_model(s_model * model)3946 int free_model(s_model* model)
3947 {
3948 	int i;
3949 	if(!model) return 0;
3950 	printf("Unload '%s' ", model->name);
3951 
3952 	if(hasFreetype(model, MF_ANIMLIST))
3953 		anim_list_delete(model->index);
3954 
3955 	printf(".");
3956 
3957 	if(hasFreetype(model, MF_COLOURMAP))
3958 		for(i=0; i<MAX_COLOUR_MAPS; i++)
3959 		{
3960 			if(model->colourmap[i] != NULL)
3961 			{
3962 				free(model->colourmap[i]);
3963 				model->colourmap[i] = NULL;
3964 			}
3965 		}
3966 
3967 	printf(".");
3968 
3969 	if(hasFreetype(model, MF_PALETTE) && model->palette)
3970 		{free(model->palette); model->palette = NULL;}
3971 	printf(".");
3972 	if(hasFreetype(model, MF_WEAPONS) && model->weapon && model->ownweapons)
3973 		{free(model->weapon); model->weapon = NULL;}
3974 	printf(".");
3975 	if(hasFreetype(model, MF_BRANCH) && model->branch)
3976 		{free(model->branch); model->branch = NULL;}
3977 	printf(".");
3978 	if(hasFreetype(model, MF_ANIMATION) && model->animation)
3979 		{free(model->animation); model->animation = NULL;}
3980 	printf(".");
3981 	if(hasFreetype(model, MF_DEFENSE) && model->defense)
3982 		{free(model->defense); model->defense = NULL;}
3983 	printf(".");
3984 	if(hasFreetype(model, MF_OFF_FACTORS) && model->offense_factors)
3985 		{free(model->offense_factors); model->offense_factors = NULL;}
3986 	printf(".");
3987 	if(hasFreetype(model, MF_SPECIAL) && model->special)
3988 		{free(model->special); model->special = NULL;}
3989 	printf(".");
3990 	if(hasFreetype(model, MF_SMARTBOMB) && model->smartbomb)
3991 		{free(model->smartbomb); model->smartbomb = NULL;}
3992 	printf(".");
3993 
3994 	if(hasFreetype(model, MF_SCRIPTS)) {
3995 		clear_all_scripts(model->scripts,2);
3996 		free_all_scripts(&model->scripts);
3997 	}
3998 	printf(".");
3999 
4000 	model_cache[model->index].model = NULL;
4001 	deleteModel(model->name);
4002 	printf(".");
4003 
4004 	printf("done.\n");
4005 
4006 	return models_loaded--;
4007 }
4008 
4009 // Unload all models and animations memory
free_models()4010 void free_models()
4011 {
4012 	s_model* temp;
4013 
4014 	while((temp = getFirstModel()))
4015 		free_model(temp);
4016 
4017 	// free animation ids
4018 	if(animdowns)       {free(animdowns);       animdowns          = NULL;}
4019 	if(animups)         {free(animups);         animups            = NULL;}
4020 	if(animbackwalks)   {free(animbackwalks);   animbackwalks      = NULL;}
4021 	if(animwalks)       {free(animwalks);       animwalks          = NULL;}
4022 	if(animidles)       {free(animidles);       animidles          = NULL;}
4023 	if(animspecials)    {free(animspecials);    animspecials       = NULL;}
4024 	if(animattacks)     {free(animattacks);     animattacks        = NULL;}
4025 	if(animfollows)     {free(animfollows);     animfollows        = NULL;}
4026 	if(animpains)       {free(animpains);       animpains          = NULL;}
4027 	if(animfalls)       {free(animfalls);       animfalls          = NULL;}
4028 	if(animrises)       {free(animrises);       animrises          = NULL;}
4029 	if(animriseattacks) {free(animriseattacks); animriseattacks    = NULL;}
4030 	if(animblkpains)    {free(animblkpains);    animblkpains       = NULL;}
4031 	if(animdies)        {free(animdies);        animdies           = NULL;}
4032 }
4033 
4034 
alloc_anim()4035 s_anim * alloc_anim()
4036 {
4037 	static int animindex = 0;
4038 	s_anim_list *curr = NULL, *head = NULL;
4039 	curr = malloc(sizeof(s_anim_list));
4040 	curr->anim = malloc(sizeof(s_anim));
4041 	if(curr == NULL || curr->anim == NULL) return NULL;
4042 	memset(curr->anim, 0, sizeof(s_anim));
4043 	curr->anim->index = animindex++;
4044 	if(anim_list == NULL){
4045 		anim_list = curr;
4046 		anim_list->next = NULL;
4047 	}
4048 	else{
4049 		head = anim_list;
4050 		anim_list = curr;
4051 		anim_list->next = head;
4052 	}
4053 	++anims_loaded;
4054 	return anim_list->anim;
4055 }
4056 
4057 
addframe(s_anim * a,int spriteindex,int framecount,short delay,unsigned char idle,short * bbox,s_attack * attack,short move,short movez,short movea,short seta,float * platform,int frameshadow,short * shadow_coords,int soundtoplay,s_drawmethod * drawmethod)4058 int addframe(s_anim * a, int spriteindex, int framecount, short delay, unsigned char idle,
4059 			 short *bbox, s_attack* attack, short move, short movez, short movea,
4060 			 short seta, float* platform, int frameshadow, short* shadow_coords, int soundtoplay, s_drawmethod* drawmethod)
4061 {
4062 	ptrdiff_t currentframe;
4063 	if(framecount>0) alloc_frames(a, framecount);
4064 	else framecount = -framecount; // for alloc method, use a negative value
4065 
4066 	currentframe = a->numframes;
4067 	++a->numframes;
4068 
4069 	a->sprite[currentframe] = spriteindex;
4070 	a->delay[currentframe] = delay * GAME_SPEED / 100;
4071 
4072 	if((bbox[2]-bbox[0]) && (bbox[3]-bbox[1]))
4073 	{
4074 		if(!a->bbox_coords)
4075 		{
4076 			a->bbox_coords = malloc(framecount * sizeof(*a->bbox_coords));
4077 			memset(a->bbox_coords, 0, framecount * sizeof(*a->bbox_coords));
4078 		}
4079 		memcpy(a->bbox_coords[currentframe], bbox, sizeof(*a->bbox_coords));
4080 		a->vulnerable[currentframe] = 1;
4081 	}
4082 	if((attack->attack_coords[2]-attack->attack_coords[0]) &&
4083 		(attack->attack_coords[3]-attack->attack_coords[1]))
4084 	{
4085 		if(!a->attacks)
4086 		{
4087 			a->attacks = malloc(framecount * sizeof(s_attack*));
4088 			memset(a->attacks, 0, framecount * sizeof(s_attack*));
4089 		}
4090 		a->attacks[currentframe] = malloc(sizeof(s_attack));
4091 		memcpy(a->attacks[currentframe], attack, sizeof(s_attack));
4092 	}
4093 	if(drawmethod->flag)
4094 	{
4095 		if(!a->drawmethods)
4096 		{
4097 			a->drawmethods = malloc(framecount * sizeof(s_drawmethod*));
4098 			memset(a->drawmethods, 0, framecount * sizeof(s_drawmethod*));
4099 		}
4100 		setDrawMethod(a, currentframe, malloc(sizeof(s_drawmethod)));
4101 		//a->drawmethods[currenframe] = malloc(sizeof(s_drawmethod));
4102 		memcpy(getDrawMethod(a,currentframe), drawmethod, sizeof(s_drawmethod));
4103 		//memcpy(a->drawmethods[currentframe], drawmethod, sizeof(s_drawmethod));
4104 	}
4105 	if(idle && !a->idle)
4106 	{
4107 		a->idle = malloc(framecount*sizeof(*a->idle));
4108 		memset(a->idle, 0, framecount*sizeof(*a->idle));
4109 	}
4110 	if(a->idle) a->idle[currentframe] = idle;
4111 	if(move && !a->move)
4112 	{
4113 		a->move = malloc(framecount * sizeof(*a->move));
4114 		memset(a->move, 0, framecount * sizeof(*a->move));
4115 	}
4116 	if(a->move) a->move[currentframe] = move;
4117 	if(movez && !a->movez)
4118 	{
4119 		a->movez = malloc(framecount * sizeof(*a->movez));
4120 		memset(a->movez, 0, framecount * sizeof(*a->movez));
4121 	}
4122 	if(a->movez) a->movez[currentframe] = movez;						           // Move command for the "z" axis
4123 	if(movea && !a->movea)
4124 	{
4125 		a->movea = malloc(framecount * sizeof(*a->movea));
4126 		memset(a->movea, 0, framecount * sizeof(*a->movea));
4127 	}
4128 	if(a->movea) a->movea[currentframe] = movea;						           // Move command for moving along the "a" axis
4129 	if(seta>=0 && !a->seta)
4130 	{
4131 		a->seta = malloc(framecount * sizeof(*a->seta));
4132 		memset(a->seta, -1, framecount * sizeof(*a->seta)); //default to -1
4133 	}
4134 	if(a->seta) a->seta[currentframe] = seta;						               // Sets the "a" for the character on a frame/frame basis
4135 	if(frameshadow >= 0 && !a->shadow)
4136 	{
4137 		a->shadow = malloc(framecount * sizeof(*a->shadow));
4138 		memset(a->shadow, -1, framecount * sizeof(*a->shadow)); //default to -1
4139 	}
4140 	if(a->shadow) a->shadow[currentframe] = frameshadow;                          // shadow index for each frame
4141 	if(shadow_coords[0] || shadow_coords[1])
4142 	{
4143 		if(!a->shadow_coords)
4144 		{
4145 			a->shadow_coords=malloc(framecount * sizeof(*a->shadow_coords));
4146 			memset(a->shadow_coords, 0, framecount * sizeof(*a->shadow_coords));
4147 		}
4148 		memcpy(a->shadow_coords[currentframe], shadow_coords, sizeof(*a->shadow_coords));
4149 	}
4150 	if(platform[7]) //height
4151 	{
4152 		if(!a->platform)
4153 		{
4154 			a->platform = malloc(framecount * sizeof(*a->platform));
4155 			memset(a->platform, 0, framecount * sizeof(*a->platform));
4156 		}
4157 		memcpy(a->platform[currentframe], platform, sizeof(*a->platform));// Used so entity can be landed on
4158 	}
4159 	if(soundtoplay >= 0)
4160 	{
4161 		if(!a->soundtoplay)
4162 		{
4163 			a->soundtoplay = malloc(framecount * sizeof(*a->soundtoplay));
4164 			memset(a->soundtoplay, -1, framecount * sizeof(*a->soundtoplay)); // default to -1
4165 		}
4166 		a->soundtoplay[currentframe] = soundtoplay;
4167 	}
4168 
4169 	return a->numframes;
4170 }
4171 
4172 
4173 // ok this func only seems to overwrite the name which was assigned from models.txt with the one
4174 // in the models own text file.
4175 // it does so in the cache.
_peek_model_name(int index)4176 void _peek_model_name(int index)
4177 {
4178 	size_t size = 0;
4179 	ptrdiff_t pos = 0, len;
4180 	char *buf = NULL;
4181 	char *command, *value;
4182 	ArgList arglist;
4183 	char argbuf[MAX_ARG_LEN+1] = "";
4184 	modelCommands cmd;
4185 
4186 	if(buffer_pakfile(model_cache[index].path, &buf, &size)!=1) return;
4187 
4188 	while(pos<size)
4189 	{
4190 		ParseArgs(&arglist,buf+pos,argbuf);
4191 		command = GET_ARG(0);
4192 
4193 		if(command && command[0]){
4194 			cmd = getModelCommand(modelcmdlist, command);
4195 			if(cmd == CMD_MODEL_NAME)
4196 			{
4197 				value = GET_ARG(1);
4198 				free(model_cache[index].name);
4199 				model_cache[index].name = NULL;
4200 				len = strlen(value);
4201 				model_cache[index].name = malloc(len + 1);
4202 				strcpy(model_cache[index].name, value);
4203 				model_cache[index].name[len] = 0;
4204 				break;
4205 			}
4206 		}
4207 		pos += getNewLineStart(buf + pos);
4208 	}
4209 
4210 	if(buf != NULL)
4211 	{
4212 		free(buf);
4213 		buf = NULL;
4214 	}
4215 }
4216 
prepare_cache_map(size_t size)4217 void prepare_cache_map(size_t size)
4218 {
4219 	if(model_cache== NULL || size + 1 > cache_map_max_items )
4220 	{
4221 #ifdef VERBOSE
4222 		printf("%s %p\n", "prepare_cache_map was", model_cache);
4223 #endif
4224 		do {
4225 			cache_map_max_items += 128;
4226 		}
4227 		while (size + 1 > cache_map_max_items);
4228 
4229 		model_cache = realloc(model_cache, sizeof(s_modelcache) * cache_map_max_items);
4230 		if(model_cache == NULL) shutdown(1, "Out Of Memory!  Failed to create a new cache_map\n");
4231 	}
4232 }
4233 
cache_model(char * name,char * path,int flag)4234 void cache_model(char *name, char *path, int flag)
4235 {
4236 	int len;
4237 	printf("Cacheing '%s' from %s\n", name, path);
4238 	prepare_cache_map(models_cached+1);
4239 	memset(&model_cache[models_cached], 0, sizeof(s_modelcache));
4240 
4241 	len = strlen(name);
4242 	model_cache[models_cached].name = malloc(len + 1);
4243 	strcpy(model_cache[models_cached].name, name);
4244 	model_cache[models_cached].name[len] = 0;
4245 
4246 	len = strlen(path);
4247 	model_cache[models_cached].path = malloc(len + 1);
4248 	strcpy(model_cache[models_cached].path, path);
4249 	model_cache[models_cached].path[len] = 0;
4250 
4251 	model_cache[models_cached].loadflag = flag;
4252 
4253 	_peek_model_name(models_cached);
4254 	++models_cached;
4255 }
4256 
4257 
free_modelcache()4258 void free_modelcache()
4259 {
4260 	if(model_cache != NULL)
4261 	{
4262 		while(models_cached)
4263 		{
4264 			--models_cached;
4265 			free(model_cache[models_cached].name);
4266 			model_cache[models_cached].name = NULL;
4267 			free(model_cache[models_cached].path);
4268 			model_cache[models_cached].path = NULL;
4269 		}
4270 		free(model_cache);
4271 		model_cache = NULL;
4272 	}
4273 }
4274 
4275 
get_cached_model_index(char * name)4276 int get_cached_model_index(char * name)
4277 {
4278 	int i;
4279 	for(i=0; i<models_cached; i++)
4280 	{
4281 		if(stricmp(name, model_cache[i].name)==0) return i;
4282 	}
4283 	return -1;
4284 }
4285 
get_cached_model_path(char * name)4286 char *get_cached_model_path(char * name)
4287 {
4288 	int i;
4289 	for(i=0; i<models_cached; i++)
4290 	{
4291 		if(stricmp(name, model_cache[i].name)==0) return model_cache[i].path;
4292 	}
4293 	return NULL;
4294 }
4295 
4296 static void _readbarstatus(char*, s_barstatus*);
4297 
lcmHandleCommandName(ArgList * arglist,s_model * newchar,int cacheindex)4298 void lcmHandleCommandName(ArgList* arglist, s_model* newchar, int cacheindex) {
4299 	char* value = GET_ARGP(1);
4300 	s_model* tempmodel;
4301 	if((tempmodel=findmodel(value)) && tempmodel!=newchar) shutdown(1, "Duplicate model name '%s'", value);
4302 	/*if((tempmodel=find_model(value))) {
4303 		return tempmodel;
4304 	}*/
4305 	model_cache[cacheindex].model = newchar;
4306 	newchar->name = model_cache[cacheindex].name;
4307 	if(stricmp(newchar->name, "steam")==0)
4308 	{
4309 		newchar->alpha = 1;
4310 	}
4311 }
4312 
lcmHandleCommandType(ArgList * arglist,s_model * newchar,char * filename)4313 void lcmHandleCommandType(ArgList* arglist, s_model* newchar, char* filename) {
4314 	char* value = GET_ARGP(1);
4315 	int i;
4316 	if(stricmp(value, "none")==0){
4317 		newchar->type = TYPE_NONE;
4318 	}
4319 	else if(stricmp(value, "player")==0){
4320 		newchar->type = TYPE_PLAYER;
4321 		newchar->nopassiveblock = 1;
4322 		for(i=0; i<MAX_ATCHAIN; i++)
4323 		{
4324 			if(i < 2 || i > 3) newchar->atchain[i] = 1;
4325 			else newchar->atchain[i] = i;
4326 		}
4327 		newchar->chainlength            = 4;
4328 		newchar->bounce                 = 1;
4329 		newchar->subject_to_wall        = 1;
4330 		newchar->subject_to_platform    = 1;
4331 		newchar->subject_to_obstacle    = 1;
4332 		newchar->subject_to_hole        = 1;
4333 		newchar->subject_to_gravity     = 1;
4334 		newchar->subject_to_screen      = 1;
4335 		newchar->subject_to_minz        = 1;
4336 		newchar->subject_to_maxz        = 1;
4337 		newchar->no_adjust_base         = 0;
4338 	}
4339 	else if(stricmp(value, "enemy")==0){
4340 		newchar->type                   = TYPE_ENEMY;
4341 		newchar->bounce                 = 1;
4342 		newchar->subject_to_wall        = 1;
4343 		newchar->subject_to_platform    = 1;
4344 		newchar->subject_to_hole        = 1;
4345 		newchar->subject_to_obstacle    = 1;
4346 		newchar->subject_to_gravity     = 1;
4347 		newchar->subject_to_minz        = 1;
4348 		newchar->subject_to_maxz        = 1;
4349 		newchar->no_adjust_base         = 0;
4350 	}
4351 	else if(stricmp(value, "item")==0){
4352 		newchar->type                   = TYPE_ITEM;
4353 		newchar->subject_to_wall        = 1;
4354 		newchar->subject_to_platform    = 1;
4355 		newchar->subject_to_hole        = 1;
4356 		newchar->subject_to_obstacle    = 1;
4357 		newchar->subject_to_gravity     = 1;
4358 		newchar->subject_to_minz        = 1;
4359 		newchar->subject_to_maxz        = 1;
4360 		newchar->no_adjust_base         = 0;
4361 	}
4362 	else if(stricmp(value, "obstacle")==0){
4363 		newchar->type                   = TYPE_OBSTACLE;
4364 		if(newchar->aimove==-1) newchar->aimove = 0;
4365 		newchar->aimove |= AIMOVE1_NOMOVE;
4366 		if(newchar->aimove==-1) newchar->aiattack = 0;
4367 		newchar->aimove |= AIATTACK1_NOATTACK;
4368 		newchar->subject_to_wall        = 1;
4369 		newchar->subject_to_platform    = 1;
4370 		newchar->subject_to_hole        = 1;
4371 		newchar->subject_to_gravity     = 1;
4372 		newchar->subject_to_minz        = 1;
4373 		newchar->subject_to_maxz        = 1;
4374 		newchar->no_adjust_base         = 0;
4375 	}
4376 	else if(stricmp(value, "steamer")==0){
4377 		newchar->type = TYPE_STEAMER;
4378 	}
4379 	// my new types   7-1-2005
4380 	else if(stricmp(value, "pshot")==0){
4381 		newchar->type = TYPE_SHOT;
4382 		if(newchar->aimove==-1) newchar->aimove = 0;
4383 		newchar->aimove |= AIMOVE1_ARROW;
4384 		if(!newchar->offscreenkill) newchar->offscreenkill = 200;
4385 		newchar->subject_to_hole                = 0;
4386 		newchar->subject_to_gravity             = 1;
4387 		newchar->subject_to_wall                = 0;
4388 		newchar->subject_to_platform            = 0;
4389 		newchar->subject_to_screen              = 0;
4390 		newchar->subject_to_minz                = 1;
4391 		newchar->subject_to_maxz                = 1;
4392 		newchar->subject_to_platform            = 0;
4393 		newchar->no_adjust_base                 = 1;
4394 	}
4395 	else if(stricmp(value, "trap")==0){
4396 		newchar->type                   = TYPE_TRAP;
4397 		newchar->subject_to_wall        = 1;
4398 		newchar->subject_to_platform    = 1;
4399 		newchar->subject_to_hole        = 1;
4400 		newchar->subject_to_gravity     = 1;
4401 		newchar->subject_to_minz        = 1;
4402 		newchar->subject_to_maxz        = 1;
4403 		newchar->no_adjust_base         = 0;
4404 	}
4405 	else if(stricmp(value, "text")==0){    // Used for displaying text/images and freezing the screen
4406 		newchar->type                   = TYPE_TEXTBOX;
4407 		newchar->subject_to_gravity     = 0;
4408 		newchar->subject_to_minz        = 1;
4409 		newchar->subject_to_maxz        = 1;
4410 	}
4411 	else if(stricmp(value, "endlevel")==0){    // Used for ending the level when the players reach a certain point
4412 		newchar->type                   = TYPE_ENDLEVEL;
4413 		newchar->subject_to_wall        = 1;
4414 		newchar->subject_to_platform    = 1;
4415 		newchar->subject_to_hole        = 1;
4416 		newchar->subject_to_obstacle    = 1;
4417 		newchar->subject_to_gravity     = 1;
4418 	}
4419 	else if(stricmp(value, "npc")==0){    // NPC type
4420 		newchar->type                   = TYPE_NPC;
4421 		newchar->bounce                 = 1;
4422 		newchar->subject_to_wall        = 1;
4423 		newchar->subject_to_platform    = 1;
4424 		newchar->subject_to_hole        = 1;
4425 		newchar->subject_to_obstacle    = 1;
4426 		newchar->subject_to_gravity     = 1;
4427 		newchar->subject_to_minz        = 1;
4428 		newchar->subject_to_maxz        = 1;
4429 		newchar->no_adjust_base         = 0;
4430 	}
4431 	else if(stricmp(value, "panel")==0){    // NPC type
4432 		newchar->type                   = TYPE_PANEL;
4433 		newchar->antigravity            = 1.0; //float type
4434 		newchar->subject_to_gravity     = 1;
4435 		newchar->no_adjust_base         = 1;
4436 	}
4437 	else shutdown(1, "Model '%s' has invalid type: '%s'", filename, value);
4438 }
4439 
lcmHandleCommandSubtype(ArgList * arglist,s_model * newchar,char * filename)4440 void lcmHandleCommandSubtype(ArgList* arglist, s_model* newchar, char* filename) {
4441 	char* value = GET_ARGP(1);
4442 	int i;
4443 	if(stricmp(value, "biker")==0){
4444 		newchar->subtype                                        = SUBTYPE_BIKER;
4445 		if(newchar->aimove==-1) newchar->aimove                 = 0;
4446 		newchar->aimove |= AIMOVE1_BIKER;
4447 		if(!newchar->offscreenkill) newchar->offscreenkill = 300;
4448 		for(i=0; i<max_attack_types; i++)
4449 			newchar->defense[i].factor = 2.f;
4450 		newchar->subject_to_hole                                = 1;
4451 		newchar->subject_to_gravity                             = 1;
4452 		newchar->subject_to_wall                                = 0;
4453 		newchar->subject_to_platform                            = 0;
4454 		newchar->subject_to_screen                              = 0;
4455 		newchar->subject_to_minz                                = 1;
4456 		newchar->subject_to_maxz                                = 1;
4457 		newchar->subject_to_platform                            = 0;
4458 		newchar->no_adjust_base                                 = 0;
4459 	}
4460 	else if(stricmp(value, "arrow")==0){  // 7-1-2005 Arrow type
4461 		newchar->subtype = SUBTYPE_ARROW;   // 7-1-2005 Arrow type
4462 		if(newchar->aimove==-1) newchar->aimove = 0;
4463 		newchar->aimove |= AIMOVE1_ARROW;
4464 		if(!newchar->offscreenkill) newchar->offscreenkill = 200;
4465 		newchar->subject_to_hole        = 0;
4466 		newchar->subject_to_gravity     = 1;
4467 		newchar->subject_to_wall        = 0;
4468 		newchar->subject_to_platform    = 0;
4469 		newchar->subject_to_screen      = 0;
4470 		newchar->subject_to_minz        = 1;
4471 		newchar->subject_to_maxz        = 1;
4472 		newchar->subject_to_platform    = 0;
4473 		newchar->no_adjust_base         = 1;
4474 	}
4475 	else if(stricmp(value, "notgrab")==0){  // 7-1-2005 notgrab type
4476 		newchar->subtype = SUBTYPE_NOTGRAB;   // 7-1-2005 notgrab type
4477 	}
4478 	//    ltb 1-18-05  Item Subtype
4479 	else if(stricmp(value, "touch")==0){  // 7-1-2005 notgrab type
4480 		newchar->subtype = SUBTYPE_TOUCH;   // 7-1-2005 notgrab type
4481 	}
4482 	else if(stricmp(value, "weapon")==0){  // 7-1-2005 notgrab type
4483 		newchar->subtype = SUBTYPE_WEAPON;   // 7-1-2005 notgrab type
4484 	}
4485 	else if(stricmp(value, "noskip")==0){    // Text animation cannot be skipped if subtype noskip
4486 		newchar->subtype = SUBTYPE_NOSKIP;
4487 	}
4488 	else if(stricmp(value, "flydie")==0){    // Obstacle will fly across the screen when hit if subtype flydie
4489 		newchar->subtype = SUBTYPE_FLYDIE;
4490 	}
4491 	else if(stricmp(value, "both")==0){
4492 		newchar->subtype = SUBTYPE_BOTH;
4493 	}
4494 	else if(stricmp(value, "project")==0){
4495 		newchar->subtype = SUBTYPE_PROJECTILE;
4496 	}
4497 	else if(stricmp(value, "follow")==0){
4498 		newchar->subtype = SUBTYPE_FOLLOW;
4499 	}
4500 	else if(stricmp(value, "chase")==0){
4501 		newchar->subtype = SUBTYPE_CHASE;
4502 	}
4503 	//    end new subtype
4504 	else shutdown(1, "Model '%s' has invalid subtype: '%s'", filename, value);
4505 }
4506 
lcmHandleCommandSmartbomb(ArgList * arglist,s_model * newchar,char * filename)4507 void lcmHandleCommandSmartbomb(ArgList* arglist, s_model* newchar, char* filename) {
4508 	//smartbomb now use a normal attack box
4509 	if(!newchar->smartbomb) {
4510 		newchar->smartbomb = malloc(sizeof(s_attack));
4511 		*(newchar->smartbomb) = emptyattack;
4512 	} else shutdown(1, "Model '%s' has multiple smartbomb commands defined.", filename);
4513 
4514 	newchar->smartbomb->attack_force = atoi(GET_ARGP(1));			// Special force
4515 	newchar->smartbomb->attack_type = atoi(GET_ARGP(2));			// Special attack type
4516 	newchar->smartbomb->attack_drop = 1; //by default
4517 	newchar->smartbomb->dropv[0] = default_model_dropv[0];
4518 
4519 	if(newchar->smartbomb->attack_type==ATK_BLAST) {
4520 		newchar->smartbomb->blast = 1;
4521 		newchar->smartbomb->dropv[1] = default_model_dropv[1]*2.083f;
4522 	} else {
4523 		newchar->smartbomb->dropv[1] = default_model_dropv[1];
4524 	}
4525 
4526 	if(newchar->smartbomb->attack_type==ATK_FREEZE) {
4527 		newchar->smartbomb->freeze = 1;
4528 		newchar->smartbomb->forcemap = -1;
4529 		newchar->smartbomb->attack_drop = 0;
4530 	} else if(newchar->smartbomb->attack_type==ATK_STEAL) {
4531 		newchar->smartbomb->steal = 1;
4532 	}
4533 
4534 	if(newchar->type == TYPE_ITEM) {
4535 		newchar->dofreeze = 0;								// Items don't animate
4536 		newchar->smartbomb->freezetime = atoi(GET_ARGP(3)) * GAME_SPEED;
4537 	} else {
4538 		newchar->dofreeze = atoi(GET_ARGP(3));		// Are all animations frozen during special
4539 		newchar->smartbomb->freezetime = atoi(GET_ARGP(4)) * GAME_SPEED;
4540 	}
4541 }
4542 
lcmHandleCommandHostile(ArgList * arglist,s_model * newchar)4543 void lcmHandleCommandHostile(ArgList* arglist, s_model* newchar) {
4544 	int i = 1;
4545 	char* value = GET_ARGP(i);
4546 	newchar->hostile = 0;
4547 
4548 	while(value && value[0])
4549 	{
4550 		if(stricmp(value, "enemy")==0){
4551 			newchar->hostile |= TYPE_ENEMY;
4552 		} else if(stricmp(value, "player")==0){
4553 			newchar->hostile |= TYPE_PLAYER;
4554 		} else if(stricmp(value, "obstacle")==0){
4555 			newchar->hostile |= TYPE_OBSTACLE;
4556 		} else if(stricmp(value, "shot")==0){
4557 			newchar->hostile |= TYPE_SHOT;
4558 		} else if(stricmp(value, "npc")==0){
4559 			newchar->hostile |= TYPE_NPC;
4560 		}
4561 		i++;
4562 		value = GET_ARGP(i);
4563 	}
4564 }
lcmHandleCommandCandamage(ArgList * arglist,s_model * newchar)4565 void lcmHandleCommandCandamage(ArgList* arglist, s_model* newchar) {
4566 	int i = 1;
4567 	char* value = GET_ARGP(i);
4568 	newchar->candamage = 0;
4569 
4570 	while(value && value[0])
4571 	{
4572 		if(stricmp(value, "enemy")==0){
4573 			newchar->candamage |= TYPE_ENEMY;
4574 		} else if(stricmp(value, "player")==0){
4575 			newchar->candamage |= TYPE_PLAYER;
4576 		} else if(stricmp(value, "obstacle")==0){
4577 			newchar->candamage |= TYPE_OBSTACLE;
4578 		} else if(stricmp(value, "shot")==0){
4579 			newchar->candamage |= TYPE_SHOT;
4580 		} else if(stricmp(value, "npc")==0){
4581 			newchar->candamage |= TYPE_NPC;
4582 		} else if(stricmp(value, "ground")==0){ // not really needed, though
4583 			newchar->ground = 1;
4584 		}
4585 		i++;
4586 		value = GET_ARGP(i);
4587 	}
4588 }
4589 
lcmHandleCommandProjectilehit(ArgList * arglist,s_model * newchar)4590 void lcmHandleCommandProjectilehit(ArgList* arglist, s_model* newchar) {
4591 	int i = 1;
4592 	char* value = GET_ARGP(i);
4593 
4594 	newchar->projectilehit = 0;
4595 
4596 	while(value && value[0])
4597 	{
4598 		if(stricmp(value, "enemy")==0){
4599 			newchar->projectilehit |= TYPE_ENEMY;
4600 		} else if(stricmp(value, "player")==0){
4601 			newchar->projectilehit |= TYPE_PLAYER;
4602 		} else if(stricmp(value, "obstacle")==0){
4603 			newchar->projectilehit |= TYPE_OBSTACLE;
4604 		} else if(stricmp(value, "shot")==0){
4605 			newchar->projectilehit |= TYPE_SHOT;
4606 		} else if(stricmp(value, "npc")==0){
4607 			newchar->projectilehit |= TYPE_NPC;
4608 		}
4609 		i++;
4610 		value = GET_ARGP(i);
4611 	}
4612 }
4613 
lcmHandleCommandAimove(ArgList * arglist,s_model * newchar,int * aimoveset,char * filename)4614 void lcmHandleCommandAimove(ArgList* arglist, s_model* newchar, int* aimoveset, char* filename) {
4615 	char* value = GET_ARGP(1);
4616 	if(!*aimoveset)
4617 	{
4618 		newchar->aimove = 0;
4619 		*aimoveset = 1;
4620 	}
4621 
4622 	//main A.I. move switches
4623 	if(value && value[0])
4624 	{
4625 		if(stricmp(value, "normal")==0){
4626 			newchar->aimove |= AIMOVE1_NORMAL;
4627 		}
4628 		else if(stricmp(value, "chase")==0){
4629 			newchar->aimove |= AIMOVE1_CHASE;
4630 		}
4631 		else if(stricmp(value, "chasex")==0){
4632 			newchar->aimove |= AIMOVE1_CHASEX;
4633 		}
4634 		else if(stricmp(value, "chasez")==0){
4635 			newchar->aimove |= AIMOVE1_CHASEZ;
4636 		}
4637 		else if(stricmp(value, "avoid")==0){
4638 			newchar->aimove |= AIMOVE1_AVOID;
4639 		}
4640 		else if(stricmp(value, "avoidx")==0){
4641 			newchar->aimove |= AIMOVE1_AVOIDX;
4642 		}
4643 		else if(stricmp(value, "avoidz")==0){
4644 			newchar->aimove |= AIMOVE1_AVOIDZ;
4645 		}
4646 		else if(stricmp(value, "wander")==0){
4647 			newchar->aimove |= AIMOVE1_WANDER;
4648 		}
4649 		else if(stricmp(value, "biker")==0){
4650 			newchar->aimove |= AIMOVE1_BIKER;
4651 		}
4652 		else if(stricmp(value, "arrow")==0){
4653 			newchar->aimove |= AIMOVE1_ARROW;
4654 			if(!newchar->offscreenkill) newchar->offscreenkill = 200;
4655 		}
4656 		else if(stricmp(value, "star")==0){
4657 			newchar->aimove |= AIMOVE1_STAR;
4658 		}
4659 		else if(stricmp(value, "bomb")==0){
4660 			newchar->aimove |= AIMOVE1_BOMB;
4661 		}
4662 		else if(stricmp(value, "nomove")==0){
4663 			newchar->aimove |= AIMOVE1_NOMOVE;
4664 		}
4665 		else shutdown(1, "Model '%s' has invalid A.I. move switch: '%s'", filename, value);
4666 	}
4667 	value = GET_ARGP(2);
4668 	//sub A.I. move switches
4669 	if(value && value[0])
4670 	{
4671 		if(stricmp(value, "normal")==0){
4672 			newchar->aimove |= AIMOVE2_NORMAL;
4673 		}
4674 		else if(stricmp(value, "ignoreholes")==0){
4675 			newchar->aimove |= AIMOVE2_IGNOREHOLES;
4676 		}
4677 		else if(stricmp(value, "notargetidle")==0){
4678 			newchar->aimove |= AIMOVE2_NOTARGETIDLE;
4679 		}
4680 		else shutdown(1, "Model '%s' has invalid A.I. move switch: '%s'", filename, value);
4681 	}
4682 }
lcmHandleCommandAiattack(ArgList * arglist,s_model * newchar,int * aiattackset,char * filename)4683 void lcmHandleCommandAiattack(ArgList* arglist, s_model* newchar, int* aiattackset, char* filename) {
4684 	char* value = GET_ARGP(1);
4685 	if(!*aiattackset)
4686 	{
4687 		newchar->aiattack = 0;
4688 		*aiattackset = 1;
4689 	}
4690 
4691 	//main A.I. move switches
4692 	if(value && value[0])
4693 	{
4694 		if(stricmp(value, "normal")==0){
4695 			newchar->aiattack |= AIATTACK1_NORMAL;
4696 		}
4697 		else if(stricmp(value, "always")==0){
4698 			newchar->aiattack |= AIATTACK1_ALWAYS;
4699 		}
4700 		else if(stricmp(value, "noattack")==0){
4701 			newchar->aiattack |= AIATTACK1_NOATTACK;
4702 		}
4703 		else printf("Model '%s' has invalid A.I. attack switch: '%s'\n", filename, value);
4704 	}
4705 	/*
4706 	value = GET_ARGP(2);
4707 	//sub A.I. move switches
4708 	if(value && value[0])
4709 	{
4710 
4711 	}*/
4712 }
4713 
lcmHandleCommandWeapons(ArgList * arglist,s_model * newchar)4714 void lcmHandleCommandWeapons(ArgList* arglist, s_model* newchar) {
4715 	int weap;
4716 	char* value;
4717 	for(weap = 0; ; weap++){
4718 		value = GET_ARGP(weap+1);
4719 		if(!value[0]) break;
4720 	}
4721 
4722 	if(!weap) return;
4723 
4724 	newchar->numweapons = weap;
4725 
4726 	if(!newchar->weapon)
4727 	{
4728 		newchar->weapon = malloc(sizeof(*newchar->weapon)*newchar->numweapons);
4729 		memset(newchar->weapon, 0xFF, sizeof(*newchar->weapon)*newchar->numweapons);
4730 		newchar->ownweapons = 1;
4731 	}
4732 	for(weap = 0; weap<newchar->numweapons ; weap++){
4733 		value = GET_ARGP(weap+1);
4734 		if(stricmp(value, "none")!=0){
4735 			newchar->weapon[weap] = get_cached_model_index(value);
4736 		} else { // make empty weapon slots  2007-2-16
4737 			newchar->weapon[weap] = -1;
4738 		}
4739 	}
4740 }
lcmHandleCommandScripts(ArgList * arglist,Script * script,char * scriptname,char * filename)4741 void lcmHandleCommandScripts(ArgList* arglist, Script* script, char* scriptname, char* filename) {
4742 	Script_Init(script, scriptname, filename, 0);
4743 	if(load_script(script, GET_ARGP(1)))
4744 		Script_Compile(script);
4745 	else shutdown(1, "Unable to load %s '%s' in file '%s'.\n", scriptname, GET_ARGP(1), filename);
4746 }
4747 
4748 //alloc a new model, and everything thats required,
4749 //set all values to defaults
init_model(int cacheindex,int unload)4750 s_model* init_model(int cacheindex, int unload) {
4751 	//to free: newchar, newchar->offense_factors, newchar->special, newchar->animation - OK
4752 	int i;
4753 
4754 	s_model* newchar = calloc(1, sizeof(s_model));
4755 	if(!newchar) shutdown(1, (char*)E_OUT_OF_MEMORY);
4756 	newchar->name = model_cache[cacheindex].name; // well give it a name for sort method
4757 	newchar->index = cacheindex;
4758 	newchar->isSubclassed = 0;
4759 	newchar->freetypes = MF_ALL;
4760 
4761 	newchar->defense		        = (s_defense*)calloc(max_attack_types + 1, sizeof(s_defense));
4762 	newchar->offense_factors        = (float*)calloc(max_attack_types + 1, sizeof(float));
4763 
4764 	newchar->special                = (s_com*)calloc(1, sizeof(s_com));
4765 
4766 	alloc_all_scripts(&newchar->scripts);
4767 
4768 	newchar->unload             = unload;
4769 	newchar->jumpspeed          = default_model_jumpspeed;
4770 	newchar->jumpheight         = default_model_jumpheight; // 28-12-2004   Set default jump height to 4, if not specified
4771 	newchar->runjumpheight      = default_model_jumpheight; // Default jump height if a player is running
4772 	newchar->runjumpdist        = 1; // Default jump distane if a player is running
4773 	newchar->grabdistance       = default_model_grabdistance; //  30-12-2004 Default grabdistance is same as originally set
4774 	newchar->grabflip		    = 3;
4775 	newchar->throwdamage        = 21; // default throw damage
4776 	newchar->icon.def			= -1;
4777 	newchar->icon.die           = -1;
4778 	newchar->icon.pain          = -1;
4779 	newchar->icon.get           = -1;
4780 	newchar->icon.weapon		= -1;			    // No weapon icon set yet
4781 	newchar->diesound           = -1;
4782 	newchar->nolife             = 0;			    // default show life = 1 (yes)
4783 	newchar->remove             = 1;			    // Flag set to weapons are removed upon hitting an opponent
4784 	newchar->throwdist          = default_model_jumpheight*0.625f;
4785 	newchar->counter            = 3;			    // Default 3 times to drop a weapon / projectile
4786 	newchar->aimove             = -1;
4787 	newchar->aiattack           = -1;
4788 	newchar->throwframewait     = -1;               // makes sure throw animations run normally unless throwfram is specified, added by kbandressen 10/20/06
4789 	newchar->path               = model_cache[cacheindex].path;         // Record path, so script can get it without looping the whole model collection.
4790 	newchar->icon.mphigh        = -1;               //No mphigh icon yet.
4791     newchar->icon.mplow         = -1;               //No mplow icon yet.
4792     newchar->icon.mpmed         = -1;               //No mpmed icon yet.
4793 
4794 		// Default Attack1 in chain must be referenced if not used.
4795 	for(i=0; i<MAX_ATCHAIN; i++) newchar->atchain[i] = 1;
4796 	newchar->chainlength = 1;
4797 
4798 	if(magic_type == 1) newchar->mprate = 1;
4799 	else newchar->mprate                = 2;
4800 	newchar->chargerate = newchar->guardrate = 2;
4801 	newchar->risetime[0]                = -1;
4802 	newchar->sleepwait                  = 1000;
4803 	newchar->jugglepoints.current = newchar->jugglepoints.maximum = 0;
4804 	newchar->guardpoints.current = newchar->guardpoints.maximum = 0;
4805 	newchar->mpswitch                   = -1;       // switch between reduce mp or gain mp for mpstabletype 4
4806 	newchar->weaploss[0]                = -1;
4807 	newchar->weaploss[1]                = -1;
4808 	newchar->lifespan                   = (float)0xFFFFFFFF;
4809 	newchar->summonkill                 = 1;
4810 	newchar->candamage                  = -1;
4811 	newchar->hostile                    = -1;
4812 	newchar->projectilehit              = -1;
4813 	newchar->subject_to_wall            = -1;
4814 	newchar->subject_to_platform        = -1;
4815 	newchar->subject_to_obstacle        = -1;
4816 	newchar->subject_to_hole            = -1;
4817 	newchar->subject_to_gravity         = -1;
4818 	newchar->subject_to_screen          = -1;
4819 	newchar->subject_to_minz            = -1;
4820 	newchar->subject_to_maxz            = -1;
4821 	newchar->no_adjust_base             = -1;
4822 	newchar->pshotno                    = -1;
4823 	newchar->project                    = -1;
4824 	newchar->dust[0]                    = -1;
4825 	newchar->dust[1]                    = -1;
4826 	newchar->dust[2]                    = -1;
4827 	newchar->bomb                       = -1;
4828 	newchar->star                       = -1;
4829 	newchar->knife                      = -1;
4830     newchar->stealth.hide               = 0;
4831     newchar->stealth.detect             = 0;
4832 	newchar->attackthrottle				= 0.0f;
4833 	newchar->attackthrottletime			= noatk_duration*GAME_SPEED;
4834 
4835 	newchar->animation = (s_anim**)calloc(max_animations, sizeof(s_anim*));
4836 	if(!newchar->animation) shutdown(1, (char*)E_OUT_OF_MEMORY);
4837 
4838 	// default string value, only by reference
4839 	newchar->rider = get_cached_model_index("K'");
4840 	newchar->flash = newchar->bflash = get_cached_model_index("flash");
4841 
4842 	//Default offense/defense values.
4843 	for(i=0;i<max_attack_types;i++)
4844 	{
4845 		newchar->offense_factors[i]     = 1;
4846 		newchar->defense[i]				= default_defense;
4847 	}
4848 
4849 	//Default sight ranges.
4850     newchar->sight.amin = -9999;
4851     newchar->sight.amax = 9999;
4852     newchar->sight.xmin = -9999;
4853     newchar->sight.xmax = 9999;
4854     newchar->sight.zmin = -9999;
4855     newchar->sight.zmax = 9999;
4856 
4857 	return newchar;
4858 }
4859 
update_model_loadflag(s_model * model,char unload)4860 void update_model_loadflag(s_model* model, char unload) {
4861 	model->unload = unload;
4862 }
4863 
load_cached_model(char * name,char * owner,char unload)4864 s_model* load_cached_model(char * name, char * owner, char unload)
4865 {
4866 	s_model *newchar = NULL,
4867 	*tempmodel = NULL;
4868 
4869 	s_anim *newanim = NULL;
4870 
4871 	char *filename = NULL,
4872 	*buf = NULL,
4873 	*scriptbuf = NULL,
4874 	*command = NULL,
4875 	*value = NULL,
4876 	*value2 = NULL,
4877 	*value3 = NULL;
4878 
4879 	char fnbuf[128] = {""},
4880 		namebuf[256] = {""},
4881 		argbuf[MAX_ARG_LEN+1] = "";
4882 
4883 	ArgList arglist;
4884 
4885 	float tempFloat;
4886 
4887 	int ani_id = -1,
4888 		script_id = -1,
4889 		i = 0,
4890 		j = 0,
4891 		tempInt = 0,
4892 		framecount = 0,
4893 		frameset = 0,
4894 		peek = 0,
4895 		cacheindex = 0,
4896 		curframe = 0,
4897 		delay = 0,
4898 		errorVal = 0,
4899 		shadow_set = 0,
4900 		idle = 0,
4901 		move = 0,
4902 		movez = 0,
4903 		movea = 0,
4904 		seta = -1,			// Used for setting custom "a". Set to -1 to distinguish between disabled and setting "a" to 0
4905 		frameshadow = -1,	// -1 will use default shadow for this entity, otherwise will use this value
4906 		soundtoplay = -1,
4907 		aimoveset = 0,
4908 		aiattackset = 0,
4909 		maskindex = -1,
4910 		nopalette = 0;
4911 
4912 	size_t size = 0,
4913 		line = 0,
4914 		len = 0,
4915 		sbsize=0,
4916 		scriptlen=0;
4917 
4918 	ptrdiff_t pos = 0,
4919 		index = 0;
4920 
4921 	short bbox[5] = { 0,0,0,0,0 },
4922 		bbox_con[5] = { 0,0,0,0,0 },
4923 		abox[5] = { 0,0,0,0,0 },
4924 		offset[2] = { 0,0 },
4925 		shadow_xz[2] = {0,0},
4926 		shadow_coords[2] = {0,0};
4927 
4928 	float platform[8] = { 0,0,0,0,0,0,0,0 },
4929 		platform_con[8] = { 0,0,0,0,0,0,0,0 };
4930 
4931 	s_attack attack,
4932 	*pattack = NULL;
4933 	s_defense defense;
4934 	char* shutdownmessage = NULL;
4935 
4936 	s_drawmethod drawmethod;
4937 
4938 	unsigned char mapflag[MAX_COLOUR_MAPS]; // in 24bit mode, we need to know whether a colourmap is a common map or a palette
4939 
4940 	static const char* pre_text =  // this is the skeleton of frame function
4941 		"void main()\n"
4942 		"{\n"
4943 		"    int frame = getlocalvar(\"frame\");\n"
4944 		"    int animhandle = getlocalvar(\"animhandle\");\n"
4945 		"\n}\n";
4946 
4947 	static const char* sur_text = // end of function text
4948 		"\n}\n";
4949 
4950 	static const char* ifid_text = // if expression to check animation id
4951 		"    if(animhandle==%ld)\n"
4952 		"    {\n"
4953 		"        return;\n"
4954 		"    }\n";
4955 
4956 	static const char* endifid_text = // end of if
4957 		"        return;\n"
4958 		"    }\n";
4959 
4960 	static const char* if_text = // this is the if expression of frame function
4961 		"        if(frame==%d)\n"
4962 		"        {\n";
4963 
4964 	static const char* endif_text = // end of if
4965 		"\n"
4966 		"        }\n" ;
4967 
4968 	static const char* comma_text = // arguments separator
4969 		", ";
4970 
4971 	static const char* call_text = //begin of function call
4972 		"            %s(";
4973 
4974 	static const char* endcall_text = //end of function call
4975 		");\n";
4976 
4977 	modelCommands cmd;
4978 	s_scripts* tempscripts;
4979 
4980 #ifdef DEBUG
4981 	printf("load_cached_model: %s, unload: %d\n", name, unload);
4982 #endif
4983 
4984 	// Model already loaded but we might want to unload after level is completed.
4985 	if((tempmodel=findmodel(name))!=NULL) {
4986 		update_model_loadflag(tempmodel,unload);
4987 		cache_model_sprites(tempmodel, 1);
4988 		return tempmodel;
4989 	}
4990 
4991 	cacheindex = get_cached_model_index(name);
4992 	if(cacheindex < 0) shutdown(1, "Fatal: No cache entry for '%s' within '%s'\n\n", name, owner);
4993 
4994 	filename = model_cache[cacheindex].path;
4995 
4996 	if(buffer_pakfile(filename, &buf, &size)!=1) shutdown(1, "Unable to open file '%s'\n\n", filename);
4997 
4998 	sbsize = size+1;
4999 	scriptbuf = (char*)malloc(sbsize);
5000 
5001 	if(scriptbuf==NULL){
5002 		shutdown(1, "Unable to create script buffer for file '%s' (%i bytes)", filename, size*2);
5003 	}
5004 	scriptbuf[0] = 0;
5005 
5006 	//_peek_model_name(cacheindex);
5007 	newchar = init_model(cacheindex, unload);
5008 	//newchar->name = name;
5009 
5010 	//attention, we increase models_loaded here, this can be dangerous if we access that value later on,
5011 	//since recursive calls will change it!
5012 	models_loaded++;
5013 	addModel(newchar);
5014 
5015 	attack = emptyattack;      // empty attack
5016 	drawmethod = plainmethod;  // better than memset it to 0
5017 	memset(mapflag, 0, MAX_COLOUR_MAPS);
5018 
5019 
5020 	//char* test = "load   knife 0";
5021 	//ParseArgs(&arglist,test,argbuf);
5022 
5023 	// Now interpret the contents of buf line by line
5024 	while(pos<size)
5025 	{
5026 		//command = GET_ARG(0);
5027 		line++;
5028 		if(ParseArgs(&arglist,buf+pos,argbuf)){
5029 			command = GET_ARG(0);
5030 			cmd = getModelCommand(modelcmdlist, command);
5031 
5032 			switch(cmd) {
5033 				case CMD_MODEL_SUBCLASS:
5034 					//inherit everything from an existing, cached model
5035 					tempmodel = findmodel(GET_ARG(1));
5036 					if (!tempmodel) {
5037 						shutdownmessage = "tried to subclass a non-existing/not previously loaded model!";
5038 						goto lCleanup;
5039 					}
5040 					tempscripts = newchar->scripts;
5041 					*newchar = *tempmodel;
5042 					newchar->scripts = tempscripts;
5043 					copy_all_scripts(tempmodel->scripts, newchar->scripts, 1);
5044 					newchar->isSubclassed = 1;
5045 					newchar->freetypes = MF_SCRIPTS;
5046 					break;
5047 				case CMD_MODEL_NAME:
5048 					lcmHandleCommandName(&arglist, newchar, cacheindex);
5049 					break;
5050 				case CMD_MODEL_TYPE:
5051 					lcmHandleCommandType(&arglist, newchar, filename);
5052 					break;
5053 				case CMD_MODEL_SUBTYPE:
5054 					lcmHandleCommandSubtype(&arglist, newchar, filename);
5055 					break;
5056 				case CMD_MODEL_STATS:
5057 					value = GET_ARG(1);
5058 					newchar->stats[atoi(value)] = GET_FLOAT_ARG(2);
5059 					break;
5060 				case CMD_MODEL_HEALTH:
5061 					value = GET_ARG(1);
5062 					newchar->health = atoi(value);
5063 					break;
5064 				case CMD_MODEL_SCROLL:
5065 					value = GET_ARG(1);
5066 					newchar->scroll = atof(value);
5067 					break;
5068 				case CMD_MODEL_MP: //Left for backward compatability. See mpset. // mp values to put max mp for player by tails
5069 					value = GET_ARG(1);
5070 					newchar->mp = atoi(value);
5071 					break;
5072 				case CMD_MODEL_NOLIFE:	// Feb 25, 2005 - Flag to display enemy life or not
5073 					newchar->nolife = GET_INT_ARG(1);
5074 					break;
5075 				case CMD_MODEL_MAKEINV:	// Mar 12, 2005 - If a value is supplied, corresponds to amount of time the player spawns invincible
5076 					newchar->makeinv = GET_INT_ARG(1) * GAME_SPEED;
5077 					if(GET_INT_ARG(2)) newchar->makeinv = -newchar->makeinv;
5078 					break;
5079 				case CMD_MODEL_RISEINV:
5080 					newchar->riseinv = GET_FLOAT_ARG(1) * GAME_SPEED;
5081 					if(GET_INT_ARG(2)) newchar->riseinv = -newchar->riseinv;
5082 					break;
5083 				case CMD_MODEL_LOAD:
5084 					value = GET_ARG(1);
5085 					tempmodel = findmodel(value);
5086 					if(!tempmodel)
5087 						load_cached_model(value, name, GET_INT_ARG(2));
5088 					else
5089 						update_model_loadflag(tempmodel, GET_INT_ARG(2));
5090 					break;
5091 				case CMD_MODEL_SCORE:
5092 					newchar->score = GET_INT_ARG(1);
5093 					newchar->multiple = GET_INT_ARG(2);			// New var multiple for force/scoring
5094 					break;
5095 				case CMD_MODEL_SMARTBOMB:
5096 					lcmHandleCommandSmartbomb(&arglist, newchar, filename);
5097 					break;
5098 				case CMD_MODEL_BOUNCE:
5099 					newchar->bounce = GET_INT_ARG(1);
5100 					break;
5101 				case CMD_MODEL_NOQUAKE:  // Mar 12, 2005 - Flag to determine if entity shakes screen
5102 					newchar->noquake = GET_INT_ARG(1);
5103 					break;
5104 				case CMD_MODEL_BLOCKBACK:	// Flag to determine if attacks can be blocked from behind
5105 					newchar->blockback = GET_INT_ARG(1);
5106 					break;
5107 				case CMD_MODEL_HITENEMY:	// Flag to determine if an enemy projectile will hit enemies
5108 					value = GET_ARG(1);
5109 					if(atoi(value) == 1)
5110 						newchar->candamage = newchar->hostile = TYPE_PLAYER | TYPE_ENEMY;
5111 					else if(atoi(value) == 2)
5112 						newchar->candamage = newchar->hostile = TYPE_PLAYER;
5113 					newchar->ground = GET_INT_ARG(2);    // Added to determine if enemies are damaged with mid air projectiles or ground only
5114 					break;
5115 				case CMD_MODEL_HOSTILE:
5116 					lcmHandleCommandHostile(&arglist, newchar);
5117 					break;
5118 				case CMD_MODEL_CANDAMAGE:
5119 					lcmHandleCommandCandamage(&arglist, newchar);
5120 					break;
5121 				case CMD_MODEL_PROJECTILEHIT:
5122 					lcmHandleCommandProjectilehit(&arglist, newchar);
5123 					break;
5124 				case CMD_MODEL_AIMOVE:
5125 					lcmHandleCommandAimove(&arglist, newchar, &aimoveset, filename);
5126 					break;
5127 				case CMD_MODEL_AIATTACK:
5128 					lcmHandleCommandAiattack(&arglist, newchar, &aiattackset, filename);
5129 					break;
5130 				case CMD_MODEL_SUBJECT_TO_WALL:
5131 					newchar->subject_to_wall = (0!=GET_INT_ARG(1));
5132 					break;
5133 				case CMD_MODEL_SUBJECT_TO_HOLE:
5134 					newchar->subject_to_hole = (0!=GET_INT_ARG(1));
5135 					break;
5136 				case CMD_MODEL_SUBJECT_TO_PLATFORM:
5137 					newchar->subject_to_platform = (0!=GET_INT_ARG(1));
5138 					break;
5139 				case CMD_MODEL_SUBJECT_TO_OBSTACLE:
5140 					newchar->subject_to_obstacle = (0!=GET_INT_ARG(1));
5141 					break;
5142 				case CMD_MODEL_SUBJECT_TO_GRAVITY:
5143 					newchar->subject_to_gravity = (0!=GET_INT_ARG(1));
5144 					break;
5145 				case CMD_MODEL_SUBJECT_TO_SCREEN:
5146 					newchar->subject_to_screen = (0!=GET_INT_ARG(1));
5147 					break;
5148 				case CMD_MODEL_SUBJECT_TO_MINZ:
5149 					newchar->subject_to_minz = (0!=GET_INT_ARG(1));
5150 					break;
5151 				case CMD_MODEL_SUBJECT_TO_MAXZ:
5152 					newchar->subject_to_maxz = (0!=GET_INT_ARG(1));
5153 					break;
5154 				case CMD_MODEL_NO_ADJUST_BASE:
5155 					newchar->no_adjust_base = (0!=GET_INT_ARG(1));
5156 					break;
5157 				case CMD_MODEL_INSTANTITEMDEATH:
5158 					newchar->instantitemdeath = GET_INT_ARG(1);
5159 					break;
5160 				case CMD_MODEL_SECRET:
5161 					newchar->secret = GET_INT_ARG(1);
5162 					newchar->clearcount = GET_INT_ARG(2);
5163 					break;
5164 				case CMD_MODEL_MODELFLAG: //model copy flag
5165 					newchar->model_flag = GET_INT_ARG(1);
5166 					break;
5167 				// weapons
5168 				case CMD_MODEL_WEAPLOSS:
5169 					newchar->weaploss[0] = GET_INT_ARG(1);
5170 					newchar->weaploss[1] = GET_INT_ARG(2);
5171 					break;
5172 				case CMD_MODEL_WEAPNUM:
5173 					newchar->weapnum = GET_INT_ARG(1);
5174 					break;
5175 				case CMD_MODEL_PROJECT: // New projectile subtype
5176 					value = GET_ARG(1);
5177 					if(stricmp(value, "none")==0) newchar->project = -1;
5178 					else newchar->project = get_cached_model_index(value);
5179 					break;
5180 				case CMD_MODEL_WEAPONS:
5181 					lcmHandleCommandWeapons(&arglist, newchar);
5182 					break;
5183 				case CMD_MODEL_SHOOTNUM: //here weapons things like shoot rest type of weapon ect..by tails
5184 					newchar->shootnum = GET_INT_ARG(1);
5185 					break;
5186 				case CMD_MODEL_RELOAD:
5187 					newchar->reload = GET_INT_ARG(1);
5188 					break;
5189 				case CMD_MODEL_TYPESHOT:
5190 					newchar->typeshot = GET_INT_ARG(1);
5191 					break;
5192 				case CMD_MODEL_COUNTER:
5193 					newchar->counter = GET_INT_ARG(1);
5194 					break;
5195 				case CMD_MODEL_ANIMAL:
5196 					newchar->animal = GET_INT_ARG(1);
5197 					break;
5198 				case CMD_MODEL_RIDER:
5199 					value = GET_ARG(1);
5200 					if(stricmp(value, "none")==0) newchar->rider = -1;
5201 					else newchar->rider = get_cached_model_index(value);
5202 					break;
5203 				case CMD_MODEL_KNIFE: case CMD_MODEL_FIREB: case CMD_MODEL_PLAYSHOT: case CMD_MODEL_PLAYSHOTW:
5204 					value = GET_ARG(1);
5205 					if(stricmp(value, "none")==0) newchar->knife = -1;
5206 					else  newchar->knife = get_cached_model_index(value);
5207 					break;
5208 				case CMD_MODEL_PLAYSHOTNO:
5209 					value = GET_ARG(1);
5210 					if(stricmp(value, "none")==0) newchar->pshotno = -1;
5211 					else newchar->pshotno = get_cached_model_index(value);
5212 					break;
5213 				case CMD_MODEL_STAR:
5214 					value = GET_ARG(1);
5215 					if(stricmp(value, "none")==0) newchar->star = -1;
5216 					else newchar->star = get_cached_model_index(value);
5217 					break;
5218 				case CMD_MODEL_BOMB: case CMD_MODEL_PLAYBOMB:
5219 					value = GET_ARG(1);
5220 					if(stricmp(value, "none")==0) newchar->bomb = -1;
5221 					else newchar->bomb = get_cached_model_index(value);
5222 					break;
5223 				case CMD_MODEL_FLASH:	 // Now all characters can have their own flash - even projectiles (useful for blood)
5224 					value = GET_ARG(1);
5225 					if(stricmp(value, "none")==0) newchar->flash = -1;
5226 					else newchar->flash = get_cached_model_index(value);
5227 					break;
5228 				case CMD_MODEL_BFLASH:	// Flash that is spawned if an attack is blocked
5229 					value = GET_ARG(1);
5230 					if(stricmp(value, "none")==0) newchar->bflash = -1;
5231 					else newchar->bflash = get_cached_model_index(value);
5232 					break;
5233 				case CMD_MODEL_DUST:	// Spawned when hitting the ground to "kick up dust"
5234 					value = GET_ARG(1);
5235 					if(stricmp(value, "none")==0) newchar->dust[0] = -1;
5236 					else newchar->dust[0] = get_cached_model_index(value);
5237 					value = GET_ARG(2);
5238 					if(stricmp(value, "none")==0) newchar->dust[1] = -1;
5239 					else newchar->dust[1] = get_cached_model_index(value);
5240 					value = GET_ARG(3);
5241 					if(stricmp(value, "none")==0) newchar->dust[2] = -1;
5242 					else newchar->dust[2] = get_cached_model_index(value);
5243 					break;
5244 				case CMD_MODEL_BRANCH: // for endlevel item's level branch
5245 					value = GET_ARG(1);
5246 					if(!newchar->branch)
5247 					{
5248 						newchar->branch = malloc(MAX_NAME_LEN+1);
5249 						newchar->branch[0] = 0;
5250 					}
5251 					strncpy(newchar->branch, value, MAX_NAME_LEN);
5252 					break;
5253 				case CMD_MODEL_CANTGRAB: case CMD_MODEL_NOTGRAB:
5254 					tempInt = GET_INT_ARG(1);
5255 					if(tempInt == 2) newchar->grabforce = -999999;
5256 					else             newchar->antigrab = 1;
5257 					break;
5258 				case CMD_MODEL_ANTIGRAB: // a can grab b: a->antigrab - b->grabforce <=0
5259 					newchar->antigrab = GET_INT_ARG(1);
5260 					break;
5261 				case CMD_MODEL_GRABFORCE:
5262 					newchar->grabforce = GET_INT_ARG(1);
5263 					break;
5264 				case CMD_MODEL_GRABBACK:
5265 					newchar->grabback = GET_INT_ARG(1);
5266 					break;
5267 				case CMD_MODEL_OFFSCREENKILL:
5268 					newchar->offscreenkill = GET_INT_ARG(1);
5269 					break;
5270 				case CMD_MODEL_FALLDIE: case CMD_MODEL_DEATH:
5271 					newchar->falldie = GET_INT_ARG(1);
5272 					break;
5273 				case CMD_MODEL_SPEED:
5274 					value = GET_ARG(1);
5275 					newchar->speed = atof(value);
5276 					newchar->speed /= 10;
5277 					if(newchar->speed < 0.5) newchar->speed = 0.5;
5278 					if(newchar->speed > 30) newchar->speed = 30;
5279 					break;
5280 				case CMD_MODEL_SPEEDF:
5281 					value = GET_ARG(1);
5282 					newchar->speed = atof(value);
5283 					break;
5284 				case CMD_MODEL_JUMPSPEED:
5285 					value = GET_ARG(1);
5286 					newchar->jumpspeed = atof(value);
5287 					newchar->jumpspeed /= 10;
5288 					break;
5289 				case CMD_MODEL_JUMPSPEEDF:
5290 					value = GET_ARG(1);
5291 					newchar->jumpspeed = atof(value);
5292 					break;
5293 				case CMD_MODEL_ANTIGRAVITY:
5294 					value = GET_ARG(1);
5295 					newchar->antigravity = atof(value);
5296 					newchar->antigravity /= 100;
5297 					break;
5298 				case CMD_MODEL_STEALTH:
5299 					newchar->stealth.hide = GET_INT_ARG(1);
5300 					newchar->stealth.detect = GET_INT_ARG(2);
5301 					break;
5302 				case CMD_MODEL_JUGGLEPOINTS:
5303 					value = GET_ARG(1);
5304 					newchar->jugglepoints.current = atoi(value);
5305 					newchar->jugglepoints.maximum = atoi(value);
5306 					break;
5307 				case CMD_MODEL_RISEATTACKTYPE:
5308 					value = GET_ARG(1);
5309 					newchar->riseattacktype = atoi(value);
5310 					break;
5311 				case CMD_MODEL_GUARDPOINTS:
5312 					value = GET_ARG(1);
5313 					newchar->guardpoints.current = atoi(value);
5314 					newchar->guardpoints.maximum = atoi(value);
5315 					break;
5316 				case CMD_MODEL_DEFENSE:
5317 					#define tempdef(x, y) \
5318 					x(stricmp(value, #y)==0)\
5319 					{\
5320 						newchar->defense[ATK_##y] = defense;\
5321 					}
5322 					{
5323 						value = GET_ARG(1);
5324 						defense = default_defense;
5325 						if(newchar->subtype==SUBTYPE_BIKER) defense.factor=2.f;
5326 
5327 						if(arglist.count>=2) defense.factor = GET_FLOAT_ARG(2);
5328 						if(arglist.count>=3) defense.pain = GET_FLOAT_ARG(3);
5329 						if(arglist.count>=4) defense.knockdown = GET_FLOAT_ARG(4);
5330 						if(arglist.count>=5) defense.blockpower = GET_FLOAT_ARG(5);
5331 						if(arglist.count>=6) defense.blockthreshold = GET_FLOAT_ARG(6);
5332 						if(arglist.count>=7) defense.blockratio = GET_FLOAT_ARG(7);
5333 						if(arglist.count>=8) defense.blocktype = GET_FLOAT_ARG(8);
5334 
5335 						tempdef(if, NORMAL)
5336 						tempdef(else if, NORMAL2)
5337 						tempdef(else if, NORMAL3)
5338 						tempdef(else if, NORMAL4)
5339 						tempdef(else if, NORMAL5)
5340 						tempdef(else if, NORMAL6)
5341 						tempdef(else if, NORMAL7)
5342 						tempdef(else if, NORMAL8)
5343 						tempdef(else if, NORMAL9)
5344 						tempdef(else if, NORMAL10)
5345 						tempdef(else if, BLAST)
5346 						tempdef(else if, STEAL)
5347 						tempdef(else if, BURN)
5348 						tempdef(else if, SHOCK)
5349 						tempdef(else if, FREEZE)
5350 						else if(strnicmp(value, "normal", 6)==0)
5351 						{
5352 							tempInt = atoi(value+6);
5353 							if(tempInt<11) tempInt = 11;
5354 							newchar->defense[tempInt+STA_ATKS-1] = defense;
5355 						}
5356 						else if(stricmp(value, "ALL")==0)
5357 						{
5358 							for(i=0;i<max_attack_types;i++) newchar->defense[i] = defense;
5359 						}
5360 					}
5361 					#undef tempdef
5362 					break;
5363 				case CMD_MODEL_OFFENSE:
5364 					#define tempoff(x, y, z) \
5365 					x(stricmp(value, #y)==0)\
5366 					{\
5367 					newchar->z[ATK_##y] = GET_FLOAT_ARG(2);\
5368 					/*newchar->z[ATK_##y] /= 100;*/\
5369 					}
5370 					{
5371 						value = GET_ARG(1);
5372 						tempoff(if,         NORMAL,     offense_factors)
5373 						tempoff(else if,    NORMAL2,    offense_factors)
5374 						tempoff(else if,    NORMAL3,    offense_factors)
5375 						tempoff(else if,    NORMAL4,    offense_factors)
5376 						tempoff(else if,    NORMAL5,    offense_factors)
5377 						tempoff(else if,    NORMAL6,    offense_factors)
5378 						tempoff(else if,    NORMAL7,    offense_factors)
5379 						tempoff(else if,    NORMAL8,    offense_factors)
5380 						tempoff(else if,    NORMAL9,    offense_factors)
5381 						tempoff(else if,    NORMAL10,   offense_factors)
5382 						tempoff(else if,    BLAST,      offense_factors)
5383 						tempoff(else if,    STEAL,      offense_factors)
5384 						tempoff(else if,    BURN,       offense_factors)
5385 						tempoff(else if,    SHOCK,      offense_factors)
5386 						tempoff(else if,    FREEZE,     offense_factors)
5387 						else if(strnicmp(value, "normal", 6)==0)
5388 						{
5389 							tempInt = atoi(value+6);
5390 							if(tempInt<11) tempInt = 11;
5391 							newchar->offense_factors[tempInt+STA_ATKS-1] = GET_FLOAT_ARG(2);
5392 						}
5393 						else if(stricmp(value, "ALL")==0)
5394 						{
5395 							tempFloat = GET_FLOAT_ARG(2);
5396 							for(i=0;i<max_attack_types;i++)
5397 							{
5398 								newchar->offense_factors[i] = tempFloat;
5399 							}
5400 						}
5401 					}
5402 					#undef tempoff
5403 					break;
5404 				case CMD_MODEL_HEIGHT:
5405 					newchar->height = GET_INT_ARG(1);
5406 					break;
5407 				case CMD_MODEL_JUMPHEIGHT:
5408 					newchar->jumpheight = GET_FLOAT_ARG(1);
5409 					break;
5410 				case CMD_MODEL_JUMPMOVE:
5411 					newchar->jumpmovex = GET_INT_ARG(1);
5412 					newchar->jumpmovez = GET_INT_ARG(2);
5413 					break;
5414 				case CMD_MODEL_KNOCKDOWNCOUNT:
5415 					newchar->knockdowncount = GET_FLOAT_ARG(1);
5416 					break;
5417 				case CMD_MODEL_GRABDISTANCE:
5418 					newchar->grabdistance = GET_FLOAT_ARG(1);                    // 30-12-2004 and store for character
5419 					break;
5420 				case CMD_MODEL_GRABFLIP:
5421 					newchar->grabflip = GET_INT_ARG(1);
5422 					break;
5423 				case CMD_MODEL_GRABFINISH:
5424 					newchar->grabfinish = GET_INT_ARG(1);
5425 					break;
5426 				case CMD_MODEL_THROWDAMAGE:
5427 					newchar->throwdamage = GET_INT_ARG(1);
5428 					break;
5429 				case CMD_MODEL_SHADOW:
5430 					newchar->shadow = GET_INT_ARG(1);
5431 					break;
5432 				case CMD_MODEL_GFXSHADOW:
5433 					newchar->gfxshadow = GET_INT_ARG(1);
5434 					break;
5435 				case CMD_MODEL_AIRONLY:	// Shadows display in air only?
5436 					newchar->aironly = GET_INT_ARG(1);
5437 					break;
5438 				case CMD_MODEL_FMAP:	// Map that corresponds with the remap when a character is frozen
5439 					newchar->maps.frozen = GET_INT_ARG(1);
5440 					break;
5441 				case CMD_MODEL_KOMAP:	// Remap when character is KO'd.
5442 					newchar->maps.ko = GET_INT_ARG(1);  //Remap.
5443 					newchar->maps.kotype = GET_INT_ARG(2);  //Type: 0 start of fall/death, 1 last frame.
5444 					break;
5445 				case CMD_MODEL_HMAP:	// Maps range unavailable to player in select screen.
5446 					newchar->maps.hide_start = GET_INT_ARG(1); //First unavailable map.
5447 					newchar->maps.hide_end = GET_INT_ARG(2); //Last unavailable map.
5448 					break;
5449 				case CMD_MODEL_SETLAYER:
5450 					newchar->setlayer = GET_INT_ARG(1);
5451 					break;
5452 				case CMD_MODEL_TOFLIP:	  // Flag to determine if flashes images will be flipped or not
5453 					newchar->toflip = GET_INT_ARG(1);
5454 					break;
5455 				case CMD_MODEL_NODIEBLINK:
5456 					// Added to determine if dying animation blinks or not
5457 					newchar->nodieblink = GET_INT_ARG(1);
5458 					break;
5459 				case CMD_MODEL_NOATFLASH:	 // Flag to determine if an opponents attack spawns their flash or not
5460 					newchar->noatflash = GET_INT_ARG(1);
5461 					break;
5462 				case CMD_MODEL_NOMOVE:
5463 					// If set, will be static (speed must be set to 0 or left blank)
5464 					newchar->nomove = GET_INT_ARG(1);
5465 					newchar->noflip = GET_INT_ARG(2);    // If set, static will not flip directions
5466 					if(newchar->nomove) newchar->nodrop = 1;
5467 					break;
5468 				case CMD_MODEL_NODROP:
5469 					newchar->nodrop = GET_INT_ARG(1);
5470 					break;
5471 				case CMD_MODEL_THOLD:
5472 					// Threshold for enemies/players block
5473 					newchar->thold = GET_INT_ARG(1);
5474 					break;
5475 				case CMD_MODEL_RUNNING:
5476 					// The speed at which the player runs
5477 					newchar->runspeed = GET_FLOAT_ARG(1);
5478 					newchar->runspeed /= 10;
5479 					newchar->runjumpheight = GET_FLOAT_ARG(2);    // The height at which a player jumps when running
5480 					newchar->runjumpdist = GET_FLOAT_ARG(3);    // The distance a player jumps when running
5481 					newchar->runupdown = GET_INT_ARG(4);
5482 					newchar->runhold = GET_INT_ARG(5);
5483 					break;
5484 				case CMD_MODEL_BLOCKODDS:
5485 					// Odds that an attack will hit an enemy (1 : blockodds)
5486 					newchar->blockodds = GET_INT_ARG(1);
5487 					break;
5488 				case CMD_MODEL_HOLDBLOCK:
5489 					newchar->holdblock = GET_INT_ARG(1);
5490 					break;
5491 				case CMD_MODEL_BLOCKPAIN:
5492 					newchar->blockpain = GET_INT_ARG(1);
5493 					break;
5494 				case CMD_MODEL_NOPASSIVEBLOCK:
5495 					newchar->nopassiveblock = GET_INT_ARG(1);
5496 					break;
5497 				case CMD_MODEL_EDELAY:
5498 					newchar->edelay.mode        = GET_INT_ARG(1);
5499 					newchar->edelay.factor      = GET_FLOAT_ARG(2);
5500 					newchar->edelay.cap_min     = GET_INT_ARG(3);
5501 					newchar->edelay.cap_max     = GET_INT_ARG(4);
5502 					newchar->edelay.range_min   = GET_INT_ARG(5);
5503 					newchar->edelay.range_max   = GET_INT_ARG(6);
5504 					break;
5505 				case CMD_MODEL_PAINGRAB:
5506 					newchar->paingrab = GET_INT_ARG(1);
5507 					break;
5508 				case CMD_MODEL_THROW:
5509 					newchar->throwdist = GET_FLOAT_ARG(1);
5510 					newchar->throwheight = GET_FLOAT_ARG(2);
5511 					break;
5512 				case CMD_MODEL_GRABWALK:
5513 					newchar->grabwalkspeed = GET_FLOAT_ARG(1);
5514 					newchar->grabwalkspeed /= 10;
5515 					if(newchar->grabwalkspeed < 0.5) newchar->grabwalkspeed = 0.5;
5516 					break;
5517 				case CMD_MODEL_GRABTURN:
5518 					newchar->grabturn = GET_INT_ARG(1);
5519 					break;
5520 				case CMD_MODEL_THROWFRAMEWAIT:
5521 					newchar->throwframewait = GET_INT_ARG(1);
5522 					break;
5523 				case CMD_MODEL_DIESOUND:
5524 					newchar->diesound = sound_load_sample(GET_ARG(1), packfile, 0);
5525 					break;
5526 				case CMD_MODEL_ICON:
5527 					value = GET_ARG(1);
5528 					if(newchar->icon.def > -1) {
5529 						shutdownmessage = "model has multiple icons defined";
5530 						goto lCleanup;
5531 					}
5532 					newchar->icon.def = loadsprite(value,0,0,pixelformat); //use same palette as the owner
5533 					newchar->icon.pain = newchar->icon.def;
5534 					newchar->icon.die = newchar->icon.def;
5535 					newchar->icon.get = newchar->icon.def;
5536 					break;
5537 				case CMD_MODEL_ICONPAIN:
5538 					value = GET_ARG(1);
5539 					newchar->icon.pain = loadsprite(value,0,0,pixelformat);
5540 					break;
5541 				case CMD_MODEL_ICONDIE:
5542 					value = GET_ARG(1);
5543 					newchar->icon.die = loadsprite(value,0,0,pixelformat);
5544 					break;
5545 				case CMD_MODEL_ICONGET:
5546 					value = GET_ARG(1);
5547 					newchar->icon.get = loadsprite(value,0,0,pixelformat);
5548 					break;
5549 				case CMD_MODEL_ICONW:
5550 					value = GET_ARG(1);
5551 					newchar->icon.weapon = loadsprite(value,0,0,pixelformat);
5552 					break;
5553 				case CMD_MODEL_ICONMPHIGH:
5554 					value = GET_ARG(1);
5555 					newchar->icon.mphigh = loadsprite(value,0,0,pixelformat);
5556 					break;
5557 				case CMD_MODEL_ICONMPHALF:
5558 					value = GET_ARG(1);
5559 					newchar->icon.mpmed = loadsprite(value,0,0,pixelformat);
5560 					break;
5561 				case CMD_MODEL_ICONMPLOW:
5562 					value = GET_ARG(1);
5563 					newchar->icon.mplow = loadsprite(value,0,0,pixelformat);
5564 					break;
5565 				case CMD_MODEL_PARROW:
5566 					// Image that is displayed when player 1 spawns invincible
5567 					value = GET_ARG(1);
5568 					newchar->parrow[0][0] = loadsprite(value,0,0,pixelformat);
5569 					newchar->parrow[0][1] = GET_INT_ARG(2);
5570 					newchar->parrow[0][2] = GET_INT_ARG(3);
5571 					break;
5572 				case CMD_MODEL_PARROW2:
5573 					// Image that is displayed when player 2 spawns invincible
5574 					value = GET_ARG(1);
5575 					newchar->parrow[1][0] = loadsprite(value,0,0,pixelformat);
5576 					newchar->parrow[1][1] = GET_INT_ARG(2);
5577 					newchar->parrow[1][2] = GET_INT_ARG(3);
5578 					break;
5579 				case CMD_MODEL_PARROW3:
5580 					value = GET_ARG(1);
5581 					newchar->parrow[2][0] = loadsprite(value,0,0,pixelformat);
5582 					newchar->parrow[2][1] = GET_INT_ARG(2);
5583 					newchar->parrow[2][2] = GET_INT_ARG(3);
5584 					break;
5585 				case CMD_MODEL_PARROW4:
5586 					value = GET_ARG(1);
5587 					newchar->parrow[3][0] = loadsprite(value,0,0,pixelformat);
5588 					newchar->parrow[3][1] = GET_INT_ARG(2);
5589 					newchar->parrow[3][2] = GET_INT_ARG(3);
5590 					break;
5591 				case CMD_MODEL_ATCHAIN:
5592 					newchar->chainlength = 0;
5593 					for(i = 0; i < MAX_ATCHAIN; i++)
5594 					{
5595 						newchar->atchain[i] = GET_INT_ARG(i + 1);
5596 						if(newchar->atchain[i] < 0) newchar->atchain[i] = 0;
5597 						if(newchar->atchain[i] > max_attacks) newchar->atchain[i] = max_attacks;
5598 						if(newchar->atchain[i]) newchar->chainlength = i+1;
5599 					}
5600 					break;
5601 				case CMD_MODEL_COMBOSTYLE:
5602 					newchar->combostyle = GET_INT_ARG(1);
5603 					break;
5604 				case CMD_MODEL_CREDIT:
5605 					newchar->credit = GET_INT_ARG(1);
5606 					break;
5607 				case CMD_MODEL_NOPAIN:
5608 					newchar->nopain = GET_INT_ARG(1);
5609 					break;
5610 				case CMD_MODEL_ESCAPEHITS:
5611 					// How many times an enemy can be hit before retaliating
5612 					newchar->escapehits = GET_INT_ARG(1);
5613 					break;
5614 				case CMD_MODEL_CHARGERATE:
5615 					// How much mp does this character gain while recharging?
5616 					newchar->chargerate = GET_INT_ARG(1);
5617 					break;
5618 				case CMD_MODEL_MPRATE:
5619 					newchar->mprate = GET_INT_ARG(1);
5620 					break;
5621 				case CMD_MODEL_MPSET:
5622 					// Mp bar wax/wane.
5623 					newchar->mp             = GET_INT_ARG(1); //Max MP.
5624 					newchar->mpstable       = GET_INT_ARG(2); //MP stable setting.
5625 					newchar->mpstableval    = GET_INT_ARG(3); //MP stable value (% Mp bar will try and maintain).
5626 					newchar->mprate         = GET_INT_ARG(4); //Rate MP value rises over time.
5627 					newchar->mpdroprate     = GET_INT_ARG(5); //Rate MP value drops over time.
5628 					newchar->chargerate     = GET_INT_ARG(6); //MP Chargerate.
5629 					break;
5630 				case CMD_MODEL_SLEEPWAIT:
5631 					newchar->sleepwait = GET_INT_ARG(1);
5632 					break;
5633 				case CMD_MODEL_GUARDRATE:
5634 					newchar->guardrate = GET_INT_ARG(1);
5635 					break;
5636 				case CMD_MODEL_AGGRESSION:
5637 					newchar->aggression = GET_INT_ARG(1);
5638 					break;
5639 				case CMD_MODEL_ATTACKTHROTTLE:
5640 					newchar->attackthrottle = GET_FLOAT_ARG(1);
5641 					if(arglist.count>=2)
5642 						newchar->attackthrottletime = GET_FLOAT_ARG(2)*GAME_SPEED;
5643 					break;
5644 				case CMD_MODEL_RISETIME:
5645 					newchar->risetime[0] = GET_INT_ARG(1);
5646 					newchar->risetime[1] = GET_INT_ARG(2);
5647 					break;
5648 				case CMD_MODEL_FACING:
5649 					newchar->facing = GET_INT_ARG(1);
5650 					break;
5651 				case CMD_MODEL_TURNDELAY:
5652 					newchar->turndelay = GET_INT_ARG(1);
5653 					break;
5654 				case CMD_MODEL_LIFESPAN:
5655 					newchar->lifespan = GET_FLOAT_ARG(1)*GAME_SPEED;
5656 					break;
5657 				case CMD_MODEL_SUMMONKILL:
5658 					newchar->summonkill = GET_INT_ARG(1);
5659 					break;
5660 				case CMD_MODEL_LIFEPOSITION:
5661 					if((value=GET_ARG(1))[0]) newchar->hpx = atoi(value);
5662 					if((value=GET_ARG(2))[0]) newchar->hpy = atoi(value);
5663 					break;
5664 				case CMD_MODEL_LIFEBARSTATUS:
5665 					_readbarstatus(buf+pos, &(newchar->hpbarstatus));
5666 					newchar->hpbarstatus.colourtable = &hpcolourtable;
5667 					break;
5668 				case CMD_MODEL_ICONPOSITION:
5669 					if((value=GET_ARG(1))[0]) newchar->icon.x = atoi(value);
5670 					if((value=GET_ARG(2))[0]) newchar->icon.y = atoi(value);
5671 					break;
5672 				case CMD_MODEL_NAMEPOSITION:
5673 					if((value=GET_ARG(1))[0]) newchar->namex = atoi(value);
5674 					if((value=GET_ARG(2))[0]) newchar->namey = atoi(value);
5675 					break;
5676 				case CMD_MODEL_COM:
5677 					{
5678 						// Section for custom freespecials starts here
5679 						int i, t;
5680 						alloc_specials(newchar);
5681 						for(i = 0, t = 1; i < MAX_SPECIAL_INPUTS-3; i++, t++)
5682 						{
5683 							value = GET_ARG(t);
5684 							if(!value[0]) break;
5685 							if(stricmp(value, "u")==0){
5686 								newchar->special[newchar->specials_loaded].input[i] = FLAG_MOVEUP;
5687 							}
5688 							else if(stricmp(value, "d")==0){
5689 								newchar->special[newchar->specials_loaded].input[i] = FLAG_MOVEDOWN;
5690 							}
5691 							else if(stricmp(value, "f")==0){
5692 								newchar->special[newchar->specials_loaded].input[i] = FLAG_FORWARD;
5693 							}
5694 							else if(stricmp(value, "b")==0){
5695 								newchar->special[newchar->specials_loaded].input[i] = FLAG_BACKWARD;
5696 							}
5697 							else if(stricmp(value, "a")==0){
5698 								newchar->special[newchar->specials_loaded].input[i] = FLAG_ATTACK;
5699 							}
5700 							else if(stricmp(value, "a2")==0){
5701 								newchar->special[newchar->specials_loaded].input[i] = FLAG_ATTACK2;
5702 							}
5703 							else if(stricmp(value, "a3")==0){
5704 								newchar->special[newchar->specials_loaded].input[i] = FLAG_ATTACK3;
5705 							}
5706 							else if(stricmp(value, "a4")==0){
5707 								newchar->special[newchar->specials_loaded].input[i] = FLAG_ATTACK4;
5708 							}
5709 							else if(stricmp(value, "j")==0){
5710 								newchar->special[newchar->specials_loaded].input[i] = FLAG_JUMP;
5711 							}
5712 							else if(stricmp(value, "s")==0 || stricmp(value, "k")==0){
5713 								newchar->special[newchar->specials_loaded].input[i] = FLAG_SPECIAL;
5714 							}
5715 							else if(strnicmp(value, "freespecial", 11)==0 && (!value[11] || (value[11] >= '1' && value[11] <= '9'))){
5716 								tempInt = atoi(value+11);
5717 								if(tempInt<1) tempInt = 1;
5718 								newchar->special[newchar->specials_loaded].anim = animspecials[tempInt-1];
5719 							}
5720 							else {
5721 								shutdownmessage = "Invalid freespecial command";
5722 								goto lCleanup;
5723 							}
5724 						}
5725 						newchar->special[newchar->specials_loaded].steps=i-1; // max steps
5726 						newchar->specials_loaded++;
5727 					}
5728 					// End section for custom freespecials
5729 					break;
5730 				case CMD_MODEL_REMAP:
5731 					{
5732 						// This command should not be used under 24bit mode, but for old mods, just give it a default palette
5733 						value = GET_ARG(1);
5734 						value2 = GET_ARG(2);
5735 						errorVal = load_colourmap(newchar, value, value2);
5736 						if(pixelformat==PIXEL_x8 && newchar->palette==NULL)
5737 						{
5738 							newchar->palette = malloc(PAL_BYTES);
5739 							if(loadimagepalette(value, packfile, newchar->palette)==0) {
5740 								shutdownmessage = "Failed to load palette!";
5741 								goto lCleanup;
5742 							}
5743 						}
5744 						mapflag[newchar->maps_loaded-1] = 1;
5745 						if(!errorVal){
5746 							switch(errorVal){
5747 								case 0: // uhm wait, we just tested for !errorVal...
5748 									shutdownmessage = "Failed to create colourmap. Image Used Twice!";
5749 									goto lCleanup;
5750 									break;
5751 								case -1:
5752 									shutdownmessage = "Failed to create colourmap. MAX_COLOUR_MAPS full!";
5753 									goto lCleanup;
5754 									break;
5755 								case -2:
5756 									shutdownmessage = "Failed to create colourmap. Failed to allocate memory!";
5757 									goto lCleanup;
5758 									break;
5759 								case -3:
5760 									shutdownmessage = "Failed to create colourmap. Failed to create bitmap1";
5761 									goto lCleanup;
5762 									break;
5763 								case -4:
5764 									shutdownmessage = "Failed to create colourmap. Failed to create bitmap2";
5765 									goto lCleanup;
5766 									break;
5767 							}
5768 						}
5769 					}
5770 					break;
5771 				case CMD_MODEL_PALETTE:
5772 					// main palette for the entity under 24bit mode
5773 					if(pixelformat!=PIXEL_x8) printf("Warning: command '%s' is not available under 8bit mode\n", command);
5774 					else if(newchar->palette==NULL)
5775 					{
5776 						value = GET_ARG(1);
5777 						if(stricmp(value, "none")==0){
5778 							if(pixelformat==PIXEL_x8) nopalette = 1;
5779 						}else{
5780 							newchar->palette = malloc(PAL_BYTES);
5781 							if(loadimagepalette(value, packfile, newchar->palette)==0) {
5782 								shutdownmessage = "Failed to load palette!";
5783 								goto lCleanup;
5784 							}
5785 						}
5786 					}
5787 					break;
5788 				case CMD_MODEL_ALTERNATEPAL:
5789 					// remap for the entity under 24bit mode, this method can replace remap command
5790 					if(pixelformat!=PIXEL_x8) printf("Warning: command '%s' is not available under 8bit mode\n", command);
5791 					else if(newchar->maps_loaded<MAX_COLOUR_MAPS) {
5792 						value = GET_ARG(1);
5793 						newchar->colourmap[(int)newchar->maps_loaded] = malloc(PAL_BYTES);
5794 						if(loadimagepalette(value, packfile, newchar->colourmap[(int)newchar->maps_loaded])==0) {
5795 							shutdownmessage = "Failed to load palette!";
5796 							goto lCleanup;
5797 						}
5798 						newchar->maps_loaded++;
5799 					}
5800 					break;
5801 				case CMD_MODEL_GLOBALMAP:
5802 					// use global palette under 24bit mode, so some entity/panel/bg can still use palette feature, that saves some memory
5803 					if(pixelformat!=PIXEL_x8) printf("Warning: command '%s' is not available under 8bit mode\n", command);
5804 					else newchar->globalmap = GET_INT_ARG(1);
5805 					break;
5806 				case CMD_MODEL_ALPHA:
5807 					newchar->alpha = GET_INT_ARG(1);
5808 					break;
5809 				case CMD_MODEL_REMOVE:
5810 					newchar->remove = GET_INT_ARG(1);
5811 					break;
5812 				case CMD_MODEL_SCRIPT:
5813 					//load the update script
5814 					lcmHandleCommandScripts(&arglist, newchar->scripts->update_script, "updateentityscript", filename);
5815 					break;
5816 				case CMD_MODEL_THINKSCRIPT:
5817 					lcmHandleCommandScripts(&arglist, newchar->scripts->think_script, "thinkscript", filename);
5818 					break;
5819 				case CMD_MODEL_TAKEDAMAGESCRIPT:
5820 					lcmHandleCommandScripts(&arglist, newchar->scripts->takedamage_script, "takedamagescript", filename);
5821 					break;
5822 				case CMD_MODEL_ONFALLSCRIPT:
5823 					lcmHandleCommandScripts(&arglist, newchar->scripts->onfall_script, "onfallscript", filename);
5824 					break;
5825 				case CMD_MODEL_ONPAINSCRIPT:
5826 					lcmHandleCommandScripts(&arglist, newchar->scripts->onpain_script, "onpainscript", filename);
5827 					break;
5828 				case CMD_MODEL_ONBLOCKSSCRIPT:
5829 					lcmHandleCommandScripts(&arglist, newchar->scripts->onblocks_script, "onblocksscript", filename);
5830 					break;
5831 				case CMD_MODEL_ONBLOCKWSCRIPT:
5832 					lcmHandleCommandScripts(&arglist, newchar->scripts->onblockw_script, "onblockwscript", filename);
5833 					break;
5834 				case CMD_MODEL_ONBLOCKOSCRIPT:
5835 					lcmHandleCommandScripts(&arglist, newchar->scripts->onblocko_script, "onblockoscript", filename);
5836 					break;
5837 				case CMD_MODEL_ONBLOCKZSCRIPT:
5838 					lcmHandleCommandScripts(&arglist, newchar->scripts->onblockz_script, "onblockzscript", filename);
5839 					break;
5840 				case CMD_MODEL_ONBLOCKASCRIPT:
5841 					lcmHandleCommandScripts(&arglist, newchar->scripts->onblocka_script, "onblockascript", filename);
5842 					break;
5843 				case CMD_MODEL_ONMOVEXSCRIPT:
5844 					lcmHandleCommandScripts(&arglist, newchar->scripts->onmovex_script, "onmovexscript", filename);
5845 					break;
5846 				case CMD_MODEL_ONMOVEZSCRIPT:
5847 					lcmHandleCommandScripts(&arglist, newchar->scripts->onmovez_script, "onmovezscript", filename);
5848 					break;
5849 				case CMD_MODEL_ONMOVEASCRIPT:
5850 					lcmHandleCommandScripts(&arglist, newchar->scripts->onmovea_script, "onmoveascript", filename);
5851 					break;
5852 				case CMD_MODEL_ONDEATHSCRIPT:
5853 					lcmHandleCommandScripts(&arglist, newchar->scripts->ondeath_script, "ondeathscript", filename);
5854 					break;
5855 				case CMD_MODEL_ONKILLSCRIPT:
5856 					lcmHandleCommandScripts(&arglist, newchar->scripts->onkill_script, "onkillscript", filename);
5857 					break;
5858 				case CMD_MODEL_DIDBLOCKSCRIPT:
5859 					lcmHandleCommandScripts(&arglist, newchar->scripts->didblock_script, "didblockscript", filename);
5860 					break;
5861 				case CMD_MODEL_ONDOATTACKSCRIPT:
5862 					lcmHandleCommandScripts(&arglist, newchar->scripts->ondoattack_script, "ondoattackscript", filename);
5863 					break;
5864 				case CMD_MODEL_DIDHITSCRIPT:
5865 					lcmHandleCommandScripts(&arglist, newchar->scripts->didhit_script, "didhitscript", filename);
5866 					break;
5867 				case CMD_MODEL_ONSPAWNSCRIPT:
5868 					lcmHandleCommandScripts(&arglist, newchar->scripts->onspawn_script, "onspawnscript", filename);
5869 					break;
5870 				case CMD_MODEL_ANIMATIONSCRIPT:
5871 					Script_Init(newchar->scripts->animation_script, "animationscript", filename, 0);
5872 					if(!load_script(newchar->scripts->animation_script, GET_ARG(1))) {
5873 						shutdownmessage = "Unable to load animation script!";
5874 						goto lCleanup;
5875 					}
5876 					//dont compile, until at end of this function
5877 					break;
5878 				case CMD_MODEL_KEYSCRIPT:
5879 					lcmHandleCommandScripts(&arglist, newchar->scripts->key_script, "entitykeyscript", filename);
5880 					break;
5881 				case CMD_MODEL_ANIM:
5882 					{
5883 						value = GET_ARG(1);
5884 						frameset = 0;
5885 						framecount = 0;
5886 						// Create new animation
5887 						newanim = alloc_anim();
5888 						if(!newanim){
5889 							shutdownmessage = "Not enough memory for animations!";
5890 							goto lCleanup;
5891 						}
5892 						newanim->model_index = newchar->index;
5893 						// Reset vars
5894 						curframe = 0;
5895 						memset(bbox, 0, sizeof(bbox));
5896 						memset(abox, 0, sizeof(abox));
5897 						memset(offset, 0, sizeof(offset));
5898 						memset(shadow_coords, 0, sizeof(shadow_coords));
5899 						memset(shadow_xz, 0, sizeof(shadow_xz));
5900 						memset(platform, 0, sizeof(platform));
5901 						shadow_set = 0;
5902 						attack = emptyattack;
5903 						attack.hitsound = SAMPLE_BEAT;
5904 						attack.hitflash = -1;
5905 						attack.blockflash = -1;
5906 						attack.blocksound = -1;
5907 						drawmethod = plainmethod;
5908 						idle = 0;
5909 						move = 0;
5910 						movez = 0;
5911 						movea = 0;
5912 						seta = -1;
5913 						frameshadow = -1;
5914 						soundtoplay = -1;
5915 
5916 						if(!newanim->range.xmin) newanim->range.xmin = -10;
5917 						newanim->range.xmax = (int)newchar->jumpheight*20;    //30-12-2004 default range affected by jump height
5918 						newanim->range.zmin = (int)-newchar->grabdistance/3;  //zmin
5919 						newanim->range.zmax = (int)newchar->grabdistance/3;   //zmax
5920 						newanim->range.amin = -1000;                          //amin
5921 						newanim->range.amax = 1000;                           //amax
5922 						newanim->range.bmin = -1000;                          //Base min.
5923 						newanim->range.bmax = 1000;                           //Base max.
5924 
5925 						newanim->jumpframe.v = 0;                           // Default disabled
5926 						//newanim->fastattack = 0;
5927 						newanim->energycost.mponly = 0;							//MP only.
5928 						newanim->energycost.disable = 0;							//Disable flag.
5929 						newanim->chargetime = 2;			// Default for backwards compatibility
5930 						newanim->shootframe = -1;
5931 						newanim->throwframe = -1;
5932 						newanim->tossframe = -1;			// this get 1 of weapons numshots shots in the animation that you want(normaly the last)by tails
5933 						newanim->jumpframe.f = -1;
5934 						newanim->flipframe = -1;
5935 						newanim->attackone = -1;
5936 						newanim->dive = 0;
5937 						newanim->followanim = 0;			// Default disabled
5938 						newanim->followcond = 0;
5939 						newanim->counterrange.framestart = -1;		//Start frame.
5940 						newanim->counterrange.frameend = -1;		//End frame.
5941 						newanim->counterrange.condition = 0;		//Counter cond.
5942 						newanim->counterrange.damaged = 0;		//Counter damage.
5943 						newanim->unsummonframe = -1;
5944 						newanim->landframe.frame = -1;
5945 						newanim->dropframe = -1;
5946 						newanim->cancel = 0;  // OX. For cancelling anims into a freespecial. 0 by default , 3 when enabled. IMPORTANT!! Must stay as it is!
5947 						newanim->animhits = 0; //OX counts hits on a per anim basis for cancels.
5948 						newanim->subentity = newanim->custbomb = newanim->custknife = newanim->custstar = newanim->custpshotno = -1;
5949 						newanim->quakeframe.framestart = 0;
5950 						newanim->sync = -1;
5951 
5952 						if(strnicmp(value, "idle", 4)==0 &&
5953 						(!value[4] || (value[4] >= '1' && value[4]<='9'))){
5954 								tempInt = atoi(value+4);
5955 								if(tempInt<1) tempInt = 1;
5956 								ani_id = animidles[tempInt-1];
5957 						}
5958 						else if(stricmp(value, "waiting")==0){
5959 								ani_id = ANI_SELECT;
5960 						}
5961 						else if(strnicmp(value, "walk", 4)==0 &&
5962 						(!value[4] || (value[4] >= '1' && value[4]<='9'))){
5963 							tempInt = atoi(value+4);
5964 							if(tempInt<1) tempInt = 1;
5965 							ani_id = animwalks[tempInt-1];
5966 							newanim->sync = ANI_WALK;
5967 						}
5968 						else if(stricmp(value, "sleep")==0){
5969 							ani_id = ANI_SLEEP;
5970 						}
5971 						else if(stricmp(value, "run")==0){
5972 							ani_id = ANI_RUN;
5973 						}
5974 						else if(strnicmp(value, "up", 2)==0 &&
5975 						(!value[2] || (value[2] >= '1' && value[2]<='9'))){
5976 							tempInt = atoi(value+2);
5977 							if(tempInt<1) tempInt = 1;
5978 							ani_id = animups[tempInt-1];
5979 							newanim->sync = ANI_WALK;
5980 						}
5981 						else if(strnicmp(value, "down", 4)==0 &&
5982 						(!value[4] || (value[4] >= '1' && value[4]<='9'))){
5983 							tempInt = atoi(value+4);
5984 							if(tempInt<1) tempInt = 1;
5985 							ani_id = animdowns[tempInt-1];
5986 							newanim->sync = ANI_WALK;
5987 						}
5988 						else if(strnicmp(value, "backwalk", 8)==0 &&
5989 						(!value[8] || (value[8] >= '1' && value[8]<='9'))){
5990 							tempInt = atoi(value+8);
5991 							if(tempInt<1) tempInt = 1;
5992 							ani_id = animbackwalks[tempInt-1];
5993 							newanim->sync = ANI_WALK;
5994 						}
5995 						else if(stricmp(value, "jump")==0){
5996 							ani_id = ANI_JUMP;
5997 							newanim->range.xmin = 50;    // Used for enemies that jump on walls
5998 							newanim->range.xmax = 60;    // Used for enemies that jump on walls
5999 						}
6000 						else if(stricmp(value, "duck")==0){
6001 							ani_id = ANI_DUCK;
6002 						}
6003 						else if(stricmp(value, "land")==0){
6004 							ani_id = ANI_LAND;
6005 						}
6006 						else if(stricmp(value, "pain")==0){
6007 							ani_id = ANI_PAIN;
6008 						}
6009 						else if(strnicmp(value, "pain", 4)==0 && value[4]>='1' && value[4]<='9'){
6010 							tempInt = atoi(value+4);
6011 							if(tempInt==1){
6012 								ani_id = ANI_PAIN;
6013 							}
6014 							else if(tempInt==2){
6015 								ani_id = ANI_PAIN2;
6016 							}
6017 							else if(tempInt==3){
6018 								ani_id = ANI_PAIN3;
6019 							}
6020 							else if(tempInt==4){
6021 								ani_id = ANI_PAIN4;
6022 							}
6023 							else if(tempInt==5){
6024 								ani_id = ANI_PAIN5;
6025 							}
6026 							else if(tempInt==6){
6027 								ani_id = ANI_PAIN6;
6028 							}
6029 							else if(tempInt==7){
6030 								ani_id = ANI_PAIN7;
6031 							}
6032 							else if(tempInt==8){
6033 								ani_id = ANI_PAIN8;
6034 							}
6035 							else if(tempInt==9){
6036 								ani_id = ANI_PAIN9;
6037 							}
6038 							else if(tempInt==10){
6039 								ani_id = ANI_PAIN10;
6040 							}
6041 							else{
6042 								if(tempInt<MAX_ATKS-STA_ATKS+1) tempInt = MAX_ATKS-STA_ATKS+1;
6043 								ani_id = animpains[tempInt+STA_ATKS-1];
6044 							}
6045 						}
6046 						else if(stricmp(value, "spain")==0){    // If shock attacks don't knock opponent down, play this
6047 							ani_id = ANI_SHOCKPAIN;
6048 						}
6049 						else if(stricmp(value, "bpain")==0){    // If burn attacks don't knock opponent down, play this
6050 							ani_id = ANI_BURNPAIN;
6051 						}
6052 						else if(stricmp(value, "fall")==0){
6053 							ani_id = ANI_FALL;   // If no new animation, load fall animation into both "respawn" & "fall"
6054 							newanim->bounce = 4;
6055 						}
6056 						else if(strnicmp(value, "fall", 4)==0 && value[4]>='1' && value[4]<='9'){
6057 							tempInt = atoi(value+4);
6058 							if(tempInt==1){
6059 								ani_id = ANI_FALL;
6060 							}
6061 							else if(tempInt==2){
6062 								ani_id = ANI_FALL2;
6063 							}
6064 							else if(tempInt==3){
6065 								ani_id = ANI_FALL3;
6066 							}
6067 							else if(tempInt==4){
6068 								ani_id = ANI_FALL4;
6069 							}
6070 							else if(tempInt==5){
6071 								ani_id = ANI_FALL5;
6072 							}
6073 							else if(tempInt==6){
6074 								ani_id = ANI_FALL6;
6075 							}
6076 							else if(tempInt==7){
6077 								ani_id = ANI_FALL7;
6078 							}
6079 							else if(tempInt==8){
6080 								ani_id = ANI_FALL8;
6081 							}
6082 							else if(tempInt==9){
6083 								ani_id = ANI_FALL9;
6084 							}
6085 							else if(tempInt==10){
6086 								ani_id = ANI_FALL10;
6087 							}
6088 							else{
6089 								if(tempInt<MAX_ATKS-STA_ATKS+1) tempInt = MAX_ATKS-STA_ATKS+1;
6090 								ani_id = animfalls[tempInt+STA_ATKS-1];
6091 							}
6092 							newanim->bounce = 4;
6093 						}
6094 						else if(stricmp(value, "shock")==0){    // If shock attacks do knock opponent down, play this
6095 							ani_id = ANI_SHOCK;
6096 							newanim->bounce = 4;
6097 						}
6098 						else if(stricmp(value, "burn")==0){    // If burn attacks do knock opponent down, play this
6099 							ani_id = ANI_BURN;
6100 							newanim->bounce = 4;
6101 						}
6102 						else if(stricmp(value, "death")==0){      //  If new animation is present, overwrite new_anim with it.
6103 							ani_id = ANI_DIE;
6104 						}
6105 						else if(strnicmp(value, "death", 5)==0 && value[5]>='1' && value[5]<='9'){
6106 							tempInt = atoi(value+5);
6107 							if(tempInt==1){
6108 								ani_id = ANI_DIE;
6109 							}
6110 							else if(tempInt==2){
6111 								ani_id = ANI_DIE2;
6112 							}
6113 							else if(tempInt==3){
6114 								ani_id = ANI_DIE3;
6115 							}
6116 							else if(tempInt==4){
6117 								ani_id = ANI_DIE4;
6118 							}
6119 							else if(tempInt==5){
6120 								ani_id = ANI_DIE5;
6121 							}
6122 							else if(tempInt==6){
6123 								ani_id = ANI_DIE6;
6124 							}
6125 							else if(tempInt==7){
6126 								ani_id = ANI_DIE7;
6127 							}
6128 							else if(tempInt==8){
6129 								ani_id = ANI_DIE8;
6130 							}
6131 							else if(tempInt==9){
6132 								ani_id = ANI_DIE9;
6133 							}
6134 							else if(tempInt==10){
6135 								ani_id = ANI_DIE10;
6136 							}
6137 							else{
6138 								if(tempInt<MAX_ATKS-STA_ATKS+1) tempInt = MAX_ATKS-STA_ATKS+1;
6139 								ani_id = animdies[tempInt+STA_ATKS-1];
6140 							}
6141 						}
6142 						else if(stricmp(value, "sdie")==0){
6143 							ani_id = ANI_SHOCKDIE;
6144 						}
6145 						else if(stricmp(value, "bdie")==0){
6146 							ani_id = ANI_BURNDIE;
6147 						}
6148 						else if(stricmp(value, "chipdeath")==0){
6149 							ani_id = ANI_CHIPDEATH;
6150 						}
6151 						else if(stricmp(value, "guardbreak")==0){
6152 							ani_id = ANI_GUARDBREAK;
6153 						}
6154 						else if(stricmp(value, "riseb")==0){
6155 							ani_id = ANI_RISEB;
6156 						}
6157 
6158 
6159 						else if(stricmp(value, "rises")==0){
6160 							ani_id = ANI_RISES;
6161 						}
6162 						else if(stricmp(value, "rise")==0){
6163 							ani_id = ANI_RISE;   // If no new animation, load fall animation into both "respawn" & "fall"
6164 						}
6165 						else if(strnicmp(value, "rise", 4)==0 && value[4]>='1' && value[4]<='9'){
6166 							tempInt = atoi(value+4);
6167 							if(tempInt==1){
6168 								ani_id = ANI_RISE;
6169 							}
6170 							else if(tempInt==2){
6171 								ani_id = ANI_RISE2;
6172 							}
6173 							else if(tempInt==3){
6174 								ani_id = ANI_RISE3;
6175 							}
6176 							else if(tempInt==4){
6177 								ani_id = ANI_RISE4;
6178 							}
6179 							else if(tempInt==5){
6180 								ani_id = ANI_RISE5;
6181 							}
6182 							else if(tempInt==6){
6183 								ani_id = ANI_RISE6;
6184 							}
6185 							else if(tempInt==7){
6186 								ani_id = ANI_RISE7;
6187 							}
6188 							else if(tempInt==8){
6189 								ani_id = ANI_RISE8;
6190 							}
6191 							else if(tempInt==9){
6192 								ani_id = ANI_RISE9;
6193 							}
6194 							else if(tempInt==10){
6195 								ani_id = ANI_RISE10;
6196 							}
6197 							else{
6198 								if(tempInt<MAX_ATKS-STA_ATKS+1) tempInt = MAX_ATKS-STA_ATKS+1;
6199 								ani_id = animrises[tempInt+STA_ATKS-1];
6200 							}
6201 						}
6202 						else if(stricmp(value, "riseattackb")==0){
6203 							ani_id = ANI_RISEATTACKB;
6204 						}
6205 						else if(stricmp(value, "riseattacks")==0){
6206 							ani_id = ANI_RISEATTACKS;
6207 						}
6208 						else if(stricmp(value, "riseattack")==0){
6209 							ani_id = ANI_RISEATTACK;   // If no new animation, load fall animation into both "respawn" & "fall"
6210 						}
6211 						else if(strnicmp(value, "riseattack", 10)==0 && value[10]>='1' && value[10]<='9'){
6212 							tempInt = atoi(value+10);
6213 							if(tempInt==1){
6214 								ani_id = ANI_RISEATTACK;
6215 							}
6216 							else if(tempInt==2){
6217 								ani_id = ANI_RISEATTACK2;
6218 							}
6219 							else if(tempInt==3){
6220 								ani_id = ANI_RISEATTACK3;
6221 							}
6222 							else if(tempInt==4){
6223 								ani_id = ANI_RISEATTACK4;
6224 							}
6225 							else if(tempInt==6){
6226 								ani_id = ANI_RISEATTACK5;
6227 							}
6228 							else if(tempInt==6){
6229 								ani_id = ANI_RISEATTACK6;
6230 							}
6231 							else if(tempInt==7){
6232 								ani_id = ANI_RISEATTACK7;
6233 							}
6234 							else if(tempInt==8){
6235 								ani_id = ANI_RISEATTACK8;
6236 							}
6237 							else if(tempInt==9){
6238 								ani_id = ANI_RISEATTACK9;
6239 							}
6240 							else if(tempInt==10){
6241 								ani_id = ANI_RISEATTACK10;
6242 							}
6243 							else{
6244 								if(tempInt<MAX_ATKS-STA_ATKS+1) tempInt = MAX_ATKS-STA_ATKS+1;
6245 								ani_id = animriseattacks[tempInt+STA_ATKS-1];
6246 							}
6247 						}
6248 						else if(stricmp(value, "select")==0){
6249 							ani_id = ANI_PICK;
6250 						}
6251 						else if(strnicmp(value, "attack", 6)==0 &&
6252 							(!value[6] || (value[6] >= '1' && value[6]<='9')))
6253 						{
6254 							tempInt = atoi(value+6);
6255 							if(tempInt<1) tempInt = 1;
6256 							ani_id = animattacks[tempInt-1];
6257 						}
6258 						else if(stricmp(value, "throwattack")==0){
6259 							ani_id = ANI_THROWATTACK;
6260 						}
6261 						else if(stricmp(value, "upper")==0){
6262 							ani_id = ANI_UPPER;
6263 							attack.counterattack = 100; //default to 100
6264 							newanim->range.xmin = -10;
6265 							newanim->range.xmax = 120;
6266 						}
6267 						else if(stricmp(value, "cant")==0){
6268 							ani_id = ANI_CANT;
6269 						}
6270 						else if(stricmp(value, "jumpcant")==0){
6271 							ani_id = ANI_JUMPCANT;
6272 						}
6273 						else if(stricmp(value, "charge")==0){
6274 							ani_id = ANI_CHARGE;
6275 						}
6276 						else if(stricmp(value, "faint")==0){
6277 							ani_id = ANI_FAINT;
6278 						}
6279 						else if(stricmp(value, "dodge")==0){
6280 							ani_id = ANI_DODGE;
6281 						}
6282 						else if(stricmp(value, "special")==0 || stricmp(value, "special1")==0){
6283 							ani_id = ANI_SPECIAL;
6284 							newanim->energycost.cost = 6;
6285 						}
6286 						else if(stricmp(value, "special2")==0){
6287 							ani_id = ANI_SPECIAL2;
6288 						}
6289 						else if(stricmp(value, "special3")==0 || stricmp(value, "jumpspecial")==0){
6290 							ani_id = ANI_JUMPSPECIAL;
6291 						}
6292 						else if(strnicmp(value, "freespecial", 11)==0 && (!value[11] || (value[11] >= '1' && value[11] <= '9'))){
6293 							tempInt = atoi(value+11);
6294 							if(tempInt<1) tempInt = 1;
6295 							ani_id = animspecials[tempInt-1];
6296 						}
6297 						else if(stricmp(value, "jumpattack")==0){
6298 							ani_id = ANI_JUMPATTACK;
6299 							if(newchar->jumpheight==4)
6300 							{
6301 								newanim->range.xmin = 150;
6302 								newanim->range.xmax = 200;
6303 							}
6304 						}
6305 						else if(stricmp(value, "jumpattack2")==0){
6306 							ani_id = ANI_JUMPATTACK2;
6307 						}
6308 						else if(stricmp(value, "jumpattack3")==0){
6309 							ani_id = ANI_JUMPATTACK3;
6310 						}
6311 						else if(stricmp(value, "jumpforward")==0){
6312 							ani_id = ANI_JUMPFORWARD;
6313 						}
6314 						else if(stricmp(value, "runjumpattack")==0){
6315 							ani_id = ANI_RUNJUMPATTACK;
6316 						}
6317 						else if(stricmp(value, "runattack")==0){
6318 							ani_id = ANI_RUNATTACK;    // New attack for when a player is running
6319 						}
6320 						else if(stricmp(value, "attackup")==0){
6321 							ani_id = ANI_ATTACKUP;    // New attack for when a player presses u u
6322 						}
6323 						else if(stricmp(value, "attackdown")==0){
6324 							ani_id = ANI_ATTACKDOWN;    // New attack for when a player presses d d
6325 						}
6326 						else if(stricmp(value, "attackforward")==0){
6327 							ani_id = ANI_ATTACKFORWARD;    // New attack for when a player presses f f
6328 						}
6329 						else if(stricmp(value, "attackbackward")==0){
6330 							ani_id = ANI_ATTACKBACKWARD;    // New attack for when a player presses b a
6331 						}
6332 						else if(stricmp(value, "attackboth")==0){    // Attack that is executed by holding down j and pressing a
6333 							ani_id = ANI_ATTACKBOTH;
6334 						}
6335 						else if(stricmp(value, "get")==0){
6336 							ani_id = ANI_GET;
6337 						}
6338 						else if(stricmp(value, "grab")==0){
6339 							ani_id = ANI_GRAB;
6340 						}
6341 						else if(stricmp(value, "grabwalk")==0){
6342 							ani_id = ANI_GRABWALK;
6343 							newanim->sync = ANI_GRABWALK;
6344 						}
6345 						else if(stricmp(value, "grabwalkup")==0){
6346 							ani_id = ANI_GRABWALKUP;
6347 							newanim->sync = ANI_GRABWALK;
6348 						}
6349 						else if(stricmp(value, "grabwalkdown")==0){
6350 							ani_id = ANI_GRABWALKDOWN;
6351 							newanim->sync = ANI_GRABWALK;
6352 						}
6353 						else if(stricmp(value, "grabbackwalk")==0){
6354 							ani_id = ANI_GRABBACKWALK;
6355 							newanim->sync = ANI_GRABWALK;
6356 						}
6357 						else if(stricmp(value, "grabturn")==0){
6358 							ani_id = ANI_GRABTURN;
6359 						}
6360 						else if(stricmp(value, "grabbed")==0){    // New grabbed animation for when grabbed
6361 							ani_id = ANI_GRABBED;
6362 						}
6363 						else if(stricmp(value, "grabbedwalk")==0){    // New animation for when grabbed and forced to walk
6364 							ani_id = ANI_GRABBEDWALK;
6365 							newanim->sync = ANI_GRABBEDWALK;
6366 						}
6367 						else if(stricmp(value, "grabbedwalkup")==0){
6368 							ani_id = ANI_GRABWALKUP;
6369 							newanim->sync = ANI_GRABBEDWALK;
6370 						}
6371 						else if(stricmp(value, "grabbedwalkdown")==0){
6372 							ani_id = ANI_GRABWALKDOWN;
6373 							newanim->sync = ANI_GRABBEDWALK;
6374 						}
6375 						else if(stricmp(value, "grabbedbackwalk")==0){
6376 							ani_id = ANI_GRABBEDBACKWALK;
6377 							newanim->sync = ANI_GRABBEDWALK;
6378 						}
6379 						else if(stricmp(value, "grabbedturn")==0){
6380 							ani_id = ANI_GRABBEDTURN;
6381 						}
6382 						else if(stricmp(value, "grabattack")==0){
6383 							ani_id = ANI_GRABATTACK;
6384 							newanim->attackone = 1; // default to 1, attack one one opponent
6385 						}
6386 						else if(stricmp(value, "grabattack2")==0){
6387 							ani_id = ANI_GRABATTACK2;
6388 							newanim->attackone = 1;
6389 						}
6390 						else if(stricmp(value, "grabforward")==0){    // New grab attack for when pressing forward attack
6391 							ani_id = ANI_GRABFORWARD;
6392 							newanim->attackone = 1;
6393 						}
6394 						else if(stricmp(value, "grabforward2")==0){    // New grab attack for when pressing forward attack
6395 							ani_id = ANI_GRABFORWARD2;
6396 							newanim->attackone = 1;
6397 						}
6398 						else if(stricmp(value, "grabbackward")==0){    // New grab attack for when pressing backward attack
6399 							ani_id = ANI_GRABBACKWARD;
6400 							newanim->attackone = 1;
6401 						}
6402 						else if(stricmp(value, "grabbackward2")==0){    // New grab attack for when pressing backward attack
6403 							ani_id = ANI_GRABBACKWARD2;
6404 							newanim->attackone = 1;
6405 						}
6406 						else if(stricmp(value, "grabup")==0){    // New grab attack for when pressing up attack
6407 							ani_id = ANI_GRABUP;
6408 							newanim->attackone = 1;
6409 						}
6410 						else if(stricmp(value, "grabup2")==0){    // New grab attack for when pressing up attack
6411 							ani_id = ANI_GRABUP2;
6412 							newanim->attackone = 1;
6413 						}
6414 						else if(stricmp(value, "grabdown")==0){    // New grab attack for when pressing down attack
6415 							ani_id = ANI_GRABDOWN;
6416 							newanim->attackone = 1;
6417 						}
6418 						else if(stricmp(value, "grabdown2")==0){    // New grab attack for when pressing down attack
6419 							ani_id = ANI_GRABDOWN2;
6420 							newanim->attackone = 1;
6421 						}
6422 						else if(stricmp(value, "spawn")==0){      //  spawn/respawn works separately now
6423 							ani_id = ANI_SPAWN;
6424 						}
6425 						else if(stricmp(value, "respawn")==0){      //  spawn/respawn works separately now
6426 							ani_id = ANI_RESPAWN;
6427 						}
6428 						else if(stricmp(value, "throw")==0){
6429 							ani_id = ANI_THROW;
6430 						}
6431 						else if(stricmp(value, "block")==0){    // Now enemies can block attacks on occasion
6432 							ani_id = ANI_BLOCK;
6433 							newanim->range.xmin = 1;
6434 							newanim->range.xmax = 100;
6435 						}
6436 						else if(strnicmp(value, "follow", 6)==0 && (!value[6] || (value[6]>='1' && value[6]<='9'))){
6437 							tempInt = atoi(value+6);
6438 							if(tempInt<1) tempInt = 1;
6439 							ani_id = animfollows[tempInt-1];
6440 						}
6441 						else if(stricmp(value, "chargeattack")==0){
6442 							ani_id = ANI_CHARGEATTACK;
6443 						}
6444 						else if(stricmp(value, "vault")==0){
6445 							ani_id = ANI_VAULT;
6446 						}
6447 						else if(stricmp(value, "turn")==0){
6448 							ani_id = ANI_TURN;
6449 						}
6450 						else if(stricmp(value, "forwardjump")==0){
6451 							ani_id = ANI_FORWARDJUMP;
6452 						}
6453 						else if(stricmp(value, "runjump")==0){
6454 							ani_id = ANI_RUNJUMP;
6455 						}
6456 						else if(stricmp(value, "jumpland")==0){
6457 							ani_id = ANI_JUMPLAND;
6458 						}
6459 						else if(stricmp(value, "jumpdelay")==0){
6460 							ani_id = ANI_JUMPDELAY;
6461 						}
6462 						else if(stricmp(value, "hitwall")==0){
6463 							ani_id = ANI_HITWALL;
6464 						}
6465 						else if(stricmp(value, "slide")==0){
6466 							ani_id = ANI_SLIDE;
6467 						}
6468 						else if(stricmp(value, "runslide")==0){
6469 							ani_id = ANI_RUNSLIDE;
6470 						}
6471 						else if(stricmp(value, "blockpainb")==0){
6472 							ani_id = ANI_BLOCKPAINB;
6473 						}
6474 						else if(stricmp(value, "blockpains")==0){
6475 							ani_id = ANI_BLOCKPAINS;
6476 						}
6477 						else if(stricmp(value, "blockpain")==0){
6478 							ani_id = ANI_BLOCKPAIN;   // If no new animation, load fall animation into both "respawn" & "fall"
6479 						}
6480 						else if(strnicmp(value, "blockpain", 9)==0 && value[9]>='1' && value[9]<='9'){
6481 							tempInt = atoi(value+9);
6482 							if(tempInt==1){
6483 								ani_id = ANI_BLOCKPAIN;
6484 							}
6485 							else if(tempInt==2){
6486 								ani_id = ANI_BLOCKPAIN2;
6487 							}
6488 							else if(tempInt==3){
6489 								ani_id = ANI_BLOCKPAIN3;
6490 							}
6491 							else if(tempInt==4){
6492 								ani_id = ANI_BLOCKPAIN4;
6493 							}
6494 							else if(tempInt==5){
6495 								ani_id = ANI_BLOCKPAIN5;
6496 							}
6497 							else if(tempInt==6){
6498 								ani_id = ANI_BLOCKPAIN6;
6499 							}
6500 							else if(tempInt==7){
6501 								ani_id = ANI_BLOCKPAIN7;
6502 							}
6503 							else if(tempInt==8){
6504 								ani_id = ANI_BLOCKPAIN8;
6505 							}
6506 							else if(tempInt==9){
6507 								ani_id = ANI_BLOCKPAIN9;
6508 							}
6509 							else if(tempInt==10){
6510 								ani_id = ANI_BLOCKPAIN10;
6511 							}
6512 							else{
6513 								if(tempInt<MAX_ATKS-STA_ATKS+1) tempInt = MAX_ATKS-STA_ATKS+1;
6514 								ani_id = animblkpains[tempInt+STA_ATKS-1];
6515 							}
6516 						}
6517 						else if(stricmp(value, "duckattack")==0){
6518 							ani_id = ANI_DUCKATTACK;
6519 						}
6520 						else if(stricmp(value, "walkoff")==0){
6521 							ani_id = ANI_WALKOFF;
6522 						}
6523 						else {
6524 							shutdownmessage = "Invalid animation name!";
6525 							goto lCleanup;
6526 						}
6527 
6528 						newchar->animation[ani_id] = newanim;
6529 					}
6530 					break;
6531 				case CMD_MODEL_LOOP:
6532 					if(!newanim) {
6533 						shutdownmessage = "Can't set loop: no animation specified!";
6534 						goto lCleanup;
6535 					}
6536 					newanim->loop.mode          = GET_INT_ARG(1); //0 = Off, 1 = on.
6537 					newanim->loop.framestart    = GET_INT_ARG(2); //Loop to frame.
6538 					newanim->loop.frameend      = GET_INT_ARG(3); //Loop end frame.
6539 					break;
6540 				case CMD_MODEL_ANIMHEIGHT:
6541 					newanim->height = GET_INT_ARG(1);
6542 					break;
6543 				case CMD_MODEL_DELAY:
6544 					delay = GET_INT_ARG(1);
6545 					break;
6546 				case CMD_MODEL_OFFSET:
6547 					offset[0] = GET_INT_ARG(1);
6548 					offset[1] = GET_INT_ARG(2);
6549 					break;
6550 				case CMD_MODEL_SHADOWCOORDS:
6551 					shadow_xz[0] = GET_INT_ARG(1);
6552 					shadow_xz[1] = GET_INT_ARG(2);
6553 					shadow_set=1;
6554 					break;
6555 				case CMD_MODEL_ENERGYCOST: case CMD_MODEL_MPCOST:
6556 					newanim->energycost.cost    = GET_INT_ARG(1);
6557 					newanim->energycost.mponly  = GET_INT_ARG(2);
6558 					newanim->energycost.disable = GET_INT_ARG(3);
6559 					break;
6560 				case CMD_MODEL_MPONLY:
6561 					newanim->energycost.mponly = GET_INT_ARG(1);
6562 					break;
6563 				case CMD_MODEL_CHARGETIME:
6564 					newanim->chargetime = GET_FLOAT_ARG(1);
6565 					break;
6566 				case CMD_MODEL_ATTACKONE:
6567 					newanim->attackone = GET_INT_ARG(1);
6568 					break;
6569 				case CMD_MODEL_COUNTERATTACK:
6570 					attack.counterattack = GET_INT_ARG(1);
6571 					break;
6572 				case CMD_MODEL_THROWFRAME:	case CMD_MODEL_PSHOTFRAME: case CMD_MODEL_PSHOTFRAMEW: case CMD_MODEL_PSHOTFRAMENO:
6573 					newanim->throwframe = GET_FRAME_ARG(1);
6574 					newanim->throwa = GET_INT_ARG(2);
6575 					if(!newanim->throwa)
6576 						newanim->throwa = 70;
6577 					else if(newanim->throwa == -1)
6578 						newanim->throwa = 0;
6579 					break;
6580 				case CMD_MODEL_SHOOTFRAME:
6581 					newanim->shootframe = GET_FRAME_ARG(1);
6582 					newanim->throwa = GET_INT_ARG(2);
6583 					if(newanim->throwa == -1)
6584 						newanim->throwa = 0;
6585 					break;
6586 				case CMD_MODEL_TOSSFRAME: case CMD_MODEL_PBOMBFRAME:
6587 					newanim->tossframe = GET_FRAME_ARG(1);
6588 					newanim->throwa = GET_INT_ARG(2);
6589 					if(newanim->throwa < 0) newanim->throwa = -1;
6590 					break;
6591 				case CMD_MODEL_CUSTKNIFE: case CMD_MODEL_CUSTPSHOT: case CMD_MODEL_CUSTPSHOTW:
6592 					newanim->custknife= get_cached_model_index(GET_ARG(1));
6593 					break;
6594 				case CMD_MODEL_CUSTPSHOTNO:
6595 					newanim->custpshotno= get_cached_model_index(GET_ARG(1));
6596 					break;
6597 				case CMD_MODEL_CUSTBOMB: case CMD_MODEL_CUSTPBOMB:
6598 					newanim->custbomb= get_cached_model_index(GET_ARG(1));
6599 					break;
6600 				case CMD_MODEL_CUSTSTAR:
6601 					newanim->custstar= get_cached_model_index(GET_ARG(1));
6602 					break;
6603 
6604 				// UT: merge dive and jumpframe, because they can't be used at the same time
6605 				case CMD_MODEL_DIVE:	//dive kicks
6606 					newanim->dive = 1;
6607 					newanim->jumpframe.f = 0;
6608 					newanim->jumpframe.x = GET_FLOAT_ARG(1);
6609 					newanim->jumpframe.v = -GET_FLOAT_ARG(2);
6610 					newanim->jumpframe.ent = -1;
6611 					break;
6612 				case CMD_MODEL_DIVE1:
6613 					newanim->dive = 1;
6614 					newanim->jumpframe.f = 0;
6615 					newanim->jumpframe.x = GET_FLOAT_ARG(1);
6616 					newanim->jumpframe.ent = -1;
6617 					break;
6618 				case CMD_MODEL_DIVE2:
6619 					newanim->dive = 1;
6620 					newanim->jumpframe.f = 0;
6621 					newanim->jumpframe.v = -GET_FLOAT_ARG(1);
6622 					newanim->jumpframe.ent = -1;
6623 					break;
6624 				case CMD_MODEL_JUMPFRAME:
6625 					{
6626 						newanim->jumpframe.f    = GET_FRAME_ARG(1);   //Frame.
6627 						newanim->jumpframe.v    = GET_FLOAT_ARG(2); //Vertical velocity.
6628 						value = GET_ARG(3);
6629 						if(value[0])
6630 						{
6631 							newanim->jumpframe.x = GET_FLOAT_ARG(3);
6632 							newanim->jumpframe.z = GET_FLOAT_ARG(4);
6633 						}
6634 						else // k, only for backward compatibility :((((((((((((((((
6635 						{
6636 							if(newanim->jumpframe.v <= 0)
6637 							{
6638 								if(newchar->type == TYPE_PLAYER)
6639 								{
6640 									newanim->jumpframe.v = newchar->jumpheight / 2;
6641 									newanim->jumpframe.z = 0;
6642 									newanim->jumpframe.x = 2;
6643 								}
6644 								else
6645 								{
6646 									newanim->jumpframe.v = newchar->jumpheight;
6647 									newanim->jumpframe.z = newanim->jumpframe.x = 0;
6648 								}
6649 							}
6650 							else
6651 							{
6652 								if(newchar->type != TYPE_ENEMY && newchar->type != TYPE_NPC)
6653 									newanim->jumpframe.z = newanim->jumpframe.x = 0;
6654 								else
6655 								{
6656 									newanim->jumpframe.z = 0;
6657 									newanim->jumpframe.x = (float)1.3;
6658 								}
6659 							}
6660 						}
6661 
6662 						value = GET_ARG(5);
6663 						if(value[0]) newanim->jumpframe.ent = get_cached_model_index(value);
6664 						else newanim->jumpframe.ent = -1;
6665 
6666 					}
6667 					break;
6668 				case CMD_MODEL_BOUNCEFACTOR:
6669 					newanim->bounce = GET_FLOAT_ARG(1);
6670 					break;
6671 				case CMD_MODEL_LANDFRAME:
6672 					newanim->landframe.frame = GET_FRAME_ARG(1);
6673 					value = GET_ARG(2);
6674 					if(value[0]) newanim->landframe.ent = get_cached_model_index(value);
6675 					else newanim->landframe.ent = -1;
6676 					break;
6677 				case CMD_MODEL_DROPFRAME:
6678 					newanim->dropframe = GET_FRAME_ARG(1);
6679 					break;
6680 				case CMD_MODEL_CANCEL:
6681 					{
6682 						int i, t;
6683 						alloc_specials(newchar);
6684 						newanim->cancel = 3;
6685 						for(i = 0, t = 4; i < MAX_SPECIAL_INPUTS-6; i++, t++)
6686 						{
6687 							value = GET_ARG(t);
6688 							if(!value[0]) break;
6689 							if(stricmp(value, "u")==0){
6690 								newchar->special[newchar->specials_loaded].input[i] = FLAG_MOVEUP;
6691 							}
6692 							else if(stricmp(value, "d")==0){
6693 								newchar->special[newchar->specials_loaded].input[i] = FLAG_MOVEDOWN;
6694 							}
6695 							else if(stricmp(value, "f")==0){
6696 								newchar->special[newchar->specials_loaded].input[i] = FLAG_FORWARD;
6697 							}
6698 							else if(stricmp(value, "b")==0){
6699 								newchar->special[newchar->specials_loaded].input[i] = FLAG_BACKWARD;
6700 							}
6701 							else if(stricmp(value, "a")==0){
6702 								newchar->special[newchar->specials_loaded].input[i] = FLAG_ATTACK;
6703 							}
6704 							else if(stricmp(value, "a2")==0){
6705 								newchar->special[newchar->specials_loaded].input[i] = FLAG_ATTACK2;
6706 							}
6707 							else if(stricmp(value, "a3")==0){
6708 								newchar->special[newchar->specials_loaded].input[i] = FLAG_ATTACK3;
6709 							}
6710 							else if(stricmp(value, "a4")==0){
6711 								newchar->special[newchar->specials_loaded].input[i] = FLAG_ATTACK4;
6712 							}
6713 							else if(stricmp(value, "j")==0){
6714 								newchar->special[newchar->specials_loaded].input[i] = FLAG_JUMP;
6715 							}
6716 							else if(stricmp(value, "s")==0 || stricmp(value, "k")==0){
6717 								newchar->special[newchar->specials_loaded].input[i] = FLAG_SPECIAL;
6718 							}
6719 							else if(strnicmp(value, "freespecial", 11)==0 && (!value[11] || (value[11] >= '1' && value[11] <= '9'))){
6720 								tempInt = atoi(value+11);
6721 								if(tempInt<1) tempInt = 1;
6722 								newchar->special[newchar->specials_loaded].anim = animspecials[tempInt-1];
6723 								newchar->special[newchar->specials_loaded].startframe = GET_INT_ARG(1); // stores start frame
6724 								newchar->special[newchar->specials_loaded].endframe = GET_INT_ARG(2); // stores end frame
6725 								newchar->special[newchar->specials_loaded].cancel = ani_id;                    // stores current anim
6726 								newchar->special[newchar->specials_loaded].hits = GET_INT_ARG(3);// stores hits
6727 							}
6728 							else {
6729 								shutdownmessage = "Invalid cancel command!";
6730 								goto lCleanup;
6731 							}
6732 						}
6733 						newchar->special[newchar->specials_loaded].steps = i-1; // max steps
6734 						newchar->specials_loaded++;
6735 					}
6736 					break;
6737 				case CMD_MODEL_SOUND:
6738 					soundtoplay = sound_load_sample(GET_ARG(1), packfile, 0);
6739 					break;
6740 				case CMD_MODEL_HITFX:
6741 					if(stricmp(GET_ARG(1),"none")==0) attack.hitsound=-1;
6742 					else attack.hitsound = sound_load_sample(GET_ARG(1), packfile, 0);
6743 					break;
6744 				case CMD_MODEL_HITFLASH:
6745 					value = GET_ARG(1);
6746 					if(stricmp(value, "none")==0) attack.hitflash = -1;
6747 					else attack.hitflash = get_cached_model_index(value);
6748 					break;
6749 				case CMD_MODEL_BLOCKFLASH:
6750 					value = GET_ARG(1);
6751 					if(stricmp(value, "none")==0) attack.blockflash = -1;
6752 					else attack.blockflash = get_cached_model_index(value);
6753 					break;
6754 				case CMD_MODEL_BLOCKFX:
6755 					attack.blocksound = sound_load_sample(GET_ARG(1), packfile, 0);
6756 					break;
6757 				case CMD_MODEL_FASTATTACK:
6758 					if(GET_INT_ARG(1))
6759 						attack.pain_time = GAME_SPEED/20;
6760 					break;
6761 				case CMD_MODEL_BBOX:
6762 					bbox[0] = GET_INT_ARG(1);
6763 					bbox[1] = GET_INT_ARG(2);
6764 					bbox[2] = GET_INT_ARG(3);
6765 					bbox[3] = GET_INT_ARG(4);
6766 					bbox[4] = GET_INT_ARG(5);
6767 					break;
6768 				case CMD_MODEL_BBOXZ:
6769 					bbox[4] = GET_INT_ARG(1);
6770 					break;
6771 				case CMD_MODEL_PLATFORM:
6772 					newchar->hasPlatforms=1;
6773 					//for(i=0;(GET_ARG(i+1)[0]; i++);
6774 					for(i=0;i<arglist.count && arglist.args[i] && arglist.args[i][0];i++);
6775 					if(i<8)
6776 					{
6777 						for(i=0;i<6; i++) platform[i+2] = GET_FLOAT_ARG(i+1);
6778 						platform[0] = 99999;
6779 					}
6780 					else for(i=0; i<8; i++) platform[i] = GET_FLOAT_ARG(i+1);
6781 					break;
6782 				case CMD_MODEL_DRAWMETHOD:
6783 					// special effects
6784 					drawmethod.scalex = GET_INT_ARG(1);
6785 					drawmethod.scaley = GET_INT_ARG(2);
6786 					drawmethod.flipx = GET_INT_ARG(3);
6787 					drawmethod.flipy = GET_INT_ARG(4);
6788 					drawmethod.shiftx = GET_INT_ARG(5);
6789 					drawmethod.alpha = GET_INT_ARG(6);
6790 					if(!blendfx_is_set)
6791 					{
6792 						if(drawmethod.alpha>0 && drawmethod.alpha<=MAX_BLENDINGS)
6793 						{
6794 							blendfx[drawmethod.alpha-1] = 1;
6795 						}
6796 					}
6797 					drawmethod.remap = GET_INT_ARG(7);
6798 					drawmethod.fillcolor = parsecolor(GET_ARG(8));
6799 					drawmethod.rotate = GET_INT_ARG(9);
6800 					drawmethod.fliprotate = GET_INT_ARG(10);
6801 					if(drawmethod.scalex<0) {drawmethod.scalex = -drawmethod.scalex;drawmethod.flipx = !drawmethod.flipx;}
6802 					if(drawmethod.scaley<0) {drawmethod.scaley = -drawmethod.scaley;drawmethod.flipy = !drawmethod.flipy;}
6803 					if(drawmethod.rotate)
6804 					{
6805 						drawmethod.rotate = (drawmethod.rotate%360 + 360)%360;
6806 					}
6807 					drawmethod.flag = 1;
6808 					break;
6809 				case CMD_MODEL_NODRAWMETHOD:
6810 					//disable special effects
6811 					drawmethod.flag = 0;
6812 					break;
6813 				case CMD_MODEL_ATTACK: case CMD_MODEL_ATTACK1:  case CMD_MODEL_ATTACK2: case CMD_MODEL_ATTACK3:
6814 				case CMD_MODEL_ATTACK4: case CMD_MODEL_ATTACK5: case CMD_MODEL_ATTACK6: case CMD_MODEL_ATTACK7:
6815 				case CMD_MODEL_ATTACK8: case CMD_MODEL_ATTACK9: case CMD_MODEL_ATTACK10:
6816 				case CMD_MODEL_SHOCK: case CMD_MODEL_BURN: case CMD_MODEL_STEAL: case CMD_MODEL_FREEZE: case CMD_MODEL_ITEMBOX:
6817 				case CMD_MODEL_ATTACK_ETC:
6818 					abox[0] = GET_INT_ARG(1);
6819 					abox[1] = GET_INT_ARG(2);
6820 					abox[2] = GET_INT_ARG(3);
6821 					abox[3] = GET_INT_ARG(4);
6822 					attack.dropv[0] = default_model_dropv[0];
6823 					attack.dropv[1] = default_model_dropv[1];
6824 					attack.dropv[2] = default_model_dropv[2];
6825 					attack.attack_force = GET_INT_ARG(5);
6826 
6827 					attack.attack_drop = GET_INT_ARG(6);
6828 
6829 					attack.no_block = GET_INT_ARG(7);
6830 					attack.no_flash = GET_INT_ARG(8);
6831 					attack.pause_add = GET_INT_ARG(9);
6832 					attack.attack_coords[4] = GET_INT_ARG(10); // depth or z
6833 
6834 					switch(cmd) {
6835 						case CMD_MODEL_ATTACK: case CMD_MODEL_ATTACK1:
6836 							attack.attack_type = ATK_NORMAL;
6837 							break;
6838 						case CMD_MODEL_ATTACK2:
6839 							attack.attack_type  = ATK_NORMAL2;
6840 							break;
6841 						case CMD_MODEL_ATTACK3:
6842 							attack.attack_type  = ATK_NORMAL3;
6843 							break;
6844 						case CMD_MODEL_ATTACK4:
6845 							attack.attack_type  = ATK_NORMAL4;
6846 							break;
6847 						case CMD_MODEL_ATTACK5:
6848 							attack.attack_type  = ATK_NORMAL5;
6849 							break;
6850 						case CMD_MODEL_ATTACK6:
6851 							attack.attack_type  = ATK_NORMAL6;
6852 							break;
6853 						case CMD_MODEL_ATTACK7:
6854 							attack.attack_type  = ATK_NORMAL7;
6855 							break;
6856 						case CMD_MODEL_ATTACK8:
6857 							attack.attack_type  = ATK_NORMAL8;
6858 							break;
6859 						case CMD_MODEL_ATTACK9:
6860 							attack.attack_type  = ATK_NORMAL9;
6861 							break;
6862 						case CMD_MODEL_ATTACK10:
6863 							attack.attack_type  = ATK_NORMAL10;
6864 							break;
6865 						case CMD_MODEL_SHOCK:
6866 							attack.attack_type  = ATK_SHOCK;
6867 							break;
6868 						case CMD_MODEL_BURN:
6869 							attack.attack_type  = ATK_BURN;
6870 							break;
6871 						case CMD_MODEL_STEAL:
6872 							attack.steal = 1;
6873 							attack.attack_type  = ATK_STEAL;
6874 							break;
6875 						case CMD_MODEL_FREEZE:
6876 							attack.attack_type  = ATK_FREEZE;
6877 							attack.freeze = 1;
6878 							attack.freezetime = GET_FLOAT_ARG(6) * GAME_SPEED;
6879 							attack.forcemap = -1;
6880 							attack.attack_drop = 0;
6881 							break;
6882 						case CMD_MODEL_ITEMBOX:
6883 							attack.attack_type  = ATK_ITEM;
6884 							break;
6885 						default:
6886 							tempInt = atoi(command+6);
6887 							if(tempInt<MAX_ATKS-STA_ATKS+1)
6888 								tempInt = MAX_ATKS-STA_ATKS+1;
6889 							attack.attack_type = tempInt+STA_ATKS-1;
6890 					}
6891 					break;
6892 				case CMD_MODEL_ATTACKZ: case CMD_MODEL_HITZ:
6893 					attack.attack_coords[4] = GET_INT_ARG(1);
6894 					break;
6895 				case CMD_MODEL_BLAST:
6896 					abox[0] = GET_INT_ARG(1);
6897 					abox[1] = GET_INT_ARG(2);
6898 					abox[2] = GET_INT_ARG(3);
6899 					abox[3] = GET_INT_ARG(4);
6900 					attack.dropv[0] = default_model_dropv[0];
6901 					attack.dropv[1] = default_model_dropv[1]*2.083f;
6902 					attack.dropv[2] = 0;
6903 					attack.attack_force = GET_INT_ARG(5);
6904 					attack.no_block = GET_INT_ARG(6);
6905 					attack.no_flash = GET_INT_ARG(7);
6906 					attack.pause_add = GET_INT_ARG(8);
6907 					attack.attack_drop = 1;
6908 					attack.attack_type = ATK_BLAST;
6909 					attack.attack_coords[4] = GET_INT_ARG(9); // depth or z
6910 					attack.blast = 1;
6911 					break;
6912 				case CMD_MODEL_DROPV:
6913 					// drop velocity add if the target is knocked down
6914 					pattack = (!newanim && newchar->smartbomb)?newchar->smartbomb:&attack;
6915 					pattack->dropv[0] = GET_FLOAT_ARG(1); // height add
6916 					pattack->dropv[1] = GET_FLOAT_ARG(2); // xdir add
6917 					pattack->dropv[2] = GET_FLOAT_ARG(3); // zdir add
6918 					break;
6919 				case CMD_MODEL_OTG:
6920 					// Over The Ground hit.
6921 					attack.otg = GET_INT_ARG(1);
6922 					break;
6923 				case CMD_MODEL_JUGGLECOST:
6924 					// if cost >= opponents jugglepoints , we can juggle
6925 					attack.jugglecost = GET_INT_ARG(1);
6926 					break;
6927 				case CMD_MODEL_GUARDCOST:
6928 					// if cost >= opponents guardpoints , opponent will play guardcrush anim
6929 					attack.guardcost = GET_INT_ARG(1);
6930 					break;
6931 				case CMD_MODEL_STUN:
6932 					//Like Freeze, but no auto remap.
6933 					pattack = (!newanim && newchar->smartbomb)?newchar->smartbomb:&attack;
6934 					pattack->freeze = 1;
6935 					pattack->freezetime = GET_FLOAT_ARG(1) * GAME_SPEED;
6936 					pattack->attack_drop = 0;
6937 					break;
6938 				case CMD_MODEL_GRABIN:
6939 					// fake grab distanse efffect, not link
6940 					pattack = (!newanim && newchar->smartbomb)?newchar->smartbomb:&attack;
6941 					pattack->grab =  GET_INT_ARG(1);
6942 					pattack->grab_distance = GET_FLOAT_ARG(2);
6943 					break;
6944 				case CMD_MODEL_NOREFLECT:
6945 					// only cost target's hp, don't knock down or cause pain, unless the target is killed
6946 					pattack = (!newanim && newchar->smartbomb)?newchar->smartbomb:&attack;
6947 					pattack->no_pain = GET_INT_ARG(1);
6948 					break;
6949 				case CMD_MODEL_NOKILL:
6950 					// don't kill the target, leave 1 hp
6951 					pattack = (!newanim && newchar->smartbomb)?newchar->smartbomb:&attack;
6952 					pattack->no_kill = GET_INT_ARG(1);
6953 					break;
6954 				case CMD_MODEL_FORCEDIRECTION:
6955 					// the attack direction
6956 					pattack = (!newanim && newchar->smartbomb)?newchar->smartbomb:&attack;
6957 					pattack->force_direction = GET_INT_ARG(1);
6958 					break;
6959 				case CMD_MODEL_DAMAGEONLANDING:
6960 					// fake throw damage on landing
6961 					pattack = (!newanim && newchar->smartbomb)?newchar->smartbomb:&attack;
6962 					pattack->damage_on_landing = GET_INT_ARG(1);
6963 					pattack->blast = GET_INT_ARG(2);
6964 					break;
6965 				case CMD_MODEL_SEAL:
6966 					// Disable special moves for specified time.
6967 					pattack = (!newanim && newchar->smartbomb)?newchar->smartbomb:&attack;
6968 					pattack->sealtime = GET_INT_ARG(1) * GAME_SPEED;
6969 					pattack->seal = GET_INT_ARG(2);
6970 					break;
6971 				case CMD_MODEL_STAYDOWN:
6972 					// Disable special moves for specified time.
6973 					pattack = (!newanim && newchar->smartbomb)?newchar->smartbomb:&attack;
6974 					pattack->staydown[0]    = GET_INT_ARG(1); //Risetime modifier.
6975 					pattack->staydown[1]    = GET_INT_ARG(2); //Riseattack time addition and toggle.
6976 					break;
6977 				case CMD_MODEL_DOT:
6978 					// Cause damage over time effect.
6979 					attack.dot_index  = GET_INT_ARG(1);  //Index.
6980 					attack.dot_time   = GET_INT_ARG(2);  //Time to expiration.
6981 					attack.dot        = GET_INT_ARG(3);  //Mode, see common_dot.
6982 					attack.dot_force  = GET_INT_ARG(4);  //Amount per tick.
6983 					attack.dot_rate   = GET_INT_ARG(5);  //Tick delay.
6984 					break;
6985 				case CMD_MODEL_FORCEMAP:
6986 					// force color map change for specified time
6987 					pattack = (!newanim && newchar->smartbomb)?newchar->smartbomb:&attack;
6988 					pattack->forcemap = GET_INT_ARG(1);
6989 					pattack->maptime = GET_FLOAT_ARG(2) * GAME_SPEED;
6990 					break;
6991 				case CMD_MODEL_IDLE:
6992 					idle = GET_INT_ARG(1);
6993 					break;
6994 				case CMD_MODEL_MOVE:
6995 					move = GET_INT_ARG(1);
6996 					break;
6997 				case CMD_MODEL_MOVEZ:
6998 					movez = GET_INT_ARG(1);
6999 					break;
7000 				case CMD_MODEL_MOVEA:
7001 					movea = GET_INT_ARG(1);
7002 					break;
7003 				case CMD_MODEL_SETA:
7004 					seta = GET_INT_ARG(1);
7005 					break;
7006 				case CMD_MODEL_FSHADOW:
7007 					frameshadow = GET_INT_ARG(1);
7008 					break;
7009 				case CMD_MODEL_RANGE:
7010 					if(!newanim) {
7011 						shutdownmessage = "Cannot set range: no animation!";
7012 						goto lCleanup;
7013 					}
7014 					newanim->range.xmin = GET_INT_ARG(1);
7015 					newanim->range.xmax = GET_INT_ARG(2);
7016 					if(newanim->range.xmin==newanim->range.xmax)
7017 						newanim->range.xmin--;
7018 					break;
7019 				case CMD_MODEL_RANGEZ:
7020 					if(!newanim) {
7021 						shutdownmessage = "Cannot set rangez: no animation!";
7022 						goto lCleanup;
7023 					}
7024 					newanim->range.zmin = GET_INT_ARG(1);
7025 					newanim->range.zmax = GET_INT_ARG(2);
7026 					break;
7027 				case CMD_MODEL_RANGEA:
7028 					if(!newanim) {
7029 						shutdownmessage = "Cannot set rangea: no animation!";
7030 						goto lCleanup;
7031 					}
7032 					newanim->range.amin = GET_INT_ARG(1);
7033 					newanim->range.amax = GET_INT_ARG(2);
7034 					break;
7035 				case CMD_MODEL_RANGEB:
7036 					if(!newanim) {
7037 						shutdownmessage = "Cannot set rangeb: no animation!";
7038 						goto lCleanup;
7039 					}
7040 					newanim->range.bmin = GET_INT_ARG(1);
7041 					newanim->range.bmax = GET_INT_ARG(2);
7042 					break;
7043 				case CMD_MODEL_PATHFINDSTEP:
7044 					newchar->pathfindstep = GET_FLOAT_ARG(1);
7045 					break;
7046 				case CMD_MODEL_FRAME:
7047 					{
7048 						if(!newanim) {
7049 							shutdownmessage = "Cannot add frame: animation not specified!";
7050 							goto lCleanup;
7051 						}
7052 						peek = 0;
7053 						if(frameset && framecount>=0) framecount = -framecount;
7054 						while(!frameset){
7055 							value3 = findarg(buf+pos+peek, 0);
7056 							if(stricmp(value3, "frame")==0) framecount++;
7057 							if((stricmp(value3, "anim")==0) || (pos+peek >= size)) frameset = 1;
7058 							// Go to next line
7059 							while(buf[pos+peek] && buf[pos+peek]!='\n' && buf[pos+peek]!='\r') ++peek;
7060 							while(buf[pos+peek]=='\n' || buf[pos+peek]=='\r') ++peek;
7061 						}
7062 						value = GET_ARG(1);
7063 						//printf("frame count: %d\n",framecount);
7064 						//printf("Load sprite '%s'...\n", value);
7065 						index = loadsprite(value, offset[0], offset[1],nopalette?PIXEL_x8:PIXEL_8);//don't use palette for the sprite since it will one palette from the entity's remap list in 24bit mode
7066 						if(pixelformat==PIXEL_x8 && !nopalette)
7067 						{
7068 							// for old mod just give it a default palette
7069 							if(newchar->palette==NULL)
7070 							{
7071 								newchar->palette = malloc(PAL_BYTES);
7072 								if(loadimagepalette(value, packfile, newchar->palette)==0) {
7073 									shutdownmessage = "Failed to load palette!";
7074 									goto lCleanup;
7075 								}
7076 							}
7077 							if(index>=0 && !nopalette)
7078 							{
7079 								sprite_map[index].node->sprite->palette = newchar->palette;
7080 								sprite_map[index].node->sprite->pixelformat = pixelformat;
7081 							}
7082 						}
7083 						if((index>=0) && (maskindex>=0))
7084 						{
7085 							sprite_map[index].node->sprite->mask = sprite_map[maskindex].node->sprite;
7086 							maskindex = -1;
7087 						}
7088 						// Adjust coords: add offsets and change size to coords
7089 						bbox_con[0] = bbox[0] - offset[0];
7090 						bbox_con[1] = bbox[1] - offset[1];
7091 						bbox_con[2] = bbox[2] + bbox_con[0];
7092 						bbox_con[3] = bbox[3] + bbox_con[1];
7093 						bbox_con[4] = bbox[4];
7094 						attack.attack_coords[0] = abox[0] - offset[0];
7095 						attack.attack_coords[1] = abox[1] - offset[1];
7096 						attack.attack_coords[2] = abox[2] + attack.attack_coords[0];
7097 						attack.attack_coords[3] = abox[3] + attack.attack_coords[1];
7098 						//attack.attack_coords[4] = abox[4];
7099 						if(platform[0]==99999) // old style
7100 						{
7101 							platform_con[0] = 0;
7102 							platform_con[1] = 3;
7103 							platform_con[2] = platform[2] - offset[0];
7104 							platform_con[3] = platform[3] - offset[0];
7105 							platform_con[4] = platform[4] - offset[0];
7106 							platform_con[5] = platform[5] - offset[0];
7107 							platform_con[6] = platform[6]+3;
7108 						}
7109 						else // wall style
7110 						{
7111 							platform_con[0] = platform[0] - offset[0];
7112 							platform_con[1] = platform[1] - offset[1];
7113 							platform_con[2] = platform[2];
7114 							platform_con[3] = platform[3];
7115 							platform_con[4] = platform[4];
7116 							platform_con[5] = platform[5];
7117 							platform_con[6] = platform[6];
7118 						}
7119 						platform_con[6] = platform[6];
7120 						platform_con[7] = platform[7];
7121 						if(shadow_set)
7122 						{
7123 							shadow_coords[0] = shadow_xz[0] - offset[0];
7124 							shadow_coords[1] = shadow_xz[1] - offset[1];
7125 						}
7126 						else
7127 						{
7128 							shadow_coords[0] = shadow_coords[1] = 0;
7129 						}
7130 
7131 						curframe = addframe(newanim, index, framecount, delay, (unsigned char)idle,
7132 								bbox_con, &attack, move, movez,
7133 								movea, seta, platform_con, frameshadow, shadow_coords, soundtoplay, &drawmethod);
7134 
7135 								memset(bbox_con, 0, sizeof(bbox_con));
7136 								soundtoplay = -1;
7137 					}
7138 					break;
7139 				case CMD_MODEL_ALPHAMASK:
7140 					if(!newanim){
7141 						shutdownmessage = "Cannot add alpha mask: animation not specified!";
7142 						goto lCleanup;
7143 					}
7144 					if(maskindex>=0) {
7145 						shutdownmessage = "Cannot add alpha mask: a mask has already been specified for this frame!";
7146 						goto lCleanup;
7147 					}
7148 					value = GET_ARG(1);
7149 					//printf("frame count: %d\n",framecount);
7150 					//printf("Load sprite '%s'...\n", value);
7151 					index = loadsprite(value, offset[0], offset[1],PIXEL_8);//don't use palette for the mask
7152 					maskindex = index;
7153 					break;
7154 				case CMD_MODEL_FLIPFRAME:
7155 					newanim->flipframe = GET_FRAME_ARG(1);
7156 					break;
7157 				case CMD_MODEL_FOLLOWANIM:
7158 					newanim->followanim = GET_INT_ARG(1);
7159 					if(newanim->followanim > max_follows) newanim->followanim = max_follows;
7160 					if(newanim->followanim < 0) newanim->followanim = 0;
7161 					break;
7162 				case CMD_MODEL_FOLLOWCOND:
7163 					newanim->followcond = GET_INT_ARG(1);
7164 					break;
7165 				case CMD_MODEL_COUNTERFRAME:
7166 					newanim->counterrange.framestart    = GET_FRAME_ARG(1);
7167 					newanim->counterrange.frameend	    = newanim->counterrange.framestart;
7168 					newanim->counterrange.condition	    = GET_INT_ARG(2);
7169 					newanim->counterrange.damaged	    = GET_INT_ARG(3);
7170 					break;
7171 				case CMD_MODEL_COUNTERRANGE:
7172 					newanim->counterrange.framestart	= GET_FRAME_ARG(1);
7173 					newanim->counterrange.frameend	    = GET_FRAME_ARG(2);
7174 					newanim->counterrange.condition	    = GET_INT_ARG(3);
7175 					newanim->counterrange.damaged	    = GET_INT_ARG(4);
7176 					break;
7177 				case CMD_MODEL_WEAPONFRAME:
7178 					newanim->weaponframe    = malloc(2 * sizeof(newanim->weaponframe));
7179 					memset(newanim->weaponframe, 0, 2 * sizeof(newanim->weaponframe));
7180 					newanim->weaponframe[0] = GET_FRAME_ARG(1);
7181 					newanim->weaponframe[1] = GET_INT_ARG(2);
7182 					break;
7183 				case CMD_MODEL_QUAKEFRAME:
7184 					newanim->quakeframe.framestart  = GET_FRAME_ARG(1);
7185 					newanim->quakeframe.repeat      = GET_INT_ARG(2);
7186 					newanim->quakeframe.v           = GET_INT_ARG(3);
7187 					newanim->quakeframe.cnt         = 0;
7188 					break;
7189 				case CMD_MODEL_SUBENTITY: case CMD_MODEL_CUSTENTITY:
7190 					value = GET_ARG(1);
7191 					if(value[0]) newanim->subentity = get_cached_model_index(value);
7192 					break;
7193 				case CMD_MODEL_SPAWNFRAME:
7194 					newanim->spawnframe    = malloc(5 * sizeof(newanim->spawnframe));
7195 					memset(newanim->spawnframe, 0, 5 * sizeof(newanim->spawnframe));
7196 					newanim->spawnframe[0] = GET_FRAME_ARG(1);
7197 					newanim->spawnframe[1] = GET_FLOAT_ARG(2);
7198 					newanim->spawnframe[2] = GET_FLOAT_ARG(3);
7199 					newanim->spawnframe[3] = GET_FLOAT_ARG(4);
7200 					newanim->spawnframe[4] = GET_FLOAT_ARG(5);
7201 					break;
7202 				case CMD_MODEL_SUMMONFRAME:
7203 					newanim->summonframe    = malloc(5 * sizeof(newanim->summonframe));
7204 					memset(newanim->summonframe, 0, 5 * sizeof(newanim->summonframe));
7205 					newanim->summonframe[0] = GET_FRAME_ARG(1);
7206 					newanim->summonframe[1] = GET_FLOAT_ARG(2);
7207 					newanim->summonframe[2] = GET_FLOAT_ARG(3);
7208 					newanim->summonframe[3] = GET_FLOAT_ARG(4);
7209 					newanim->summonframe[4] = GET_FLOAT_ARG(5);
7210 					break;
7211 				case CMD_MODEL_UNSUMMONFRAME:
7212 					newanim->unsummonframe = GET_FRAME_ARG(1);
7213 					break;
7214 				case CMD_MODEL_AT_SCRIPT:
7215 					if(!scriptbuf[0]){ // if empty, paste the main function text here
7216 						buffer_append(&scriptbuf, pre_text, 0xffffff, &sbsize, &scriptlen);
7217 					}
7218 					scriptbuf[scriptlen - strlen(sur_text)] = 0; // cut last chars
7219 					scriptlen = strlen(scriptbuf);
7220 					if(ani_id>=0)
7221 					{
7222 						if(script_id != ani_id){ // if expression 1
7223 							sprintf(namebuf, ifid_text, newanim->index);
7224 							buffer_append(&scriptbuf, namebuf, 0xffffff, &sbsize, &scriptlen);
7225 							script_id = ani_id;
7226 						}
7227 						scriptbuf[scriptlen - strlen(endifid_text)] = 0; // cut last chars
7228 						scriptlen = strlen(scriptbuf);
7229 					}
7230 					while(strncmp(buf+pos, "@script", 7)){
7231 						pos++;
7232 					}
7233 					pos += 7;
7234 					len = 0;
7235 					while(strncmp(buf+pos, "@end_script", 11)){
7236 						len++; pos++;
7237 					}
7238 					buffer_append(&scriptbuf, buf+pos-len, len, &sbsize, &scriptlen);
7239 					pos += 11;
7240 
7241 					if(ani_id>=0)
7242 					{
7243 						buffer_append(&scriptbuf, endifid_text, 0xffffff, &sbsize, &scriptlen);// put back last  chars
7244 					}
7245 					buffer_append(&scriptbuf, sur_text, 0xffffff, &sbsize, &scriptlen);// put back last  chars
7246 					break;
7247 				case CMD_MODEL_AT_CMD:
7248 					//translate @cmd into script function call
7249 					if(ani_id < 0) {
7250 						shutdownmessage = "command '@cmd' must follow an animation!";
7251 						goto lCleanup;
7252 					}
7253 					if(!scriptbuf[0]){ // if empty, paste the main function text here
7254 						buffer_append(&scriptbuf, pre_text, 0xffffff, &sbsize, &scriptlen);
7255 					}
7256 					scriptbuf[scriptlen - strlen(sur_text)] = 0; // cut last chars
7257 					scriptlen = strlen(scriptbuf);
7258 					if(script_id != ani_id){ // if expression 1
7259 						sprintf(namebuf, ifid_text, newanim->index);
7260 						buffer_append(&scriptbuf, namebuf, 0xffffff, &sbsize, &scriptlen);
7261 						script_id = ani_id;
7262 					}
7263 					j = 1;
7264 					value = GET_ARG(j);
7265 					scriptbuf[scriptlen - strlen(endifid_text)] = 0; // cut last chars
7266 					scriptlen = strlen(scriptbuf);
7267 					if(value && value[0]){
7268 						sprintf(namebuf, if_text, curframe);//only execute in current frame
7269 						buffer_append(&scriptbuf, namebuf, 0xffffff, &sbsize, &scriptlen);
7270 						sprintf(namebuf, call_text, value);
7271 						buffer_append(&scriptbuf, namebuf, 0xffffff, &sbsize, &scriptlen);
7272 						do{ //argument and comma
7273 							j++;
7274 							value = GET_ARG(j);
7275 							if(value && value[0]) {
7276 								if(j!=2) buffer_append(&scriptbuf, comma_text, 0xffffff, &sbsize, &scriptlen);
7277 								buffer_append(&scriptbuf, value, 0xffffff, &sbsize, &scriptlen);
7278 							}
7279 						}while(value && value[0]);
7280 					}
7281 					buffer_append(&scriptbuf, endcall_text, 0xffffff, &sbsize, &scriptlen);
7282 					buffer_append(&scriptbuf, endif_text, 0xffffff, &sbsize, &scriptlen);//end of if
7283 					buffer_append(&scriptbuf, endifid_text, 0xffffff, &sbsize, &scriptlen); // put back last  chars
7284 					buffer_append(&scriptbuf, sur_text, 0xffffff, &sbsize, &scriptlen); // put back last  chars
7285 					break;
7286 				default:
7287 					if(command && command[0]) {
7288 						if(!handle_txt_include(command, &arglist, &filename, fnbuf, &buf, &pos, &size))
7289 							printf("Command '%s' not understood in file '%s'!\n", command, filename);
7290 					}
7291 			}
7292 
7293 		}
7294 		// Go to next line
7295 		pos += getNewLineStart(buf + pos);
7296 	}
7297 
7298 
7299 	tempInt = 1;
7300 	if(scriptbuf[0]) {
7301 		//printf("\n%s\n", scriptbuf);
7302 		if(!Script_IsInitialized(newchar->scripts->animation_script))
7303 			Script_Init(newchar->scripts->animation_script, newchar->name, filename, 0);
7304 		tempInt = Script_AppendText(newchar->scripts->animation_script, scriptbuf, filename);
7305 		//Interpreter_OutputPCode(newchar->scripts->animation_script.pinterpreter, "code");
7306 		writeToScriptLog("\n####animationscript function main#####\n# ");
7307 		writeToScriptLog(filename);
7308 		writeToScriptLog("\n########################################\n");
7309 		writeToScriptLog(scriptbuf);
7310 	}
7311 	if(!newchar->isSubclassed)
7312 		Script_Compile(newchar->scripts->animation_script);
7313 
7314 	if(!tempInt)// parse script failed
7315 	{
7316 		shutdownmessage = "Error parsing function main of animation script in file '%s'!";
7317 		goto lCleanup;
7318 	}
7319 
7320 	// We need a little more work to initialize the new A.I. types if they are not loaded from file
7321 	if(newchar->aiattack==-1) newchar->aiattack = 0;
7322 	if(newchar->aimove==-1) newchar->aimove = 0;
7323 	//if(!newchar->offscreenkill) newchar->offscreenkill = 1000;
7324 
7325 	//temporary patch for conflicting moves
7326 	if(newchar->animation[ANI_FREESPECIAL] && !is_set(newchar, ANI_FREESPECIAL))
7327 	{
7328 		alloc_specials(newchar);
7329 		newchar->special[newchar->specials_loaded].input[0] = FLAG_FORWARD;
7330 		newchar->special[newchar->specials_loaded].input[1] = FLAG_FORWARD;
7331 		newchar->special[newchar->specials_loaded].input[2] = FLAG_ATTACK;
7332 		newchar->special[newchar->specials_loaded].anim = ANI_FREESPECIAL;
7333 		newchar->special[newchar->specials_loaded].steps = 3;
7334 		newchar->specials_loaded++;
7335 	}
7336 	if(newchar->animation[ANI_FREESPECIAL2] && !is_set(newchar, ANI_FREESPECIAL2))
7337 	{
7338 		alloc_specials(newchar);
7339 		newchar->special[newchar->specials_loaded].input[0] = FLAG_MOVEDOWN;
7340 		newchar->special[newchar->specials_loaded].input[1] = FLAG_MOVEDOWN;
7341 		newchar->special[newchar->specials_loaded].input[2] = FLAG_ATTACK;
7342 		newchar->special[newchar->specials_loaded].anim = ANI_FREESPECIAL2;
7343 		newchar->special[newchar->specials_loaded].steps = 3;
7344 		newchar->specials_loaded++;
7345 	}
7346 	if(newchar->animation[ANI_FREESPECIAL3] && !is_set(newchar, ANI_FREESPECIAL3))
7347 	{
7348 		alloc_specials(newchar);
7349 		newchar->special[newchar->specials_loaded].input[0] = FLAG_MOVEUP;
7350 		newchar->special[newchar->specials_loaded].input[1] = FLAG_MOVEUP;
7351 		newchar->special[newchar->specials_loaded].input[2] = FLAG_ATTACK;
7352 		newchar->special[newchar->specials_loaded].anim = ANI_FREESPECIAL3;
7353 		newchar->special[newchar->specials_loaded].steps = 3;
7354 		newchar->specials_loaded++;
7355 	}
7356 
7357 	if(newchar->risetime[0]==-1)
7358 	{
7359 		if(newchar->type==TYPE_PLAYER)
7360 		{
7361 			if(newchar->animation[ANI_RISEATTACK]) newchar->risetime[0] = GAME_SPEED/2;
7362 			else newchar->risetime[0]=GAME_SPEED;
7363 		}
7364 		else if(newchar->type==TYPE_ENEMY || newchar->type==TYPE_NPC)
7365 		{
7366 			newchar->risetime[0] = 0;
7367 		}
7368 	}
7369 
7370 	if(newchar->hostile<0) {// not been initialized, so initialize it
7371 		switch (newchar->type){
7372 		case TYPE_ENEMY:
7373 			newchar->hostile = TYPE_PLAYER ;
7374 			break;
7375 		case TYPE_PLAYER: // dont really needed, since you don't need A.I. control for players
7376 			newchar->hostile = TYPE_PLAYER | TYPE_ENEMY | TYPE_OBSTACLE;
7377 			break;
7378 		case TYPE_TRAP:
7379 			newchar->hostile  = TYPE_ENEMY | TYPE_PLAYER;
7380 		case TYPE_OBSTACLE:
7381 			newchar->hostile = 0;
7382 			break;
7383 		case TYPE_SHOT:  // only target enemies
7384 			newchar->hostile = TYPE_ENEMY ;
7385 			break;
7386 		case TYPE_NPC: // default npc behivior
7387 			newchar->hostile = TYPE_ENEMY ;
7388 			break;
7389 		}
7390 	}
7391 
7392 	if(newchar->candamage<0) {// not been initialized, so initialize it
7393 		switch (newchar->type){
7394 		case TYPE_ENEMY:
7395 			newchar->candamage = TYPE_PLAYER | TYPE_SHOT;
7396 			if(newchar->subtype == SUBTYPE_ARROW) newchar->candamage |= TYPE_OBSTACLE;
7397 			break;
7398 		case TYPE_PLAYER:
7399 			newchar->candamage = TYPE_PLAYER | TYPE_ENEMY | TYPE_OBSTACLE;
7400 			break;
7401 		case TYPE_TRAP:
7402 			newchar->candamage  = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE;
7403 		case TYPE_OBSTACLE:
7404 			newchar->candamage = TYPE_PLAYER | TYPE_ENEMY | TYPE_OBSTACLE;
7405 			break;
7406 		case TYPE_SHOT:
7407 			newchar->candamage = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE;
7408 			break;
7409 		case TYPE_NPC:
7410 			newchar->candamage = TYPE_ENEMY | TYPE_OBSTACLE;
7411 			break;
7412 		case TYPE_ITEM:
7413 			newchar->candamage = TYPE_PLAYER;
7414 			break;
7415 		}
7416 	}
7417 
7418 	if(newchar->projectilehit<0) {// not been initialized, so initialize it
7419 		switch (newchar->type){
7420 		case TYPE_ENEMY:
7421 			newchar->projectilehit = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE;
7422 			break;
7423 		case TYPE_PLAYER:
7424 			newchar->projectilehit = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE;
7425 			break;
7426 		case TYPE_TRAP: // hmm, don't really needed
7427 			newchar->projectilehit  = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE;
7428 		case TYPE_OBSTACLE: // hmm, don't really needed
7429 			newchar->projectilehit = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE;
7430 			break;
7431 		case TYPE_SHOT: // hmm, don't really needed
7432 			newchar->projectilehit = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE;
7433 			break;
7434 		case TYPE_NPC:
7435 			newchar->projectilehit = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE;
7436 			break;
7437 		}
7438 	}
7439 
7440 	if(newchar->jumpspeed < 0) newchar->jumpspeed = MAX(newchar->speed, 1);
7441 
7442 	if(blendfx_is_set==0)
7443 	{
7444 		if(newchar->alpha)
7445 		{
7446 			blendfx[newchar->alpha-1] = 1;
7447 		}
7448 		if(newchar->gfxshadow || newchar->shadow)
7449 		{
7450 			blendfx[BLEND_MULTIPLY] = 1;
7451 		}
7452 	}
7453 
7454 	// we need to convert 8bit colourmap into 24bit palette
7455 	if(pixelformat==PIXEL_x8)
7456 	{
7457 		convert_map_to_palette(newchar, mapflag);
7458 	}
7459 
7460 	printf("Loading '%s' from %s\n", newchar->name, filename);
7461 
7462 	lCleanup:
7463 
7464 	if(buf != NULL){
7465 		free(buf);
7466 		buf = NULL;
7467 	}
7468 	if(scriptbuf){
7469 		free(scriptbuf);
7470 		scriptbuf = NULL;
7471 	}
7472 
7473 	if(!shutdownmessage)
7474 		return newchar;
7475 
7476 	shutdown(1, "Fatal Error in load_cached_model, file: %s, line %d, message: %s\n", filename, line, shutdownmessage);
7477 	return NULL;
7478 }
7479 
7480 
7481 
is_set(s_model * model,int m)7482 int is_set(s_model * model, int m){    // New function to determine if a freespecial has been set
7483 	int i;
7484 
7485 	for(i = 0; i < model->specials_loaded; i++){
7486 		if(model->special[i].anim == m){
7487 			return 1;
7488 		}
7489 	}
7490 
7491 	return 0;
7492 }
7493 
load_script_setting()7494 int load_script_setting()
7495 {
7496 	char * filename = "data/script.txt";
7497 	char *buf, *command;
7498 	ptrdiff_t pos = 0;
7499 	size_t size = 0;
7500 	ArgList arglist;
7501 	char argbuf[MAX_ARG_LEN+1] = "";
7502 
7503 	if(buffer_pakfile(filename, &buf, &size)!=1) return 0;
7504 
7505 	while(pos<size)
7506 	{
7507 		if(ParseArgs(&arglist,buf+pos,argbuf)){
7508 			command = GET_ARG(0);
7509 			if(command && command[0])
7510 			{
7511 				if(stricmp(command, "maxscriptvars")==0) // each script can have a variable list that can be accessed by index
7512 				{
7513 					max_script_vars = GET_INT_ARG(1) ;
7514 					if(max_script_vars<0) max_script_vars = 0;
7515 				}
7516 				else if(stricmp(command, "maxentityvars")==0) // each entity can have a variable list that can be accessed by index
7517 				{
7518 					max_entity_vars = GET_INT_ARG(1) ;
7519 					if(max_entity_vars<0) max_entity_vars = 0;
7520 				}
7521 				else if(stricmp(command, "maxindexedvars")==0) // a global variable list that can be accessed by index
7522 				{
7523 					max_indexed_vars = GET_INT_ARG(1);
7524 					if(max_indexed_vars<0) max_indexed_vars = 0;
7525 				}
7526 				else if(stricmp(command, "maxglobalvars")==0) // for global_var_list, default to 2048
7527 				{
7528 					max_global_vars = GET_INT_ARG(1);
7529 					if(max_global_vars<0) max_global_vars = 0;
7530 				}
7531 				else if(stricmp(command, "keyscriptrate")==0) // Rate that keyscripts fire when holding a key.
7532 				{
7533 					keyscriptrate = GET_INT_ARG(1);
7534 				}
7535 				else if(stricmp(command, "alwaysupdate")==0) //execute update script whenever update() is called
7536 				{
7537 					alwaysupdate = GET_INT_ARG(1);
7538 				}
7539 			}
7540 		}
7541 		// Go to next line
7542 	pos += getNewLineStart(buf + pos);
7543 	}
7544 
7545 	if(buf != NULL)
7546 	{
7547 		free(buf);
7548 		buf = NULL;
7549 	}
7550 	return 1;
7551 }
7552 
7553 // Load / cache all models
load_models()7554 int load_models()
7555 {
7556 	char filename[128] = "data/models.txt";
7557 	int i;
7558 	char *buf;
7559 	size_t size;
7560 	ptrdiff_t pos;
7561 	char * command;
7562 	int line = 0;
7563 
7564 	char tmpBuff[128] = {""};
7565 	int maxanim = MAX_ANIS; // temporary counter
7566 
7567 	ArgList arglist;
7568 	char argbuf[MAX_ARG_LEN+1] = "";
7569 	modelstxtCommands cmd;
7570 	int modelLoadCount = 0;
7571 
7572 	free_modelcache();
7573 
7574 	if(isLoadingScreenTypeBg(loadingbg[0].set)) {
7575 		// New alternative background path for PSP
7576 		if(custBkgrds != NULL)
7577 		{
7578 			strcpy(tmpBuff,custBkgrds);
7579 			strncat(tmpBuff,"loading", 7);
7580 			load_background(tmpBuff, 0);
7581 		}
7582 		else load_background("data/bgs/loading", 0);
7583 		standard_palette(1);
7584 	}
7585 	if(isLoadingScreenTypeBar(loadingbg[0].set)) {
7586 		lifebar_colors();
7587 		init_colourtable();
7588 	}
7589 
7590 	update_loading(&loadingbg[0], -1, 1); // initialize the update screen
7591 
7592 	// reload default values
7593 	max_idles        = MAX_IDLES;
7594 	max_walks        = MAX_WALKS;
7595 	max_ups          = MAX_UPS;
7596 	max_downs        = MAX_DOWNS;
7597 	max_backwalks    = MAX_BACKWALKS;
7598 	max_attack_types = MAX_ATKS;
7599 	max_freespecials = MAX_SPECIALS;
7600 	max_follows      = MAX_FOLLOWS;
7601 	max_attacks      = MAX_ATTACKS;
7602 	max_animations   = MAX_ANIS;
7603 
7604 	// free old values
7605 	if(animspecials){free(animspecials); animspecials = NULL;}
7606 	if(animattacks){free(animattacks);  animattacks = NULL;}
7607 	if(animfollows){free(animfollows);  animfollows = NULL;}
7608 	if(animpains){free(animpains);    animpains = NULL;}
7609 	if(animfalls){free(animfalls);    animfalls = NULL;}
7610 	if(animrises){free(animrises);    animrises = NULL;}
7611 	if(animriseattacks){free(animriseattacks);    animriseattacks = NULL;}
7612 	if(animblkpains) {free(animblkpains); animblkpains = NULL;}
7613 	if(animdies){free(animdies);     animdies = NULL;}
7614 	if(animwalks){free(animwalks);     animwalks = NULL;}
7615 	if(animbackwalks){free(animbackwalks);     animbackwalks = NULL;}
7616 	if(animidles){free(animidles);     animidles = NULL;}
7617 	if(animups){free(animups);     animups = NULL;}
7618 	if(animdowns){free(animdowns);     animdowns = NULL;}
7619 
7620 	if(custModels != NULL)
7621 	{
7622 		strcpy(filename, "data/");
7623 		strcat(filename, custModels);
7624 	}
7625 
7626 	// Read file
7627 	if(buffer_pakfile(filename, &buf, &size)!=1) shutdown(1, "Error loading model list from %s", filename);
7628 
7629 	pos = 0;
7630 	while(pos<size) // peek global settings
7631 	{
7632 		line++;
7633 		if(ParseArgs(&arglist,buf+pos,argbuf)){
7634 			command = GET_ARG(0);
7635 			cmd = getModelCommand(modelstxtcmdlist, command);
7636 			switch(cmd) {
7637 				case CMD_MODELSTXT_MAXIDLES:
7638 					// max idle stances
7639 					max_idles = GET_INT_ARG(1);
7640 					if(max_idles < MAX_IDLES) max_idles = MAX_IDLES;
7641 					break;
7642 				case CMD_MODELSTXT_MAXWALKS:
7643 					max_walks = GET_INT_ARG(1);
7644 					if(max_walks < MAX_WALKS) max_walks = MAX_WALKS;
7645 					break;
7646 				case CMD_MODELSTXT_MAXBACKWALKS:
7647 					// max backward walks
7648 					max_backwalks = GET_INT_ARG(1);
7649 					if(max_backwalks < MAX_BACKWALKS) max_backwalks = MAX_BACKWALKS;
7650 					break;
7651 				case CMD_MODELSTXT_MAXUPS:
7652 					// max up walks
7653 					max_ups = GET_INT_ARG(1);
7654 					if(max_ups < MAX_UPS) max_ups = MAX_UPS;
7655 					break;
7656 				case CMD_MODELSTXT_MAXDOWNS:
7657 					// max down walks
7658 					max_downs = GET_INT_ARG(1);
7659 					if(max_downs < MAX_DOWNS) max_downs = MAX_DOWNS;
7660 					break;
7661 				case CMD_MODELSTXT_MAXATTACKTYPES:
7662 					// max attacktype/pain/fall/die
7663 					max_attack_types = GET_INT_ARG(1) + STA_ATKS;
7664 					if(max_attack_types < MAX_ATKS) max_attack_types = MAX_ATKS;
7665 					break;
7666 				case CMD_MODELSTXT_MAXFOLLOWS:
7667 					// max follow-ups
7668 					max_follows = GET_INT_ARG(1);
7669 					if(max_follows<MAX_FOLLOWS) max_follows = MAX_FOLLOWS;
7670 					break;
7671 				case CMD_MODELSTXT_MAXFREESPECIALS:
7672 					// max freespecials
7673 					max_freespecials = GET_INT_ARG(1);
7674 					if(max_freespecials<MAX_SPECIALS) max_freespecials = MAX_SPECIALS;
7675 					break;
7676 				case CMD_MODELSTXT_MAXATTACKS:
7677 					max_attacks = GET_INT_ARG(1);
7678 					if(max_attacks<MAX_ATTACKS) max_attacks = MAX_ATTACKS;
7679 					break;
7680 				case CMD_MODELSTXT_COMBODELAY:
7681 					combodelay = GET_INT_ARG(1);
7682 					break;
7683 				case CMD_MODELSTXT_MUSIC:
7684 					music(GET_ARG(1), 1, atol(GET_ARG(2)));
7685 					break;
7686 				case CMD_MODELSTXT_LOAD:
7687 					// Add path to cache list
7688 					modelLoadCount++;
7689 					cache_model(GET_ARG(1), GET_ARG(2), 1);
7690 					break;
7691 				case CMD_MODELSTXT_COLOURSELECT:
7692 					// 6-2-2005 if string for colourselect found
7693 					colourselect =  GET_INT_ARG(1);          //  6-2-2005
7694 					break;
7695 				case CMD_MODELSTXT_SPDIRECTION:
7696 					// Select Player Direction for select player screen
7697 					spdirection[0] =  GET_INT_ARG(1);
7698 					spdirection[1] =  GET_INT_ARG(2);
7699 					spdirection[2] =  GET_INT_ARG(3);
7700 					spdirection[3] =  GET_INT_ARG(4);
7701 					break;
7702 				case CMD_MODELSTXT_AUTOLAND:
7703 					// New flag to determine if a player auto lands when thrown by another player (2 completely disables the ability to land)
7704 					autoland = GET_INT_ARG(1);
7705 					break;
7706 				case CMD_MODELSTXT_NOLOST:
7707 					// this is use for dont lost your weapon if you grab a enemy flag it to 1 to no drop by tails
7708 					nolost = GET_INT_ARG(1);
7709 					break;
7710 				case CMD_MODELSTXT_AJSPECIAL:
7711 					// Flag to determine if a + j executes special
7712 					ajspecial = GET_INT_ARG(1);
7713 					break;
7714 				case CMD_MODELSTXT_NOCOST:
7715 					// Nocost set in models.txt
7716 					nocost = GET_INT_ARG(1);
7717 					break;
7718 				case CMD_MODELSTXT_NOCHEATS:
7719 					//disable cheat option in menu
7720 					forcecheatsoff =  GET_INT_ARG(1);
7721 					break;
7722 				case CMD_MODELSTXT_NODROPEN:
7723 					nodropen = 1;
7724 					break;
7725 				case CMD_MODELSTXT_NODROPSPAWN:
7726 					nodropspawn = 1;
7727 					break;
7728 				case CMD_MODELSTXT_KNOW:
7729 					// Just add path to cache list
7730 					cache_model(GET_ARG(1), GET_ARG(2), 0);
7731 					break;
7732 				case CMD_MODELSTXT_NOAIRCANCEL:
7733 					noaircancel = GET_INT_ARG(1);
7734 					break;
7735 				case CMD_MODELSTXT_NOMAXRUSHRESET:
7736 					nomaxrushreset[4] = GET_INT_ARG(1);
7737 					break;
7738 				case CMD_MODELSTXT_MPBLOCK:
7739 					// Take from MP first?
7740 					mpblock = GET_INT_ARG(1);
7741 					break;
7742 				case CMD_MODELSTXT_BLOCKRATIO:
7743 					// Nullify or reduce damage?
7744 					blockratio = GET_INT_ARG(1);
7745 					break;
7746 				case CMD_MODELSTXT_NOCHIPDEATH:
7747 					nochipdeath = GET_INT_ARG(1);
7748 					break;
7749 				case CMD_MODELSTXT_LIFESCORE:
7750 					lifescore =  GET_INT_ARG(1);
7751 					break;
7752 				case CMD_MODELSTXT_CREDSCORE:
7753 					// Number of points needed to earn a 1-up
7754 					credscore =  GET_INT_ARG(1);
7755 					break;
7756 				case CMD_MODELSTXT_VERSUSDAMAGE:
7757 					// Number of points needed to earn a credit
7758 					versusdamage =  GET_INT_ARG(1);
7759 					if(versusdamage == 0 || versusdamage == 1) savedata.mode = versusdamage^1;
7760 					break;
7761 				case CMD_MODELSTXT_DROPV:
7762 					default_model_dropv[0] =  GET_FLOAT_ARG(1);
7763 					default_model_dropv[1] =  GET_FLOAT_ARG(2);
7764 					default_model_dropv[2] =  GET_FLOAT_ARG(3);
7765 					break;
7766 				case CMD_MODELSTXT_JUMPSPEED:
7767 					default_model_jumpspeed =  GET_FLOAT_ARG(1);
7768 					break;
7769 				case CMD_MODELSTXT_JUMPHEIGHT:
7770 					default_model_jumpheight =  GET_FLOAT_ARG(1);
7771 					break;
7772 				case CMD_MODELSTXT_GRABDISTANCE:
7773 					default_model_grabdistance =  GET_FLOAT_ARG(1);
7774 					break;
7775 				case CMD_MODELSTXT_DEBUG_MNAF:
7776 					move_noatk_factor =  GET_FLOAT_ARG(1);
7777 					break;
7778 				case CMD_MODELSTXT_DEBUG_GNAF:
7779 					group_noatk_factor =  GET_FLOAT_ARG(1);
7780 					break;
7781 				case CMD_MODELSTXT_DEBUG_ANAF:
7782 					agg_noatk_factor =  GET_FLOAT_ARG(1);
7783 					break;
7784 				case CMD_MODELSTXT_DEBUG_MINNA:
7785 					min_noatk_chance =  GET_FLOAT_ARG(1);
7786 					break;
7787 				case CMD_MODELSTXT_DEBUG_MAXNA:
7788 					max_noatk_chance =  GET_FLOAT_ARG(1);
7789 					break;
7790 				case CMD_MODELSTXT_DEBUG_OSNAF:
7791 					offscreen_noatk_factor =  GET_FLOAT_ARG(1);
7792 					break;
7793 				case CMD_MODELSTXT_DEBUG_NAD:
7794 					noatk_duration =  GET_FLOAT_ARG(1);
7795 					break;
7796 				default:
7797 					printf("command %s not understood in %s, line %d\n", command, filename, line);
7798 			}
7799 		}
7800 
7801 		// Go to next line
7802 		pos += getNewLineStart(buf + pos);
7803 	}
7804 	// calculate max animations
7805 	max_animations += (max_attack_types - MAX_ATKS) * 6 +// multply by 5, for fall/die/pain/rise/blockpain/riseattack
7806 			(max_follows - MAX_FOLLOWS) +
7807 			(max_freespecials - MAX_SPECIALS) +
7808 			(max_attacks - MAX_ATTACKS) +
7809 			(max_idles - MAX_IDLES)+
7810 			(max_walks - MAX_WALKS)+
7811 			(max_ups - MAX_UPS)+
7812 			(max_downs - MAX_DOWNS)+
7813 			(max_backwalks - MAX_BACKWALKS);
7814 
7815 	// alloc indexed animation ids
7816 	animdowns       = (int*)malloc(sizeof(int)*max_downs);
7817 	animups         = (int*)malloc(sizeof(int)*max_ups);
7818 	animbackwalks   = (int*)malloc(sizeof(int)*max_backwalks);
7819 	animwalks       = (int*)malloc(sizeof(int)*max_walks);
7820 	animidles       = (int*)malloc(sizeof(int)*max_idles);
7821 	animpains       = (int*)malloc(sizeof(int)*max_attack_types);
7822 	animdies        = (int*)malloc(sizeof(int)*max_attack_types);
7823 	animfalls       = (int*)malloc(sizeof(int)*max_attack_types);
7824 	animrises       = (int*)malloc(sizeof(int)*max_attack_types);
7825 	animriseattacks = (int*)malloc(sizeof(int)*max_attack_types);
7826 	animblkpains    = (int*)malloc(sizeof(int)*max_attack_types);
7827 	animattacks     = (int*)malloc(sizeof(int)*max_attacks);
7828 	animfollows     = (int*)malloc(sizeof(int)*max_follows);
7829 	animspecials    = (int*)malloc(sizeof(int)*max_freespecials);
7830 
7831 	// copy default values and new animation ids
7832 	memcpy(animdowns, downs, sizeof(int)*MAX_DOWNS);
7833 	for(i=MAX_DOWNS; i<max_downs; i++) animdowns[i] = maxanim++;
7834 	memcpy(animups, ups, sizeof(int)*MAX_UPS);
7835 	for(i=MAX_UPS; i<max_ups; i++) animups[i] = maxanim++;
7836 	memcpy(animbackwalks, backwalks, sizeof(int)*MAX_BACKWALKS);
7837 	for(i=MAX_BACKWALKS; i<max_backwalks; i++) animbackwalks[i] = maxanim++;
7838 	memcpy(animwalks, walks, sizeof(int)*MAX_WALKS);
7839 	for(i=MAX_WALKS; i<max_walks; i++) animwalks[i] = maxanim++;
7840 	memcpy(animidles, idles, sizeof(int)*MAX_IDLES);
7841 	for(i=MAX_IDLES; i<max_idles; i++) animidles[i] = maxanim++;
7842 	memcpy(animspecials, freespecials,   sizeof(int)*MAX_SPECIALS);
7843 	for(i=MAX_SPECIALS; i<max_freespecials; i++) animspecials[i] = maxanim++;
7844 	memcpy(animattacks,  normal_attacks, sizeof(int)*MAX_ATTACKS);
7845 	for(i=MAX_ATTACKS; i<max_attacks; i++) animattacks[i] = maxanim++;
7846 	memcpy(animfollows,  follows,        sizeof(int)*MAX_FOLLOWS);
7847 	for(i=MAX_FOLLOWS; i<max_follows; i++) animfollows[i] = maxanim++;
7848 	memcpy(animpains,    pains,          sizeof(int)*MAX_ATKS);
7849 	for(i=MAX_ATKS; i<max_attack_types; i++) animpains[i] = maxanim++;
7850 	memcpy(animfalls,    falls,          sizeof(int)*MAX_ATKS);
7851 	for(i=MAX_ATKS; i<max_attack_types; i++) animfalls[i] = maxanim++;
7852 	memcpy(animrises,    rises,          sizeof(int)*MAX_ATKS);
7853 	for(i=MAX_ATKS; i<max_attack_types; i++) animrises[i] = maxanim++;
7854 	memcpy(animriseattacks,    riseattacks,          sizeof(int)*MAX_ATKS);
7855 	for(i=MAX_ATKS; i<max_attack_types; i++) animriseattacks[i] = maxanim++;
7856 	memcpy(animblkpains,    blkpains,    sizeof(int)*MAX_ATKS);
7857 	for(i=MAX_ATKS; i<max_attack_types; i++) animblkpains[i] = maxanim++;
7858 	memcpy(animdies,     deaths,         sizeof(int)*MAX_ATKS);
7859 	for(i=MAX_ATKS; i<max_attack_types; i++) animdies[i] = maxanim++;
7860 
7861 	// Defer load_cached_model, so you can define models after their nested model.
7862 	printf("\n");
7863 
7864 	for(i=0,pos=0; i<models_cached; i++) {
7865 		//printf("Checking '%s' '%s'\n", model_cache[i].name, model_cache[i].path);
7866 		if(model_cache[i].loadflag) {
7867 			load_cached_model(model_cache[i].name, "models.txt", 0);
7868 			update_loading(&loadingbg[0], ++pos, modelLoadCount);
7869 		}
7870 	}
7871 	printf("\nLoading models...............\tDone!\n");
7872 
7873 
7874 	if(buf)
7875 		free(buf);
7876 
7877 	return 1;
7878 }
7879 
7880 
7881 
7882 
unload_levelorder()7883 void unload_levelorder(){
7884 	int i, j;
7885 	s_level_entry *le;
7886 	s_set_entry *se;
7887 
7888 	if(levelsets){
7889 		for(i=0; i<num_difficulties; i++){
7890 			se = levelsets+i;
7891 			if(se->name){
7892 				free(se->name);
7893 			}
7894 			for(j=0; j<MAX_PLAYERS; j++){
7895 				if(se->skipselect[j])
7896 					free(se->skipselect[j]);
7897 			}
7898 			if(se->numlevels){
7899 				for(j=0; j<se->numlevels; j++){
7900 					le = se->levelorder + j;
7901 					if(le->branchname) free(le->branchname);
7902 					if(le->filename) free(le->filename);
7903 				}
7904 				free(se->levelorder);
7905 			}
7906 		}
7907 
7908 		free(levelsets);
7909 		levelsets = NULL;
7910 	}
7911 
7912 	num_difficulties = 0;
7913 }
7914 
7915 
7916 
7917 // Add a level to the level order
add_level(char * filename,s_set_entry * set)7918 s_level_entry* add_level(char *filename, s_set_entry* set){
7919 	s_level_entry* le = NULL;
7920 	int Zs[3] = {0,0,0};
7921 
7922 	if(z_coords[0] > 0) Zs[0] = z_coords[0];
7923 	else Zs[0] = PLAYER_MIN_Z;
7924 
7925 	if(z_coords[1] > 0) Zs[1] = z_coords[1];
7926 	else Zs[1] = PLAYER_MAX_Z;
7927 
7928 	if(z_coords[2] > 0) Zs[2] = z_coords[2];
7929 	else Zs[2] = PLAYER_MIN_Z;
7930 
7931 	set->levelorder = realloc(set->levelorder, (++set->numlevels)*sizeof(s_level_entry));
7932 	le = set->levelorder + set->numlevels-1;
7933 	memset(le, 0, sizeof(s_level_entry));
7934 	if(branch_name[0])
7935 		le->branchname = NAME(branch_name);
7936 	le->filename = NAME(filename);
7937 	le->z_coords[0] = Zs[0];
7938 	le->z_coords[1] = Zs[1];
7939 	le->z_coords[2] = Zs[2];
7940 	return le;
7941 }
7942 
7943 
7944 
7945 // Add a scene to the level order
add_scene(char * filename,s_set_entry * set)7946 s_level_entry* add_scene(char *filename, s_set_entry* set){
7947 	s_level_entry* le = NULL;
7948 
7949 	set->levelorder = realloc(set->levelorder, (++set->numlevels)*sizeof(s_level_entry));
7950 	le = set->levelorder + set->numlevels-1;
7951 	memset(le, 0, sizeof(s_level_entry));
7952 	if(branch_name[0])
7953 		le->branchname = NAME(branch_name);
7954 	le->filename = NAME(filename);
7955 	le->type = cut_scene;
7956 	return le;
7957 }
7958 
7959 // Add a select screen file to the level order
add_select(char * filename,s_set_entry * set)7960 s_level_entry* add_select(char *filename, s_set_entry* set){
7961 	s_level_entry* le = NULL;
7962 
7963 	set->levelorder = realloc(set->levelorder, (++set->numlevels)*sizeof(s_level_entry));
7964 	le = set->levelorder + set->numlevels-1;
7965 	memset(le, 0, sizeof(s_level_entry));
7966 	if(branch_name[0])
7967 		le->branchname = NAME(branch_name);
7968 	le->filename = NAME(filename);
7969 	le->type = select_screen;
7970 	return le;
7971 }
7972 
_readbarstatus(char * buf,s_barstatus * pstatus)7973 static void _readbarstatus(char* buf, s_barstatus* pstatus)
7974 {
7975 	char* value;
7976 	ArgList arglist;
7977 	char argbuf[MAX_ARG_LEN+1] = "";
7978 
7979 	ParseArgs(&arglist,buf,argbuf);
7980 	if((value=GET_ARG(1))[0]) pstatus->sizex       = atoi(value);
7981 	else return;
7982 	if((value=GET_ARG(2))[0]) pstatus->sizey       = atoi(value);
7983 	else return;
7984 	if((value=GET_ARG(3))[0]) pstatus->noborder    = atoi(value);
7985 	else return;
7986 	if((value=GET_ARG(4))[0]) pstatus->type        = atoi(value);
7987 	else return;
7988 	if((value=GET_ARG(5))[0]) pstatus->orientation = atoi(value);
7989 	else return;
7990 	if((value=GET_ARG(6))[0]) pstatus->borderlayer = atoi(value);
7991 	else return;
7992 	if((value=GET_ARG(7))[0]) pstatus->shadowlayer = atoi(value);
7993 	else return;
7994 	if((value=GET_ARG(8))[0]) pstatus->barlayer    = atoi(value);
7995 	else return;
7996 	if((value=GET_ARG(9))[0]) pstatus->backlayer   = atoi(value);
7997 	else return;
7998 }
7999 
add_set()8000 s_set_entry* add_set(){
8001 	s_set_entry* set = NULL;
8002 	++num_difficulties;
8003 	if(levelsets) levelsets = realloc(levelsets, sizeof(s_set_entry)*num_difficulties);
8004 	else levelsets = calloc(1, sizeof(s_set_entry));
8005 	set = levelsets+num_difficulties-1;
8006 	memset(set, 0, sizeof(s_set_entry));
8007 	set->maxplayers = defaultmaxplayers;
8008 	return set;
8009 }
8010 
8011 // Load list of levels
load_levelorder()8012 void load_levelorder()
8013 {
8014 	static const char* defaulterr = "Error in level order: a set must be specified.";
8015 #define CHKDEF if(!set) { errormessage = (char*) defaulterr; goto lCleanup; }
8016 	char filename[128] = "";
8017 	int i=0,j=0;
8018 	char *buf;
8019 	size_t size;
8020 	int pos;
8021 	s_set_entry* set = NULL;
8022 	s_level_entry* le = NULL;
8023 	char * command;
8024 	char* arg;
8025 	char* errormessage = NULL;
8026 	int plifeUsed[2]  = {0,0};
8027 	int elifeUsed[2]  = {0,0};
8028 	int piconUsed[2]  = {0,0};
8029 	int piconwUsed[2] = {0,0};
8030 	int eiconUsed[4]  = {0,0,0,0};
8031 	int pmpUsed[4]    = {0,0,0,0};
8032 	int plifeXused[4] = {0,0,0,0};        // 4-7-2006 New custimizable variable for players 'x'
8033 	int plifeNused[4] = {0,0,0,0};        // 4-7-2006 New custimizable variable for players 'lives'
8034 	int enameused[4]  = {0,0,0,0};        // 4-7-2006 New custimizable variable for enemy names
8035 	int pnameJused[4] = {0,0,0,0};        // 1-8-2006 New custimizable variable for players name Select Hero
8036 	int pscoreUsed[4] = {0,0,0,0};        // 1-8-2006 New custimizable variable for players name Select Hero
8037 
8038 	ArgList arglist;
8039 	char argbuf[MAX_ARG_LEN+1] = "";
8040 	levelOrderCommands cmd;
8041 	int line = 0;
8042 
8043 	unload_levelorder();
8044 
8045 	if(custLevels != NULL)
8046 	{
8047 		strcpy(filename,"data/");
8048 		strcat(filename,custLevels);
8049 	}
8050 	else strcpy(filename,"data/levels.txt");
8051 
8052 	// Read file
8053 
8054 	if(buffer_pakfile(filename, &buf, &size)!=1) shutdown(1, "Error loading level list from %s", filename);
8055 
8056 	// Now interpret the contents of buf line by line
8057 	pos = 0;
8058 
8059 	// Custom lifebar/timebox/icon positioning and size
8060 	picon[0][0] = piconw[0][0] = picon[2][0] = piconw[2][0] = eicon[0][0] = eicon[2][0] = 2;
8061 	picon[1][0] = piconw[1][0] = picon[3][0] = piconw[3][0] = eicon[1][0] = eicon[3][0] = 2 + P2_STATS_DIST;
8062 	picon[0][1] = piconw[0][1] = picon[1][1] = piconw[1][1] = 2;
8063 	picon[2][1] = piconw[2][1] = picon[3][1] = piconw[3][1] = 202;
8064 	plife[0][0] = pmp[0][0] = plife[2][0] = pmp[2][0] = elife[0][0] = elife[2][0] = 20;
8065 	plife[1][0] = pmp[1][0] = plife[3][0] = pmp[3][0] = elife[1][0] = elife[3][0] = 20 + P2_STATS_DIST;
8066 	plife[0][1] = plife[1][1] = 10;
8067 	plife[2][1] = plife[3][1] = 210;
8068 	pmp[0][1] = pmp[1][1] = 18;
8069 	pmp[2][1] = pmp[3][1] = 218;
8070 
8071 	memset(psmenu, 0, sizeof(int)*4*4);
8072 
8073 	eicon[0][1] = eicon[1][1] = 19;
8074 	eicon[2][1] = eicon[3][1] = 220;
8075 	elife[0][1] = elife[1][1] = 27;
8076 	elife[2][1] = elife[3][1] = 227;
8077 
8078 	timeloc[0] = 149;
8079 	timeloc[1] = 4;
8080 	timeloc[2] = 21;
8081 	timeloc[3] = 20;
8082 	timeloc[4] = 0;
8083 
8084 	lbarstatus.sizex  = mpbarstatus.sizex = 100;
8085 	lbarstatus.sizey  = 5;
8086 	mpbarstatus.sizey = 3;
8087 	lbarstatus.noborder = mpbarstatus.noborder = 0;
8088 
8089 	// Show Complete Default Values
8090 	scomplete[0] = 75;
8091 	scomplete[1] = 60;
8092 	scomplete[2] = 0;
8093 	scomplete[3] = 0;
8094 	scomplete[4] = 0;
8095 	scomplete[5] = 0;
8096 
8097 	// Show Complete Y Values
8098 	cbonus[0] = lbonus[0] = rbonus[0] = tscore[0] = 10;
8099 	cbonus[1] = cbonus[3] = cbonus[5] = cbonus[7] = cbonus[9] = 100;
8100 	lbonus[1] = lbonus[3] = lbonus[5] = lbonus[7] = lbonus[9] = 120;
8101 	rbonus[1] = rbonus[3] = rbonus[5] = rbonus[7] = rbonus[9] = 140;
8102 	tscore[1] = tscore[3] = tscore[5] = tscore[7] = tscore[9] = 160;
8103 
8104 	// Show Complete X Values
8105 	cbonus[2] = lbonus[2] = rbonus[2] = tscore[2] = 100;
8106 	cbonus[4] = lbonus[4] = rbonus[4] = tscore[4] = 155;
8107 	cbonus[6] = lbonus[6] = rbonus[6] = tscore[6] = 210;
8108 	cbonus[8] = lbonus[8] = rbonus[8] = tscore[8] = 265;
8109 
8110 
8111 	while(pos<size){
8112 		line++;
8113 		ParseArgs(&arglist,buf+pos,argbuf);
8114 		command = GET_ARG(0);
8115 		cmd = getLevelOrderCommand(levelordercmdlist, command);
8116 		switch(cmd) {
8117 			case CMD_LEVELORDER_BLENDFX:
8118 				for(i=0; i<MAX_BLENDINGS; i++)
8119 				{
8120 					if(GET_INT_ARG(i+1)) blendfx[i] = 1;
8121 					else blendfx[i] = 0;
8122 				}
8123 				blendfx_is_set = 1;
8124 				break;
8125 			case CMD_LEVELORDER_SET:
8126 				set = add_set();
8127 				set->name = NAME(GET_ARG(1));
8128 				set->ifcomplete = 0;
8129 				set->saveflag  = 1; // default to 1, so the level can be saved
8130 				branch_name[0] = 0;
8131 				le = NULL;
8132 				break;
8133 			case CMD_LEVELORDER_IFCOMPLETE:
8134 				CHKDEF;
8135 				set->ifcomplete = GET_INT_ARG(1);
8136 				break;
8137 			case CMD_LEVELORDER_SKIPSELECT:
8138 				CHKDEF;
8139 				if(arglist.count==1)
8140 				{
8141 					set->noselect = 1;
8142 				}
8143 				else
8144 				{
8145 					for(i=0; i<4;i++) {
8146 						if((arg=GET_ARG(i+1))[0]) {
8147 							set->skipselect[i] = NAME(arg);
8148 						}
8149 					}
8150 				}
8151 				break;
8152 			case CMD_LEVELORDER_FILE:
8153 				CHKDEF;
8154 				le = add_level(GET_ARG(1), set);
8155 				break;
8156 			case CMD_LEVELORDER_SCENE:
8157 				CHKDEF;
8158 				le = add_scene(GET_ARG(1), set);
8159 				break;
8160 			case CMD_LEVELORDER_SELECT:
8161 				CHKDEF;
8162 				le = add_select(GET_ARG(1), set);
8163 				break;
8164 			case CMD_LEVELORDER_NEXT:
8165 				CHKDEF;
8166 				// Set 'gonext' flag of last loaded level
8167 				if(le) le->gonext = 1;
8168 				break;
8169 			case CMD_LEVELORDER_END:
8170 				CHKDEF;
8171 				// Set endgame flag of last loaded level
8172 				if(le) le->gonext = 2;
8173 				break;
8174 			case CMD_LEVELORDER_LIVES:
8175 				// 7-1-2005  credits/lives/singleplayer start here
8176 				// used to read the new # of lives/credits from the levels.txt
8177 				CHKDEF;
8178 				set->lives = GET_INT_ARG(1);
8179 				break;
8180 			case CMD_LEVELORDER_DISABLEHOF:
8181 				CHKDEF;
8182 				set->noshowhof = GET_INT_ARG(1);
8183 				break;
8184 			case CMD_LEVELORDER_CANSAVE:
8185 				// 07-12-31
8186 				// 0 this set can't be saved
8187 				// 1 save level only
8188 				// 2 save player info and level, can't choose player in select menu
8189 				CHKDEF;
8190 				set->saveflag = GET_INT_ARG(1);
8191 				break;
8192 			case CMD_LEVELORDER_Z:
8193 				//    2-10-05  adjust the walkable coordinates
8194 				CHKDEF;
8195 				z_coords[0] = GET_INT_ARG(1);
8196 				z_coords[1] = GET_INT_ARG(2);
8197 				z_coords[2] = GET_INT_ARG(3);
8198 				break;
8199 			case CMD_LEVELORDER_BRANCH:
8200 				//    2007-2-22 level branch name
8201 				CHKDEF;
8202 				strncpy(branch_name, GET_ARG(1), MAX_NAME_LEN);
8203 				break;
8204 			case CMD_LEVELORDER_P1LIFE: case CMD_LEVELORDER_P2LIFE: case CMD_LEVELORDER_P3LIFE: case CMD_LEVELORDER_P4LIFE:
8205 				switch(cmd) {
8206 					case CMD_LEVELORDER_P1LIFE: i = 0; break;
8207 					case CMD_LEVELORDER_P2LIFE: i = 1; break;
8208 					case CMD_LEVELORDER_P3LIFE: i = 2; plifeUsed[0] = 1; break;
8209 					case CMD_LEVELORDER_P4LIFE: i = 3; plifeUsed[1] = 1; break;
8210 					default: assert(0);
8211 				}
8212 				if((arg=GET_ARG(1))[0]) plife[i][0] = atoi(arg);
8213 				if((arg=GET_ARG(2))[0]) plife[i][1] = atoi(arg);
8214 				break;
8215 			case CMD_LEVELORDER_P1MP: case CMD_LEVELORDER_P2MP: case CMD_LEVELORDER_P3MP: case CMD_LEVELORDER_P4MP:
8216 				switch(cmd) {
8217 					case CMD_LEVELORDER_P1MP: i = 0; break;
8218 					case CMD_LEVELORDER_P2MP: i = 1; break;
8219 					case CMD_LEVELORDER_P3MP: i = 2; break;
8220 					case CMD_LEVELORDER_P4MP: i = 3; break;
8221 					default: assert(0);
8222 				}
8223 				if((arg=GET_ARG(1))[0]) pmp[i][0] = atoi(arg);
8224 				if((arg=GET_ARG(2))[0]) pmp[i][1] = atoi(arg);
8225 				pmpUsed[i] = 1;
8226 				break;
8227 			case CMD_LEVELORDER_P1LIFEX: case CMD_LEVELORDER_P2LIFEX: case CMD_LEVELORDER_P3LIFEX: case CMD_LEVELORDER_P4LIFEX:
8228 				switch(cmd) {
8229 					case CMD_LEVELORDER_P1LIFEX: j = 0; break;
8230 					case CMD_LEVELORDER_P2LIFEX: j = 1; break;
8231 					case CMD_LEVELORDER_P3LIFEX: j = 2; break;
8232 					case CMD_LEVELORDER_P4LIFEX: j = 3; break;
8233 					default: assert(0);
8234 				}
8235 				for(i=0; i<3; i++)
8236 					if((arg=GET_ARG(i+1))[0]) plifeX[j][i] = atoi(arg);
8237 				plifeXused[j] = 1;
8238 				break;
8239 			case CMD_LEVELORDER_P1LIFEN: case CMD_LEVELORDER_P2LIFEN: case CMD_LEVELORDER_P3LIFEN: case CMD_LEVELORDER_P4LIFEN:
8240 				switch(cmd) {
8241 					case CMD_LEVELORDER_P1LIFEN: j = 0; break;
8242 					case CMD_LEVELORDER_P2LIFEN: j = 1; break;
8243 					case CMD_LEVELORDER_P3LIFEN: j = 2; break;
8244 					case CMD_LEVELORDER_P4LIFEN: j = 3; break;
8245 					default: assert(0);
8246 				}
8247 				for(i=0; i<3; i++)
8248 					if((arg=GET_ARG(i+1))[0]) plifeN[j][i] = atoi(arg);
8249 				plifeNused[j] = 1;
8250 				break;
8251 			case CMD_LEVELORDER_E1LIFE: case CMD_LEVELORDER_E2LIFE: case CMD_LEVELORDER_E3LIFE: case CMD_LEVELORDER_E4LIFE:
8252 				switch(cmd) {
8253 					case CMD_LEVELORDER_E1LIFE: i = 0; break;
8254 					case CMD_LEVELORDER_E2LIFE: i = 1; break;
8255 					case CMD_LEVELORDER_E3LIFE: i = 2; elifeUsed[0] = 1; break;
8256 					case CMD_LEVELORDER_E4LIFE: i = 3; elifeUsed[1] = 1; break;
8257 					default: assert(0);
8258 				}
8259 				if((arg=GET_ARG(1))[0]) elife[i][0] = atoi(arg);
8260 				if((arg=GET_ARG(2))[0]) elife[i][1] = atoi(arg);
8261 				break;
8262 			case CMD_LEVELORDER_P1ICON: case CMD_LEVELORDER_P2ICON: case CMD_LEVELORDER_P3ICON: case CMD_LEVELORDER_P4ICON:
8263 				switch(cmd) {
8264 					case CMD_LEVELORDER_P1ICON: i = 0; break;
8265 					case CMD_LEVELORDER_P2ICON: i = 1; break;
8266 					case CMD_LEVELORDER_P3ICON: i = 2; piconUsed[0] = 1; break;
8267 					case CMD_LEVELORDER_P4ICON: i = 3; piconUsed[1] = 1; break;
8268 					default: assert(0);
8269 				}
8270 				if((arg=GET_ARG(1))[0]) picon[i][0] = atoi(arg);
8271 				if((arg=GET_ARG(2))[0]) picon[i][1] = atoi(arg);
8272 				break;
8273 			case CMD_LEVELORDER_P1ICONW: case CMD_LEVELORDER_P2ICONW: case CMD_LEVELORDER_P3ICONW: case CMD_LEVELORDER_P4ICONW:
8274 				switch(cmd) {
8275 					case CMD_LEVELORDER_P1ICONW: i = 0; break;
8276 					case CMD_LEVELORDER_P2ICONW: i = 1; break;
8277 					case CMD_LEVELORDER_P3ICONW: i = 2; piconwUsed[0] = 1; break;
8278 					case CMD_LEVELORDER_P4ICONW: i = 3; piconwUsed[1] = 1; break;
8279 					default: assert(0);
8280 				}
8281 				if((arg=GET_ARG(1))[0]) piconw[i][0] = atoi(arg);
8282 				if((arg=GET_ARG(2))[0]) piconw[i][1] = atoi(arg);
8283 				break;
8284 			case CMD_LEVELORDER_MP1ICON: case CMD_LEVELORDER_MP2ICON: case CMD_LEVELORDER_MP3ICON: case CMD_LEVELORDER_MP4ICON:
8285 				switch(cmd) {
8286 					case CMD_LEVELORDER_MP1ICON: i = 0; break;
8287 					case CMD_LEVELORDER_MP2ICON: i = 1; break;
8288 					case CMD_LEVELORDER_MP3ICON: i = 2; break;
8289 					case CMD_LEVELORDER_MP4ICON: i = 3; break;
8290 					default: assert(0);
8291 				}
8292 				if((arg=GET_ARG(1))[0]) mpicon[i][0] = atoi(arg);
8293 				if((arg=GET_ARG(2))[0]) mpicon[i][1] = atoi(arg);
8294 				break;
8295 			case CMD_LEVELORDER_P1NAMEJ: case CMD_LEVELORDER_P2NAMEJ: case CMD_LEVELORDER_P3NAMEJ: case CMD_LEVELORDER_P4NAMEJ:
8296 				switch(cmd) {
8297 					case CMD_LEVELORDER_P1NAMEJ: j = 0; break;
8298 					case CMD_LEVELORDER_P2NAMEJ: j = 1; break;
8299 					case CMD_LEVELORDER_P3NAMEJ: j = 2; break;
8300 					case CMD_LEVELORDER_P4NAMEJ: j = 3; break;
8301 					default: assert(0);
8302 				}
8303 				for(i=0; i<7; i++)
8304 					if((arg=GET_ARG(i+1))[0]) pnameJ[j][i] = atoi(arg);
8305 				pnameJused[j] = 1;
8306 				break;
8307 			case CMD_LEVELORDER_P1SCORE: case CMD_LEVELORDER_P2SCORE: case CMD_LEVELORDER_P3SCORE: case CMD_LEVELORDER_P4SCORE:
8308 				switch(cmd) {
8309 					case CMD_LEVELORDER_P1SCORE: j = 0; break;
8310 					case CMD_LEVELORDER_P2SCORE: j = 1; break;
8311 					case CMD_LEVELORDER_P3SCORE: j = 2; break;
8312 					case CMD_LEVELORDER_P4SCORE: j = 3; break;
8313 					default: assert(0);
8314 				}
8315 				for(i=0; i<7; i++)
8316 					if((arg=GET_ARG(i+1))[0]) pscore[j][i] = atoi(arg);
8317 				pscoreUsed[j] = 1;
8318 				break;
8319 			case CMD_LEVELORDER_P1SHOOT: case CMD_LEVELORDER_P2SHOOT: case CMD_LEVELORDER_P3SHOOT: case CMD_LEVELORDER_P4SHOOT:
8320 				switch(cmd) {
8321 					case CMD_LEVELORDER_P1SHOOT: j = 0; break;
8322 					case CMD_LEVELORDER_P2SHOOT: j = 1; break;
8323 					case CMD_LEVELORDER_P3SHOOT: j = 2; break;
8324 					case CMD_LEVELORDER_P4SHOOT: j = 3; break;
8325 					default: assert(0);
8326 				}
8327 				for(i=0; i<3; i++)
8328 					if((arg=GET_ARG(i+1))[0]) pshoot[j][i] = atoi(arg);
8329 				break;
8330 			case CMD_LEVELORDER_P1RUSH: case CMD_LEVELORDER_P2RUSH: case CMD_LEVELORDER_P3RUSH: case CMD_LEVELORDER_P4RUSH:
8331 				switch(cmd) {
8332 					case CMD_LEVELORDER_P1RUSH: j = 0; break;
8333 					case CMD_LEVELORDER_P2RUSH: j = 1; break;
8334 					case CMD_LEVELORDER_P3RUSH: j = 2; break;
8335 					case CMD_LEVELORDER_P4RUSH: j = 3; break;
8336 					default: assert(0);
8337 				}
8338 				for(i=0; i<8; i++)
8339 					if((arg=GET_ARG(i+1))[0]) prush[j][i] = atoi(arg);
8340 				break;
8341 			case CMD_LEVELORDER_E1ICON: case CMD_LEVELORDER_E2ICON: case CMD_LEVELORDER_E3ICON: case CMD_LEVELORDER_E4ICON:
8342 				switch(cmd) {
8343 					case CMD_LEVELORDER_E1ICON: i = 0; break;
8344 					case CMD_LEVELORDER_E2ICON: i = 1; break;
8345 					case CMD_LEVELORDER_E3ICON: i = 2; eiconUsed[0] = 1; break;
8346 					case CMD_LEVELORDER_E4ICON: i = 3; eiconUsed[1] = 1; break;
8347 					default: assert(0);
8348 				}
8349 				if((arg=GET_ARG(1))[0]) eicon[i][0] = atoi(arg);
8350 				if((arg=GET_ARG(2))[0]) eicon[i][1] = atoi(arg);
8351 				break;
8352 			case CMD_LEVELORDER_E1NAME: case CMD_LEVELORDER_E2NAME: case CMD_LEVELORDER_E3NAME: case CMD_LEVELORDER_E4NAME:
8353 				switch(cmd) {
8354 					case CMD_LEVELORDER_E1NAME: j = 0; break;
8355 					case CMD_LEVELORDER_E2NAME: j = 1; break;
8356 					case CMD_LEVELORDER_E3NAME: j = 2; break;
8357 					case CMD_LEVELORDER_E4NAME: j = 3; break;
8358 					default: assert(0);
8359 				}
8360 				for(i=0; i<3; i++)
8361 					if((arg=GET_ARG(i+1))[0]) ename[j][i] = atoi(arg);
8362 				enameused[j] = 1;
8363 				break;
8364 			case CMD_LEVELORDER_P1SMENU: case CMD_LEVELORDER_P2SMENU: case CMD_LEVELORDER_P3SMENU: case CMD_LEVELORDER_P4SMENU:
8365 				switch(cmd) {
8366 					case CMD_LEVELORDER_P1SMENU: j = 0; break;
8367 					case CMD_LEVELORDER_P2SMENU: j = 1; break;
8368 					case CMD_LEVELORDER_P3SMENU: j = 2; break;
8369 					case CMD_LEVELORDER_P4SMENU: j = 3; break;
8370 					default: assert(0);
8371 				}
8372 				for(i=0; i<4; i++)
8373 					if((arg=GET_ARG(i+1))[0]) psmenu[j][i] = atoi(arg);
8374 				break;
8375 			case CMD_LEVELORDER_TIMEICON:
8376    				strncpy(timeicon_path, GET_ARG(1), 127);
8377 				timeicon = loadsprite(timeicon_path,0,0,pixelformat);
8378 				if((arg=GET_ARG(2))[0]) timeicon_offsets[0] = atoi(arg);
8379 				if((arg=GET_ARG(3))[0]) timeicon_offsets[1] = atoi(arg);
8380 				break;
8381 			case CMD_LEVELORDER_BGICON:
8382 				strncpy(bgicon_path, GET_ARG(1), 127);
8383 				bgicon = loadsprite(bgicon_path,0,0,pixelformat);
8384 				if((arg=GET_ARG(2))[0]) bgicon_offsets[0] = atoi(arg);
8385 				if((arg=GET_ARG(3))[0]) bgicon_offsets[1] = atoi(arg);
8386 				if((arg=GET_ARG(4))[0]) bgicon_offsets[2] = atoi(arg);
8387 				else bgicon_offsets[2] = HUD_Z / 2;
8388 				break;
8389 			case CMD_LEVELORDER_OLICON:
8390 				strncpy(olicon_path, GET_ARG(1), 127);
8391 				olicon = loadsprite(olicon_path,0,0,pixelformat);
8392 				if((arg=GET_ARG(2))[0]) olicon_offsets[0] = atoi(arg);
8393 				if((arg=GET_ARG(3))[0]) olicon_offsets[1] = atoi(arg);
8394 				if((arg=GET_ARG(4))[0]) olicon_offsets[2] = atoi(arg);
8395 				else olicon_offsets[2] = HUD_Z * 3;
8396 				break;
8397 			case CMD_LEVELORDER_TIMELOC:
8398 				for(i=0; i<6; i++)
8399 					if((arg=GET_ARG(i+1))[0]) timeloc[i] = atoi(arg);
8400 				break;
8401 			case CMD_LEVELORDER_LBARSIZE:
8402 				_readbarstatus(buf+pos, &lbarstatus);
8403 				break;
8404 			case CMD_LEVELORDER_OLBARSIZE:
8405 				_readbarstatus(buf+pos, &olbarstatus);
8406 				break;
8407 			case CMD_LEVELORDER_MPBARSIZE:
8408 				_readbarstatus(buf+pos, &mpbarstatus);
8409 				break;
8410 			case CMD_LEVELORDER_LBARTEXT:
8411 				for(i=0; i<4; i++)
8412 					if((arg=GET_ARG(i+1))[0]) lbartext[i] = atoi(arg);
8413 				break;
8414 			case CMD_LEVELORDER_MPBARTEXT:
8415 				for(i=0; i<4; i++)
8416 					if((arg=GET_ARG(i+1))[0]) mpbartext[i] = atoi(arg);
8417 				break;
8418 			case CMD_LEVELORDER_SHOWCOMPLETE:
8419 				for(i=0; i<6; i++)
8420 					if((arg=GET_ARG(i+1))[0]) scomplete[i] = atoi(arg);
8421 				break;
8422 			case CMD_LEVELORDER_CLEARBONUS:
8423 				for(i=0; i<10; i++)
8424 					if((arg=GET_ARG(i+1))[0]) cbonus[i] = atoi(arg);
8425 				break;
8426 			case CMD_LEVELORDER_RUSHBONUS:
8427 				for(i=0; i<10; i++)
8428 					if((arg=GET_ARG(i+1))[0]) rbonus[i] = atoi(arg);
8429 				break;
8430 			case CMD_LEVELORDER_LIFEBONUS:
8431 				for(i=0; i<10; i++)
8432 					if((arg=GET_ARG(i+1))[0]) lbonus[i] = atoi(arg);
8433 				break;
8434 			case CMD_LEVELORDER_SCBONUSES:
8435 				for(i=0; i<4; i++)
8436 					if((arg=GET_ARG(i+1))[0]) scbonuses[i] = atoi(arg);
8437 				break;
8438 			case CMD_LEVELORDER_TOTALSCORE:
8439 				for(i=0; i<10; i++)
8440 					if((arg=GET_ARG(i+1))[0]) tscore[i] = atoi(arg);
8441 				break;
8442 			case CMD_LEVELORDER_MUSICOVERLAP:
8443 				CHKDEF;
8444 				set->musicoverlap = GET_INT_ARG(1);
8445 				break;
8446 			case CMD_LEVELORDER_SHOWRUSHBONUS:
8447 				showrushbonus = 1;
8448 				break;
8449 			case CMD_LEVELORDER_NOSLOWFX:
8450 				noslowfx = 1;
8451 				break;
8452 			case CMD_LEVELORDER_EQUALAIRPAUSE:
8453 				equalairpause = 1;
8454 				break;
8455 			case CMD_LEVELORDER_HISCOREBG:
8456 				hiscorebg = 1;
8457 				break;
8458 			case CMD_LEVELORDER_COMPLETEBG:
8459 				completebg = 1;
8460 				break;
8461 			case CMD_LEVELORDER_LOADINGBG:
8462 				errormessage = fill_s_loadingbar(&loadingbg[0], GET_INT_ARG(1), GET_INT_ARG(2),GET_INT_ARG(3),GET_INT_ARG(4),GET_INT_ARG(5),GET_INT_ARG(6),GET_INT_ARG(7),GET_INT_ARG(8));
8463 				if(errormessage) goto lCleanup;
8464 				break;
8465 			case CMD_LEVELORDER_LOADINGBG2:
8466 				errormessage = fill_s_loadingbar(&loadingbg[1], GET_INT_ARG(1), GET_INT_ARG(2),GET_INT_ARG(3),GET_INT_ARG(4),GET_INT_ARG(5),GET_INT_ARG(6),GET_INT_ARG(7),GET_INT_ARG(8));
8467 				if(errormessage) goto lCleanup;
8468 				break;
8469 			case CMD_LEVELORDER_LOADINGMUSIC:
8470 				loadingmusic = GET_INT_ARG(1);
8471 				break;
8472 			case CMD_LEVELORDER_UNLOCKBG:
8473 				unlockbg = 1;
8474 				break;
8475 			case CMD_LEVELORDER_NOSHARE:
8476 				noshare = 1;
8477 				break;
8478 			case CMD_LEVELORDER_CUSTFADE:
8479 				//8-2-2005 custom fade
8480 				CHKDEF;
8481 				set->custfade = GET_INT_ARG(1);
8482 				break;
8483 			case CMD_LEVELORDER_CONTINUESCORE:
8484 				//8-2-2005 custom fade end
8485 				//continuescore
8486 				CHKDEF;
8487 				set->continuescore = GET_INT_ARG(1);
8488 				break;
8489 			case CMD_LEVELORDER_CREDITS:
8490 				CHKDEF;
8491 				set->credits = GET_INT_ARG(1);
8492 				break;
8493 			case CMD_LEVELORDER_TYPEMP:
8494 				//typemp for change for mp restored by time (0) to by enemys (1) or no restore (2) by tails
8495 				CHKDEF;
8496 				set->typemp = GET_INT_ARG(1);
8497 				break;
8498 			case CMD_LEVELORDER_SINGLE:
8499 				if(set)
8500 					set->maxplayers = 1;
8501 				else
8502 					defaultmaxplayers = 1;
8503 				break;
8504 			case CMD_LEVELORDER_MAXPLAYERS:
8505 				if(set)
8506 					set->maxplayers = GET_INT_ARG(1);
8507 				else
8508 					defaultmaxplayers = GET_INT_ARG(1);
8509 				break;
8510 			case CMD_LEVELORDER_NOSAME:
8511 				CHKDEF;
8512 				set->nosame = GET_INT_ARG(1);
8513 				break;
8514 			case CMD_LEVELORDER_RUSH:
8515 				rush[0] = GET_INT_ARG(1);
8516 				rush[1] = GET_INT_ARG(2);
8517 				strncpy(rush_names[0], GET_ARG(3), MAX_NAME_LEN);
8518 				rush[2] = GET_INT_ARG(4);
8519 				rush[3] = GET_INT_ARG(5);
8520 				strncpy(rush_names[1], GET_ARG(6), MAX_NAME_LEN);
8521 				rush[4] = GET_INT_ARG(7);
8522 				rush[5] = GET_INT_ARG(8);
8523 				break;
8524 			case CMD_LEVELORDER_MAXWALLHEIGHT:
8525 				MAX_WALL_HEIGHT = GET_INT_ARG(1);
8526 				if(MAX_WALL_HEIGHT < 0) MAX_WALL_HEIGHT = 1000;
8527 				break;
8528 			case CMD_LEVELORDER_SCOREFORMAT:
8529 				scoreformat = GET_INT_ARG(1);
8530 				break;
8531 			case CMD_LEVELORDER_GRAVITY:
8532 				default_level_gravity = GET_FLOAT_ARG(1);
8533 				default_level_maxfallspeed = GET_FLOAT_ARG(2);
8534 				default_level_maxtossspeed = GET_FLOAT_ARG(3);
8535 				break;
8536 			case CMD_LEVELORDER_SKIPTOSET:
8537 				skiptoset = GET_INT_ARG(1);
8538 				break;
8539 			default:
8540 				if (command && command[0])
8541 					printf("Command '%s' not understood in level order!", command);
8542 		}
8543 
8544 		// Go to next line
8545 		pos+=getNewLineStart(buf + pos);
8546 	}
8547 
8548 #undef CHKDEF
8549 
8550 	// Variables without defaults will be auto populated.
8551 	if(olbarstatus.sizex==0) {olbarstatus = lbarstatus;}
8552 
8553 	if(!plifeUsed[0]){ plife[2][0] = plife[0][0]; plife[2][1] = plife[2][1] + (plife[0][1] - 10); }
8554 	if(!plifeUsed[1]){ plife[3][0] = plife[1][0]; plife[3][1] = plife[3][1] + (plife[1][1] - 10); }
8555 
8556 	if(!elifeUsed[0]){ elife[2][0] = elife[0][0]; elife[2][1] = elife[2][1] + (elife[0][1] - 27); }
8557 	if(!elifeUsed[1]){ elife[3][0] = elife[1][0]; elife[3][1] = elife[3][1] + (elife[1][1] - 27); }
8558 
8559 	if(!piconUsed[0]){ picon[2][0] = picon[0][0]; picon[2][1] = picon[2][1] + (picon[0][1] - 2); }
8560 	if(!piconUsed[1]){ picon[3][0] = picon[1][0]; picon[3][1] = picon[3][1] + (picon[1][1] - 2); }
8561 
8562 	if(!piconwUsed[0]){ piconw[2][0] = piconw[0][0]; piconw[2][1] = piconw[2][1] + (piconw[0][1] - 2); }
8563 	if(!piconwUsed[1]){ piconw[3][0] = piconw[1][0]; piconw[3][1] = piconw[3][1] + (piconw[1][1] - 2); }
8564 
8565 	if(!eiconUsed[0]){ eicon[2][0] = eicon[0][0]; eicon[2][1] = eicon[2][1] + (eicon[0][1] - 19); }
8566 	if(!eiconUsed[1]){ eicon[3][0] = eicon[1][0]; eicon[3][1] = eicon[3][1] + (eicon[1][1] - 19); }
8567 
8568 	if(!pmpUsed[0]){ pmp[0][0] = plife[0][0]; pmp[0][1] = plife[0][1] + 8; }
8569 	if(!pmpUsed[1]){ pmp[1][0] = plife[1][0]; pmp[1][1] = plife[1][1] + 8; }
8570 	if(!pmpUsed[2]){ pmp[2][0] = pmp[0][0]; pmp[2][1] = pmp[2][1] + (pmp[0][1] - 18); }
8571 	if(!pmpUsed[3]){ pmp[3][0] = pmp[1][0]; pmp[3][1] = pmp[1][1] + (pmp[1][1] - 18); }
8572 
8573 	if(!plifeXused[0]){ plifeX[0][0] = plife[0][0] + lbarstatus.sizex + 4; plifeX[0][1] = picon[0][1] + 7; }
8574 	if(!plifeXused[1]){ plifeX[1][0] = plife[1][0] + lbarstatus.sizex + 4; plifeX[1][1] = picon[1][1] + 7; }
8575 	if(!plifeXused[2]){ plifeX[2][0] = plife[2][0] + lbarstatus.sizex + 4; plifeX[2][1] = picon[2][1] + 7; }
8576 	if(!plifeXused[3]){ plifeX[3][0] = plife[3][0] + lbarstatus.sizex + 4; plifeX[3][1] = picon[3][1] + 7; }
8577 	for(i=0; i<4; i++) if(plifeX[i][2] == -1) plifeX[i][2] = 0;
8578 
8579 	if(!plifeNused[0]){ plifeN[0][0] = plife[0][0] + lbarstatus.sizex + 11; plifeN[0][1] = picon[0][1]; }
8580 	if(!plifeNused[1]){ plifeN[1][0] = plife[1][0] + lbarstatus.sizex + 11; plifeN[1][1] = picon[1][1]; }
8581 	if(!plifeNused[2]){ plifeN[2][0] = plifeN[0][0]; plifeN[2][1] = picon[2][1]; }
8582 	if(!plifeNused[3]){ plifeN[3][0] = plifeN[1][0]; plifeN[3][1] = picon[3][1]; }
8583 	for(i=0; i<4; i++) if(plifeN[i][2] == -1) plifeN[i][2] = 3;
8584 
8585 	if(!pnameJused[0]){ pnameJ[0][2] = pnameJ[0][4] = pnameJ[0][0] = plife[0][0] + 1; pnameJ[0][5] = pnameJ[0][1] = picon[0][1]; pnameJ[0][3] = 10 + pnameJ[0][5]; }
8586 	if(!pnameJused[1]){ pnameJ[1][2] = pnameJ[1][4] = pnameJ[1][0] = plife[1][0] + 1; pnameJ[1][5] = pnameJ[1][1] = picon[1][1]; pnameJ[1][3] = 10 + pnameJ[1][5]; }
8587 	if(!pnameJused[2]){ pnameJ[2][2] = pnameJ[2][4] = pnameJ[2][0] = plife[2][0] + 1; pnameJ[2][5] = pnameJ[2][1] = picon[2][1]; pnameJ[2][3] = 10 + pnameJ[2][5]; }
8588 	if(!pnameJused[3]){ pnameJ[3][2] = pnameJ[3][4] = pnameJ[3][0] = plife[3][0] + 1; pnameJ[3][5] = pnameJ[3][1] = picon[3][1]; pnameJ[3][3] = 10 + pnameJ[3][5]; }
8589 	for(i=0; i<4; i++) if(pnameJ[i][6] == -1) pnameJ[i][6] = 0;
8590 
8591 	if(!pscoreUsed[0]){ pscore[0][0] = plife[0][0] + 1; pscore[0][1] = picon[0][1]; }
8592 	if(!pscoreUsed[1]){ pscore[1][0] = plife[1][0] + 1; pscore[1][1] = picon[1][1]; }
8593 	if(!pscoreUsed[2]){ pscore[2][0] = plife[2][0] + 1; pscore[2][1] = picon[2][1]; }
8594 	if(!pscoreUsed[3]){ pscore[3][0] = plife[3][0] + 1; pscore[3][1] = picon[3][1]; }
8595 	for(i=0; i<4; i++) if(pscore[i][6] == -1) pscore[i][6] = 0;
8596 
8597 	if(!enameused[0]){ ename[0][0] = elife[0][0] + 1; ename[0][1] = eicon[0][1]; }
8598 	if(!enameused[1]){ ename[1][0] = elife[1][0] + 1; ename[1][1] = eicon[1][1]; }
8599 	if(!enameused[2]){ ename[2][0] = ename[0][0]; ename[2][1] = eicon[2][1]; }
8600 	if(!enameused[3]){ ename[3][0] = ename[1][0]; ename[3][1] = eicon[3][1]; }
8601 	for(i=0; i<4; i++) if(ename[i][2] == -1) ename[i][2] = 0;
8602 
8603 	branch_name[0] = 0; //clear up branch name, so we can use it in game
8604 
8605 	for(i=0; i<4; i++) if(pshoot[i][2] == -1) pshoot[i][2] = 2;
8606 	if(timeloc[5] == -1) timeloc[5] = 3;
8607 
8608 	if(!set)
8609 		errormessage = "No levels were loaded!";
8610 
8611 	lCleanup:
8612 
8613 	if(buf)
8614 		free(buf);
8615 
8616 	if(!savelevel) savelevel = calloc(num_difficulties, sizeof(s_savelevel));
8617 
8618 	if(errormessage)
8619 		shutdown(1, "load_levelorder ERROR in %s at %d, msg: %s\n", filename, line, errormessage);
8620 }
8621 
8622 
free_level(s_level * lv)8623 void free_level(s_level* lv)
8624 {
8625 	int i, j;
8626 	s_spawn_script_list_node* templistnode;
8627 	s_spawn_script_list_node* templistnode2;
8628 	s_spawn_script_cache_node* tempnode;
8629 	s_spawn_script_cache_node* tempnode2;
8630 	if(!lv) return;
8631 	//offload blending tables
8632 	for(i=0; i<LEVEL_MAX_PALETTES; i++)
8633 	{
8634 		for(j=0; j<MAX_BLENDINGS; j++)
8635 		{
8636 			if(lv->blendings[i][j]) free(lv->blendings[i][j]);
8637 			lv->blendings[i][j] = NULL;
8638 		}
8639 	}
8640 	//offload layers
8641 	for(i=1; i<lv->numlayers; i++)
8642 	{
8643 		if(lv->layers[i].gfx.handle && lv->layers[i].gfx.handle!=background)
8644 		{
8645 			free(lv->layers[i].gfx.handle);
8646 			lv->layers[i].gfx.handle = NULL;
8647 		}
8648 	}
8649 	//offload textobjs
8650 	for(i=0; i<LEVEL_MAX_TEXTOBJS; i++)
8651 	{
8652 		if(lv->textobjs[i].text)
8653 		{
8654 			free(lv->textobjs[i].text);
8655 			lv->textobjs[i].text = NULL;
8656 		}
8657 	}
8658 
8659 	for(i=0; i<LEVEL_MAX_FILESTREAMS; i++)
8660 	{
8661 		if(filestreams[i].buf)
8662 		{
8663 			free(filestreams[i].buf);
8664 			filestreams[i].buf = NULL;
8665 		}
8666 	}
8667 
8668 	//offload scripts
8669 	Script_Clear(&(lv->update_script), 2);
8670 	Script_Clear(&(lv->updated_script), 2);
8671 	Script_Clear(&(lv->key_script), 2);
8672 	Script_Clear(&(lv->level_script), 2);
8673 	Script_Clear(&(lv->endlevel_script), 2);
8674 
8675 	for(i=0; i<LEVEL_MAX_SPAWNS; i++)
8676 	{
8677 		if(lv->spawnpoints[i].spawn_script_list_head)
8678 		{
8679 			templistnode = lv->spawnpoints[i].spawn_script_list_head;
8680 			lv->spawnpoints[i].spawn_script_list_head = NULL;
8681 			while(templistnode)
8682 			{
8683 				templistnode2 = templistnode->next;
8684 				templistnode->next = NULL;
8685 				templistnode->spawn_script = NULL;
8686 				free(templistnode);
8687 				templistnode = templistnode2;
8688 		    }
8689 		}
8690 	}
8691 
8692 	tempnode = lv->spawn_script_cache_head;
8693 	lv->spawn_script_cache_head = NULL;
8694 	while(tempnode)
8695 	{
8696 		tempnode2 = tempnode->next;
8697 		Script_Clear(tempnode->cached_spawn_script, 2);
8698 		free(tempnode->cached_spawn_script);
8699 		tempnode->cached_spawn_script = NULL;
8700 		free(tempnode->filename);
8701 		tempnode->filename = NULL;
8702 		tempnode->next = NULL;
8703 		free(tempnode);
8704 		tempnode = tempnode2;
8705 	}
8706 
8707 	free(lv);
8708 	lv = NULL;
8709 }
8710 
8711 
unload_level()8712 void unload_level(){
8713 	s_model* temp;
8714 
8715 	unload_background();
8716 
8717 	if(level){
8718 
8719 		level->pos = 0;
8720 		level->advancetime = 0;
8721 		level->quake = 0;
8722 		level->quaketime = 0;
8723 		level->waiting = 0;
8724 
8725 		printf("Level Unloading: '%s'\n", level->name);
8726 		getRamStatus(BYTES);
8727 		free(level->name);
8728 		level->name = NULL;
8729 		free_level(level);
8730 		level = NULL;
8731 		temp = getFirstModel();
8732 		do {
8733 			if(!temp) break;
8734 			if((temp->unload&2)){
8735 				cache_model_sprites(temp, 0);
8736 			}
8737 			if((temp->unload&1)){
8738 				free_model(temp);
8739 				temp = getCurrentModel();
8740 			} else temp = getNextModel();
8741 		} while(temp);
8742 		printf("Done.\n");
8743 		getRamStatus(BYTES);
8744 
8745 
8746 	}
8747 
8748 	advancex = 0;
8749 	advancey = 0;
8750 	nojoin = 0;
8751 	current_spawn = 0;
8752 	groupmin = 100;
8753 	groupmax = 100;
8754 	scrollminz = 0;
8755 	scrollmaxz = 0;
8756 	blockade = 0;
8757 	level_completed = 0;
8758 	tospeedup = 0;    // Reset so it sets to normal speed for the next level
8759 	reached[0] = reached[1] = reached[2] = reached[3] = 0;    // TYPE_ENDLEVEL values reset after level completed //4player
8760 	showtimeover = 0;
8761 	pause = 0;
8762 	endgame = 0;
8763 	go_time = 0;
8764 	debug_time = 0;
8765 	neon_time = 0;
8766 	time = 0;
8767 	cameratype = 0;
8768 	light[0] = 128;
8769 	light[1] = 64;
8770 	gfx_y_offset = gfx_x_offset = gfx_y_offset_adj = 0;    // Added so select screen graphics display correctly
8771 }
8772 
llHandleCommandSpawnscript(ArgList * arglist,s_spawn_entry * next)8773 char* llHandleCommandSpawnscript(ArgList* arglist, s_spawn_entry* next) {
8774 	char* result = NULL;
8775 	char* value;
8776 	size_t len;
8777 
8778 	s_spawn_script_cache_node* tempnode;
8779 	s_spawn_script_cache_node* tempnode2;
8780 	s_spawn_script_list_node* templistnode;
8781 
8782 	value = GET_ARGP(1);
8783 
8784 	tempnode = level->spawn_script_cache_head;
8785 
8786 	templistnode = next->spawn_script_list_head;
8787 	if(templistnode) {
8788 		while(templistnode->next)
8789 		{
8790 			templistnode = templistnode->next;
8791 		}
8792 		templistnode->next = malloc(sizeof(s_spawn_script_list_node));
8793 		templistnode = templistnode->next;
8794 	} else	{
8795 		next->spawn_script_list_head = malloc(sizeof(s_spawn_script_list_node));
8796 		templistnode = next->spawn_script_list_head;
8797 	}
8798 	templistnode->spawn_script = NULL;
8799 	templistnode->next = NULL;
8800 	if(tempnode) {
8801 		while(1) {
8802 			if(stricmp(value, tempnode->filename)==0) {
8803 				templistnode->spawn_script = tempnode->cached_spawn_script;
8804 				break;
8805 			} else {
8806 				if(tempnode->next)
8807 					tempnode = tempnode->next;
8808 				else
8809 					break;
8810 			}
8811 		}
8812 	}
8813 	if(!templistnode->spawn_script) {
8814 		templistnode->spawn_script = alloc_script();
8815 		Script_Init(templistnode->spawn_script, GET_ARGP(0), NULL, 0);
8816 
8817 		if(load_script(templistnode->spawn_script, value)) {
8818 			Script_Compile(templistnode->spawn_script);
8819 			len = strlen(value);
8820 
8821 			if(tempnode) {
8822 				tempnode2 = malloc(sizeof(s_spawn_script_cache_node));
8823 				tempnode2->cached_spawn_script = templistnode->spawn_script;
8824 				tempnode2->filename = malloc(len + 1);
8825 				strcpy(tempnode2->filename, value);
8826 				tempnode2->filename[len] = 0;
8827 				tempnode2->next = NULL;
8828 				tempnode->next = tempnode2;
8829 			} else {
8830 				level->spawn_script_cache_head = malloc(sizeof(s_spawn_script_cache_node));
8831 				level->spawn_script_cache_head->cached_spawn_script = templistnode->spawn_script;
8832 				level->spawn_script_cache_head->filename = malloc(len + 1);
8833 				level->spawn_script_cache_head->next = NULL;
8834 				strcpy(level->spawn_script_cache_head->filename, value);
8835 				level->spawn_script_cache_head->filename[len] = 0;
8836 			}
8837 		} else {
8838 			result = "Failed loading spawn entry script!";
8839 		}
8840 	}
8841 	return result;
8842 }
8843 
8844 
load_level(char * filename)8845 void load_level(char *filename){
8846 	char *buf = NULL;
8847 	size_t size, len;
8848 	ptrdiff_t pos, oldpos;
8849 	char *command;
8850 	char *value;
8851 	char string[128] = {""};
8852 	s_spawn_entry next;
8853 	s_model *tempmodel, *cached_model;
8854 
8855 	int i = 0, j = 0, crlf = 0;
8856 	int usemap[MAX_BLENDINGS];
8857 	char bgPath[128] = {""}, fnbuf[128];
8858 	s_loadingbar bgPosi = {0, 0, 0, 0, 0, 0, 0};
8859 	char musicPath[128] = {""};
8860 	u32 musicOffset = 0;
8861 
8862 	ArgList arglist;
8863 	char argbuf[MAX_ARG_LEN+1] = "";
8864 
8865 	ArgList arglist2;
8866 	char argbuf2[MAX_ARG_LEN+1] = "";
8867 
8868 	levelCommands cmd;
8869 	levelCommands cmd2;
8870 	int line = 0;
8871 	char* errormessage = NULL;
8872 	char* scriptname = NULL;
8873 	Script* tempscript = NULL;
8874 	s_drawmethod* dm;
8875 	s_layer* bgl;
8876 	s_layer* panels[LEVEL_MAX_PANELS][3];
8877 	int order[LEVEL_MAX_PANELS];
8878 	int panelcount = 0;
8879 
8880 	unload_level();
8881 
8882 	printf("Level Loading:   '%s'\n", filename);
8883 
8884 
8885 
8886 	getRamStatus(BYTES);
8887 
8888 	if(isLoadingScreenTypeBg(loadingbg[1].set)) {
8889 		if(custBkgrds) {
8890 			strcpy(string, custBkgrds);
8891 			strcat(string, "loading2");
8892 			load_background(string, 0);
8893 		} else {
8894 			load_cached_background("data/bgs/loading2", 0);
8895 		}
8896 		clearscreen(vscreen);
8897 		spriteq_clear();
8898 		standard_palette(1);
8899 	}
8900 
8901 	if(isLoadingScreenTypeBar(loadingbg[1].set)) {
8902 	    lifebar_colors();
8903 	    init_colourtable();
8904 	}
8905 
8906 	update_loading(&loadingbg[1], -1, 1); // initialize the update screen
8907 
8908 	memset(&next, 0, sizeof(s_spawn_entry));
8909 
8910 	level = calloc(1,sizeof(s_level));
8911 	if(!level) {
8912 		errormessage = "load_level() #1 FATAL: Out of memory!";
8913 		goto lCleanup;
8914 	}
8915 	len = strlen(filename);
8916 	level->name = malloc(len + 1);
8917 
8918 	if(!level->name) {
8919 		errormessage = "load_level() #1 FATAL: Out of memory!";
8920 		goto lCleanup;
8921 	}
8922 	strcpy(level->name, filename);
8923 
8924 	if(buffer_pakfile(filename, &buf, &size)!=1) {
8925 		errormessage = "Unable to load level file!";
8926 		goto lCleanup;
8927 	}
8928 
8929 	level->settime = 100;    // Feb 25, 2005 - Default time limit set to 100
8930 	level->nospecial = 0;    // Default set to specials can be used during bonus levels
8931 	level->nohurt = 0;    // Default set to players can hurt each other during bonus levels
8932 	level->nohit = 0;    // Default able to hit the other player
8933 	level->spawn[0][2] = level->spawn[1][2] = level->spawn[2][2] = level->spawn[3][2] = 300;    // Set the default spawn a to 300
8934 	level->setweap = 0;
8935 	level->maxtossspeed = default_level_maxtossspeed;
8936 	level->maxfallspeed = default_level_maxfallspeed;
8937 	level->gravity = default_level_gravity;
8938 	level->scrolldir = SCROLL_RIGHT;
8939 	level->scrollspeed = 1;
8940 	level->cameraxoffset = 0;
8941 	level->camerazoffset = 0;
8942 	level->bosses = 0;
8943 	blendfx[BLEND_MULTIPLY] = 1;
8944 	bgtravelled = 0;
8945 	traveltime = 0;
8946 	texttime = 0;
8947 	nopause = 0;
8948 	nofadeout = 0;
8949 	noscreenshot = 0;
8950 	panel_width = panel_height = frontpanels_loaded = 0;
8951 	memset(panels, 0, sizeof(s_layer*)*LEVEL_MAX_PANELS*3);
8952 	memset(order, 0, sizeof(int)*LEVEL_MAX_PANELS);
8953 
8954 	//reset_playable_list(1);
8955 
8956 	// Now interpret the contents of buf line by line
8957 	pos = 0;
8958 	while(pos<size){
8959 		line++;
8960 		ParseArgs(&arglist,buf+pos,argbuf);
8961 		command = GET_ARG(0);
8962 		cmd = getLevelCommand(levelcmdlist, command);
8963 		switch(cmd) {
8964 			case CMD_LEVEL_LOADINGBG:
8965 				load_background(GET_ARG(1), 0);
8966 				errormessage = fill_s_loadingbar(&bgPosi, GET_INT_ARG(2), GET_INT_ARG(3), GET_INT_ARG(4), GET_INT_ARG(5), GET_INT_ARG(6), GET_INT_ARG(7), GET_INT_ARG(8), GET_INT_ARG(9));
8967 				if (errormessage) goto lCleanup;
8968 				standard_palette(1);
8969 				lifebar_colors();
8970 				init_colourtable();
8971 				update_loading(&bgPosi, -1, 1); // initialize the update screen
8972 				break;
8973 			case CMD_LEVEL_MUSICFADE:
8974 				memset(&next,0,sizeof(s_spawn_entry));
8975 				next.musicfade = GET_FLOAT_ARG(1);
8976 				break;
8977 			case CMD_LEVEL_MUSIC:
8978 				value = GET_ARG(1);
8979 				strncpy(string, value, 128);
8980 				musicOffset = atol(GET_ARG(2));
8981 				if(loadingmusic) {
8982 					music(string, 1, musicOffset);
8983 					musicPath[0] = 0;
8984 				} else {
8985 					oldpos = pos;
8986 					// Go to next line
8987 					pos += getNewLineStart(buf + pos);
8988 					#define GET_ARG2(z) arglist2.count > z ? arglist2.args[z] : ""
8989 					if(pos<size) {
8990 						ParseArgs(&arglist2,buf+pos,argbuf2);
8991 						command = GET_ARG2(0);
8992 						cmd2 = getLevelCommand(levelcmdlist, command);
8993 					} else
8994 						cmd2 = (levelCommands) 0;
8995 
8996 					if(cmd2 == CMD_LEVEL_AT) {
8997 						if(next.musicfade == 0) memset(&next,0,sizeof(s_spawn_entry));
8998 						strncpy(next.music, string, 128);
8999 						next.musicoffset = musicOffset;
9000 					} else {
9001 						strncpy(musicPath, string, 128);
9002 					}
9003 					pos = oldpos;
9004 					#undef GET_ARG2
9005 				}
9006 				break;
9007 			case CMD_LEVEL_ALLOWSELECT:
9008 				load_playable_list(buf+pos);
9009 				break;
9010 			case CMD_LEVEL_LOAD:
9011 				#ifdef DEBUG
9012 				printf("load_level: load %s, %s\n", GET_ARG(1), filename);
9013 				#endif
9014 				tempmodel = findmodel(GET_ARG(1));
9015 				if (!tempmodel)
9016 					load_cached_model(GET_ARG(1), filename, GET_INT_ARG(2));
9017 				else
9018 					update_model_loadflag(tempmodel, GET_INT_ARG(2));
9019 				break;
9020 			case CMD_LEVEL_BACKGROUND:
9021 			case CMD_LEVEL_BGLAYER:
9022 			case CMD_LEVEL_LAYER:
9023 			case CMD_LEVEL_FGLAYER:
9024 				if(level->numlayers >= LEVEL_MAX_LAYERS) {
9025 					errormessage = "Too many layers in level (check LEVEL_MAX_LAYERS)!";
9026 					goto lCleanup;
9027 				}
9028 
9029 				bgl = &(level->layers[level->numlayers]);
9030 
9031 				if(cmd==CMD_LEVEL_BACKGROUND || cmd==CMD_LEVEL_BGLAYER){
9032 					i = 0;
9033 					bgl->z = MIN_INT;
9034 				}else{
9035 					i = 1;
9036 					bgl->z =  GET_FLOAT_ARG(2);
9037 					if(cmd==CMD_LEVEL_FGLAYER) bgl->z += FRONTPANEL_Z;
9038 				}
9039 
9040 				if(cmd==CMD_LEVEL_BACKGROUND){
9041 					if(bgPath[0]){
9042 						errormessage = "Background is already defined!";
9043 						goto lCleanup;
9044 					}
9045 					value = GET_ARG(1);
9046 					strncpy(bgPath, value, strlen(value)+1);
9047 					bgl->oldtype = bgt_background;
9048 				}else if(cmd==CMD_LEVEL_BGLAYER) bgl->oldtype = bgt_bglayer;
9049 				else if(cmd==CMD_LEVEL_FGLAYER) bgl->oldtype = bgt_fglayer;
9050 				else if(cmd==CMD_LEVEL_LAYER) bgl->oldtype = bgt_generic;
9051 
9052 				dm = &(bgl->drawmethod);
9053 				*dm = plainmethod;
9054 
9055 				bgl->xratio = GET_FLOAT_ARG(i+2); // x ratio
9056 				bgl->zratio = GET_FLOAT_ARG(i+3); // z ratio
9057 				bgl->xoffset = GET_INT_ARG(i+4); // x start
9058 				bgl->zoffset = GET_INT_ARG(i+5); // z start
9059 				bgl->xspacing = GET_INT_ARG(i+6); // x spacing
9060 				bgl->zspacing = GET_INT_ARG(i+7); // z spacing
9061 				dm->xrepeat = GET_INT_ARG(i+8); // x repeat
9062 				dm->yrepeat = GET_INT_ARG(i+9); // z repeat
9063 				dm->transbg = GET_INT_ARG(i+10); // transparency
9064 				dm->alpha = GET_INT_ARG(i+11); // alpha
9065 				dm->water.watermode = GET_INT_ARG(i+12); // amplitude
9066 				if(dm->water.watermode==3){
9067 					dm->water.beginsize = GET_FLOAT_ARG(i+13); // beginsize
9068 					dm->water.endsize = GET_FLOAT_ARG(i+14); // endsize
9069 					dm->water.perspective = GET_INT_ARG(i+15); // amplitude
9070 				}else{
9071 					dm->water.amplitude = GET_INT_ARG(i+13); // amplitude
9072 					dm->water.wavelength = GET_FLOAT_ARG(i+14); // wavelength
9073 					dm->water.wavespeed = GET_FLOAT_ARG(i+15); // waterspeed
9074 				}
9075 				bgl->bgspeedratio = GET_FLOAT_ARG(i+16); // moving
9076 				bgl->quake = GET_INT_ARG(i+17); // quake
9077 				bgl->neon = GET_INT_ARG(i+18); // neon
9078 				bgl->enabled = 1; // enabled
9079 
9080 				if((GET_ARG(i+2))[0]==0) bgl->xratio = (cmd==CMD_LEVEL_FGLAYER?1.5:0.5);
9081 				if((GET_ARG(i+3))[0]==0) bgl->zratio = (cmd==CMD_LEVEL_FGLAYER?1.5:0.5);
9082 
9083 				if((GET_ARG(i+8))[0]==0) dm->xrepeat = -1;
9084 				if((GET_ARG(i+9))[0]==0) dm->yrepeat = -1;
9085 				if(cmd==CMD_LEVEL_BACKGROUND && (GET_ARG(i+16))[0]==0) bgl->bgspeedratio = 1.0;
9086 
9087 				if(blendfx_is_set==0 && dm->alpha) blendfx[dm->alpha-1] = 1;
9088 
9089 				if(cmd!=CMD_LEVEL_BACKGROUND) load_layer(GET_ARG(1), level->numlayers);
9090 				level->numlayers++;
9091 				break;
9092 			case CMD_LEVEL_WATER:
9093 				if(level->numlayers >= LEVEL_MAX_LAYERS) {
9094 					errormessage = "Too many layers in level (check LEVEL_MAX_LAYERS)!";
9095 					goto lCleanup;
9096 				}
9097 
9098 				bgl = &(level->layers[level->numlayers]);
9099 				dm = &(bgl->drawmethod);
9100 				*dm = plainmethod;
9101 
9102 				bgl->oldtype = bgt_water;
9103 				bgl->z = MIN_INT+1;
9104 
9105 				bgl->xratio = 0.5; // x ratio
9106 				bgl->zratio = 0.5; // z ratio
9107 				bgl->xoffset = 0; // x start
9108 				bgl->zoffset = NaN; // z start
9109 				bgl->xspacing = 0; // x spacing
9110 				bgl->zspacing = 0; // z spacing
9111 				dm->xrepeat = -1; // x repeat
9112 				dm->yrepeat = 1; // z repeat
9113 				dm->transbg = 0; // transparency
9114 				dm->alpha = 0; // alpha
9115 				dm->water.watermode = 2; // amplitude
9116 				dm->water.amplitude = GET_INT_ARG(2); // amplitude
9117 				dm->water.wavelength = 40; // wavelength
9118 				dm->water.wavespeed = 1.0; // waterspeed
9119 				bgl->bgspeedratio = 0; // moving
9120 				bgl->enabled = 1; // enabled
9121 
9122 				if(dm->water.amplitude<1)dm->water.amplitude = 1;
9123 
9124 				load_layer(GET_ARG(1), level->numlayers);
9125 				level->numlayers++;
9126 				break;
9127 			case CMD_LEVEL_DIRECTION:
9128 				value = GET_ARG(1);
9129 				if(stricmp(value, "up")==0) level->scrolldir = SCROLL_UP;
9130 				else if(stricmp(value, "down")==0) level->scrolldir = SCROLL_DOWN;
9131 				else if(stricmp(value, "left")==0) level->scrolldir = SCROLL_LEFT;
9132 				else if(stricmp(value, "both")==0 || stricmp(value, "rightleft")==0) level->scrolldir = SCROLL_BOTH;
9133 				else if(stricmp(value, "leftright")==0) level->scrolldir = SCROLL_LEFTRIGHT;
9134 				else if(stricmp(value, "right")==0) level->scrolldir = SCROLL_RIGHT;
9135 				else if(stricmp(value, "in")==0) level->scrolldir = SCROLL_INWARD;
9136 				else if(stricmp(value, "out")==0) level->scrolldir = SCROLL_OUTWARD;
9137 				else if(stricmp(value, "inout")==0) level->scrolldir = SCROLL_INOUT;
9138 				else if(stricmp(value, "outin")==0) level->scrolldir = SCROLL_OUTIN;
9139 				break;
9140 			case CMD_LEVEL_FACING:
9141 				level->facing = GET_INT_ARG(1);
9142 				break;
9143 			case CMD_LEVEL_ROCK:
9144 				level->rocking = GET_INT_ARG(1);
9145 				break;
9146 			case CMD_LEVEL_BGSPEED:
9147 				level->bgspeed = GET_FLOAT_ARG(1);
9148 				if(GET_INT_ARG(2))level->bgspeed*=-1;
9149 				break;
9150 			case CMD_LEVEL_SCROLLSPEED:
9151 				level->scrollspeed = GET_FLOAT_ARG(1);
9152 				break;
9153 			case CMD_LEVEL_MIRROR:
9154 				level->mirror = GET_INT_ARG(1);
9155 				break;
9156 			case CMD_LEVEL_BOSSMUSIC:
9157 				strncpy(level->bossmusic, GET_ARG(1), 255);
9158 				level->bossmusic_offset = atol(GET_ARG(2));
9159 				break;
9160 			case CMD_LEVEL_NOSAVE:
9161 				nosave = GET_INT_ARG(1);
9162 				break;
9163 			case CMD_LEVEL_NOFADEOUT:
9164 				nofadeout = GET_INT_ARG(1);
9165 				break;
9166 			case CMD_LEVEL_NOPAUSE:
9167 				nopause = GET_INT_ARG(1);
9168 				break;
9169 			case CMD_LEVEL_NOSCREENSHOT:
9170 				noscreenshot = GET_INT_ARG(1);
9171 				break;
9172 			case CMD_LEVEL_SETTIME:
9173 				// If settime is found, overwrite the default 100 for time limit
9174 				level->settime = GET_INT_ARG(1);
9175 				if(level->settime > 100 || level->settime < 0) level->settime = 100;
9176 				// Feb 25, 2005 - Time limit loaded from individual .txt file
9177 				break;
9178 			case CMD_LEVEL_SETWEAP:
9179 				// Specify a weapon for each level
9180 				level->setweap = GET_INT_ARG(1);
9181 				break;
9182 			case CMD_LEVEL_NOTIME:
9183 				// Flag to if the time should be displayed 1 = no, else yes
9184 				level->notime = GET_INT_ARG(1);
9185 				break;
9186 			case CMD_LEVEL_NORESET:
9187 				// Flag to if the time should be reset when players respawn 1 = no, else yes
9188 				level->noreset = GET_INT_ARG(1);
9189 				break;
9190 			case CMD_LEVEL_NOSLOW:
9191 				// If set, level will not slow down when bosses are defeated
9192 				level->noslow = GET_INT_ARG(1);
9193 				break;
9194 			case CMD_LEVEL_TYPE:
9195 				level->type = GET_INT_ARG(1);    // Level type - 1 = bonus, else regular
9196 				level->nospecial = GET_INT_ARG(2);    // Can use specials during bonus levels (default 0 - yes)
9197 				level->nohurt = GET_INT_ARG(3);    // Can hurt other players during bonus levels (default 0 - yes)
9198 				break;
9199 			case CMD_LEVEL_NOHIT:
9200 				level->nohit = GET_INT_ARG(1);
9201 				break;
9202 			case CMD_LEVEL_GRAVITY:
9203 				level->gravity = GET_FLOAT_ARG(1);
9204 				level->gravity /= 100;
9205 				break;
9206 			case CMD_LEVEL_MAXFALLSPEED:
9207 				level->maxfallspeed = GET_FLOAT_ARG(1);
9208 				level->maxfallspeed /= 10;
9209 				break;
9210 			case CMD_LEVEL_MAXTOSSSPEED:
9211 				level->maxtossspeed = GET_FLOAT_ARG(1);
9212 				level->maxtossspeed /= 10;
9213 				break;
9214 			case CMD_LEVEL_CAMERATYPE:
9215 				cameratype = GET_INT_ARG(1);
9216 				break;
9217 			case CMD_LEVEL_CAMERAOFFSET:
9218 				level->cameraxoffset = GET_INT_ARG(1);
9219 				level->camerazoffset = GET_INT_ARG(2);
9220 				break;
9221 			case CMD_LEVEL_SPAWN1: case CMD_LEVEL_SPAWN2: case CMD_LEVEL_SPAWN3: case CMD_LEVEL_SPAWN4:
9222 				switch(cmd) {
9223 					case CMD_LEVEL_SPAWN1: i = 0; break;
9224 					case CMD_LEVEL_SPAWN2: i = 1; break;
9225 					case CMD_LEVEL_SPAWN3: i = 2; break;
9226 					case CMD_LEVEL_SPAWN4: i = 3; break;
9227 					default:
9228 						assert(0);
9229 				}
9230 				level->spawn[i][0] = GET_INT_ARG(1);
9231 				level->spawn[i][1] = GET_INT_ARG(2);
9232 				level->spawn[i][2] = GET_INT_ARG(3);
9233 
9234 				if(level->spawn[i][1] > 232 || level->spawn[i][1] < 0) level->spawn[i][1] = 232;
9235 				if(level->spawn[i][2] < 0) level->spawn[i][2] = 300;
9236 				break;
9237 			case CMD_LEVEL_FRONTPANEL:
9238 			case CMD_LEVEL_PANEL:
9239 				if(level->numlayers >= LEVEL_MAX_LAYERS) {
9240 					errormessage = "Too many layers in level (check LEVEL_MAX_LAYERS)!";
9241 					goto lCleanup;
9242 				}
9243 				if(level->numlayers==0) level->numlayers = 1; // reserve for background
9244 
9245 				bgl = &(level->layers[level->numlayers]);
9246 				dm = &(bgl->drawmethod);
9247 				*dm = plainmethod;
9248 
9249 				bgl->oldtype = (cmd==CMD_LEVEL_FRONTPANEL?bgt_frontpanel:bgt_panel);
9250 
9251 				if(bgl->oldtype==bgt_panel) {
9252 					panelcount++;
9253 					bgl->order = panelcount;
9254 					panels[panelcount-1][0] = bgl;
9255 					bgl->z = PANEL_Z;
9256 					bgl->xratio = 0; // x ratio
9257 					bgl->zratio = 0; // z ratio
9258 					dm->xrepeat = 1; // x repeat
9259 				}else {
9260 					frontpanels_loaded++;
9261 					bgl->z = FRONTPANEL_Z;
9262 					bgl->xratio = -0.4; // x ratio
9263 					bgl->zratio = 1; // z ratio
9264 					dm->xrepeat = -1; // x repeat
9265 				}
9266 
9267 				bgl->bgspeedratio = 0;
9268 				bgl->zoffset = 0;
9269 				dm->yrepeat = 1; // z repeat
9270 				dm->transbg = 1; // transparency
9271 				bgl->enabled = 1; // enabled
9272 				bgl->quake = 1; // accept quake and rock
9273 
9274 				load_layer(GET_ARG(1), level->numlayers);
9275 				level->numlayers++;
9276 
9277 				if(stricmp(GET_ARG(2), "none")!=0 && GET_ARG(2)[0])
9278 				{
9279 
9280 				if(level->numlayers >= LEVEL_MAX_LAYERS) {
9281 					errormessage = "Too many layers in level (check LEVEL_MAX_LAYERS)!";
9282 					goto lCleanup;
9283 				}
9284 				level->layers[level->numlayers] = *bgl;
9285 				bgl = &(level->layers[level->numlayers]);
9286 				panels[panelcount-1][1] = bgl;
9287 
9288 				bgl->z = NEONPANEL_Z;
9289 				bgl->neon = 1;
9290 				bgl->gfx.handle = NULL;
9291 				load_layer(GET_ARG(2), level->numlayers);
9292 				level->numlayers++;
9293 				}
9294 
9295 				if(stricmp(GET_ARG(3), "none")!=0 && GET_ARG(3)[0])
9296 				{
9297 
9298 				if(level->numlayers >= LEVEL_MAX_LAYERS) {
9299 					errormessage = "Too many layers in level (check LEVEL_MAX_LAYERS)!";
9300 					goto lCleanup;
9301 				}
9302 				level->layers[level->numlayers] = *bgl;
9303 				bgl = &(level->layers[level->numlayers]);
9304 				panels[panelcount-1][2] = bgl;
9305 				dm = &(bgl->drawmethod);
9306 
9307 				bgl->z = SCREENPANEL_Z;
9308 				bgl->neon = 0;
9309 				dm->alpha = 1;
9310 				bgl->gfx.handle = NULL;
9311 				load_layer(GET_ARG(3), level->numlayers);
9312 				level->numlayers++;
9313 				}
9314 				break;
9315 			case CMD_LEVEL_STAGENUMBER:
9316 				current_stage = GET_INT_ARG(1);
9317 				break;
9318 			case CMD_LEVEL_ORDER:
9319 				// Append to order
9320 				value = GET_ARG(1);
9321 				i = 0;
9322 				while(value[i] && level->numpanels < LEVEL_MAX_PANELS){
9323 					j = value[i];
9324 					// WTF ?
9325 					if(j>='A' && j<='Z') j-='A';
9326 					else if(j>='a' && j<='z') j-='a';
9327 					else {
9328 						errormessage = "Illegal character in panel order!";
9329 						goto lCleanup;
9330 					}
9331 
9332 					order[level->numpanels] = j;
9333 					level->numpanels++;
9334 					i++;
9335 				}
9336 				break;
9337 			case CMD_LEVEL_HOLE:
9338 				value = GET_ARG(1);    // ltb    1-18-05  adjustable hole sprites
9339 
9340 				if(holesprite < 0) {
9341 					if(testpackfile(value, packfile) >= 0) holesprite = loadsprite(value,0,0,pixelformat);// ltb 1-18-05  load new hole sprite
9342 					else holesprite = loadsprite("data/sprites/hole",0,0,pixelformat);    // ltb 1-18-05  no new sprite load the default
9343 				}
9344 
9345 				if(level->numholes >= LEVEL_MAX_HOLES) {
9346 					errormessage = "Too many holes in level (check LEVEL_MAX_HOLES)!";
9347 					goto lCleanup;
9348 				}
9349 				level->holes[level->numholes][0] = GET_FLOAT_ARG(1);
9350 				level->holes[level->numholes][1] = GET_FLOAT_ARG(2);
9351 				level->holes[level->numholes][2] = GET_FLOAT_ARG(3);
9352 				level->holes[level->numholes][3] = GET_FLOAT_ARG(4);
9353 				level->holes[level->numholes][4] = GET_FLOAT_ARG(5);
9354 				level->holes[level->numholes][5] = GET_FLOAT_ARG(6);
9355 				level->holes[level->numholes][6] = GET_FLOAT_ARG(7);
9356 
9357 				if(!level->holes[level->numholes][1]) level->holes[level->numholes][1] = 240;
9358 				if(!level->holes[level->numholes][2]) level->holes[level->numholes][2] = 12;
9359 				if(!level->holes[level->numholes][3]) level->holes[level->numholes][3] = 1;
9360 				if(!level->holes[level->numholes][4]) level->holes[level->numholes][4] = 200;
9361 				if(!level->holes[level->numholes][5]) level->holes[level->numholes][5] = 287;
9362 				if(!level->holes[level->numholes][6]) level->holes[level->numholes][6] = 45;
9363 				level->numholes++;
9364 				break;
9365 			case CMD_LEVEL_WALL:
9366 				if(level->numwalls >= LEVEL_MAX_WALLS) {
9367 					errormessage = "Too many walls in level (check LEVEL_MAX_WALLS)!";
9368 					goto lCleanup;
9369 				}
9370 				level->walls[level->numwalls][0] = GET_FLOAT_ARG(1);
9371 				level->walls[level->numwalls][1] = GET_FLOAT_ARG(2);
9372 				level->walls[level->numwalls][2] = GET_FLOAT_ARG(3);
9373 				level->walls[level->numwalls][3] = GET_FLOAT_ARG(4);
9374 				level->walls[level->numwalls][4] = GET_FLOAT_ARG(5);
9375 				level->walls[level->numwalls][5] = GET_FLOAT_ARG(6);
9376 				level->walls[level->numwalls][6] = GET_FLOAT_ARG(7);
9377 				level->walls[level->numwalls][7] = GET_FLOAT_ARG(8);
9378 				level->numwalls++;
9379 				break;
9380 			case CMD_LEVEL_PALETTE:
9381 				if(level->numpalettes >= LEVEL_MAX_PALETTES) {
9382 					errormessage = "Too many palettes in level (check LEVEL_MAX_PALETTES)!";
9383 					goto lCleanup;
9384 				}
9385 				for(i=0; i<MAX_BLENDINGS; i++)
9386 				usemap[i] = GET_INT_ARG(i+2);
9387 				if(!load_palette(level->palettes[level->numpalettes], GET_ARG(1)) ||
9388 				!create_blending_tables(level->palettes[level->numpalettes], level->blendings[level->numpalettes], usemap))
9389 				{
9390 					errormessage = "Failed to create colour conversion tables for level! (Out of memory?)";
9391 					goto lCleanup;
9392 				}
9393 				level->numpalettes++;
9394 				break;
9395 			case CMD_LEVEL_UPDATESCRIPT: case CMD_LEVEL_UPDATEDSCRIPT: case CMD_LEVEL_KEYSCRIPT:
9396 			case CMD_LEVEL_LEVELSCRIPT: case CMD_LEVEL_ENDLEVELSCRIPT:
9397 				switch(cmd) {
9398 					case CMD_LEVEL_UPDATESCRIPT:
9399 						tempscript = &(level->update_script);
9400 						scriptname = "levelupdatescript";
9401 						break;
9402 					case CMD_LEVEL_UPDATEDSCRIPT:
9403 						tempscript = &(level->updated_script);
9404 						scriptname = "levelupdatedscript";
9405 						break;
9406 					case CMD_LEVEL_KEYSCRIPT:
9407 						tempscript = &(level->key_script);
9408 						scriptname = "levelkeyscript";
9409 						break;
9410 					case CMD_LEVEL_LEVELSCRIPT:
9411 						tempscript = &(level->level_script);
9412 						scriptname = command;
9413 						break;
9414 					case CMD_LEVEL_ENDLEVELSCRIPT:
9415 						tempscript = &(level->endlevel_script);
9416 						scriptname = command;
9417 						break;
9418 					default:
9419 						assert(0);
9420 
9421 				}
9422 				value = GET_ARG(1);
9423 				if(!Script_IsInitialized(tempscript))
9424 					Script_Init(tempscript, scriptname, value, 1);
9425 				else {
9426 					errormessage = "Multiple level script!";
9427 					goto lCleanup;
9428 				}
9429 				if(load_script(tempscript, value))
9430 					Script_Compile(tempscript);
9431 				else {
9432 					errormessage = "Failed loading script!";
9433 					goto lCleanup;
9434 				}
9435 				break;
9436 			case CMD_LEVEL_BLOCKED:
9437 				level->exit_blocked = GET_INT_ARG(1);
9438 				break;
9439 			case CMD_LEVEL_ENDHOLE:
9440 				level->exit_hole = GET_INT_ARG(1);
9441 				break;
9442 			case CMD_LEVEL_WAIT:
9443 				// Clear spawn thing, set wait state instead
9444 				memset(&next,0,sizeof(s_spawn_entry));
9445 				next.wait = 1;
9446 				break;
9447 			case CMD_LEVEL_NOJOIN: case CMD_LEVEL_CANJOIN:
9448 				// Clear spawn thing, set nojoin state instead
9449 				memset(&next,0,sizeof(s_spawn_entry));
9450 				next.nojoin = 1;
9451 				break;
9452 			case CMD_LEVEL_SHADOWCOLOR:
9453 				memset(&next,0,sizeof(s_spawn_entry));
9454 				next.shadowcolor = GET_INT_ARG(1);
9455 				break;
9456 			case CMD_LEVEL_SHADOWALPHA:
9457 				memset(&next,0,sizeof(s_spawn_entry));
9458 				next.shadowalpha = GET_INT_ARG(1);
9459 				if(blendfx_is_set==0 && next.shadowalpha>0) blendfx[next.shadowalpha-1] = 1;
9460 				break;
9461 			case CMD_LEVEL_LIGHT:
9462 				memset(&next,0,sizeof(s_spawn_entry));
9463 				next.light[0] = GET_INT_ARG(1);
9464 				next.light[1] = GET_INT_ARG(2);
9465 				if(next.light[1] == 0) next.light[1] = 64;
9466 				break;
9467 			case CMD_LEVEL_SCROLLZ: case CMD_LEVEL_SCROLLX:
9468 				// now z scroll can be limited by this
9469 				// if the level is vertical, use scrollx, only different in name ..., but makes more sense
9470 				memset(&next,0,sizeof(s_spawn_entry));
9471 				next.scrollminz = GET_INT_ARG(1);
9472 				next.scrollmaxz = GET_INT_ARG(2);
9473 				if(next.scrollminz <= 0) next.scrollminz = 0;
9474 				if(next.scrollmaxz <= 0) next.scrollmaxz = 0;
9475 				break;
9476 			case CMD_LEVEL_BLOCKADE:
9477 				// now x scroll can be limited by this
9478 				memset(&next,0,sizeof(s_spawn_entry));
9479 				next.blockade = GET_INT_ARG(1);
9480 				if(next.blockade==0) next.blockade = -1;
9481 				break;
9482 			case CMD_LEVEL_SETPALETTE:
9483 				// change system palette
9484 				memset(&next,0,sizeof(s_spawn_entry));
9485 				next.palette = GET_INT_ARG(1);
9486 				break;
9487 			case CMD_LEVEL_GROUP:
9488 				// Clear spawn thing, set group instead
9489 				memset(&next,0,sizeof(s_spawn_entry));
9490 				next.groupmin = GET_INT_ARG(1);
9491 				next.groupmax = GET_INT_ARG(2);
9492 				if(next.groupmax < 1) next.groupmax = 1;
9493 				if(next.groupmin < 1) next.groupmin = 100;
9494 				break;
9495 			case CMD_LEVEL_SPAWN:
9496 				// Back to defaults
9497 				next.spawnplayer_count = 0;
9498 				memset(&next,0,sizeof(s_spawn_entry));
9499 				next.index = next.itemindex = next.weaponindex = -1;
9500 				// Name of entry to be spawned
9501 				// Load model (if not loaded already)
9502 				cached_model = findmodel(GET_ARG(1));
9503 				#ifdef DEBUG
9504 				printf("load_level: spawn %s, %s, cached: %p\n", GET_ARG(1), filename, cached_model);
9505 				#endif
9506 				if(cached_model) tempmodel = cached_model;
9507 				else tempmodel = load_cached_model(GET_ARG(1), filename, 0);
9508 				if(tempmodel)
9509 				{
9510 					next.name = tempmodel->name;
9511 					next.index = get_cached_model_index(next.name);
9512 					next.spawntype = 1;     //2011_03_23, DC; Spawntype 1 (level spawn).
9513 					crlf = 1;
9514 				}
9515 				break;
9516 			case CMD_LEVEL_2PSPAWN:
9517 				// Entity only for 2p game
9518 				next.spawnplayer_count = 1;
9519 				break;
9520 			case CMD_LEVEL_3PSPAWN:
9521 				// Entity only for 3p game
9522 				next.spawnplayer_count = 2;
9523 				break;
9524 			case CMD_LEVEL_4PSPAWN:
9525 				// Entity only for 4p game
9526 				next.spawnplayer_count = 3;
9527 				break;
9528 			case CMD_LEVEL_BOSS:
9529 				next.boss = GET_INT_ARG(1);
9530 				level->bosses += next.boss ? 1 : 0;
9531 				break;
9532 			case CMD_LEVEL_FLIP:
9533 				next.flip = GET_INT_ARG(1);
9534 				break;
9535 			case CMD_LEVEL_HEALTH:
9536 				next.health[0] = next.health[1] = next.health[2] = next.health[3] = GET_INT_ARG(1);
9537 				break;
9538 			case CMD_LEVEL_2PHEALTH:
9539 				// Health the spawned entity will have if 2 people are playing
9540 				next.health[1] = next.health[2] = next.health[3] = GET_INT_ARG(1);
9541 				break;
9542 			case CMD_LEVEL_3PHEALTH:
9543 				// Health the spawned entity will have if 2 people are playing
9544 				next.health[2] = next.health[3] = GET_INT_ARG(1);  //4player
9545 				break;
9546 			case CMD_LEVEL_4PHEALTH:
9547 				// Health the spawned entity will have if 2 people are playing
9548 				next.health[3] = GET_INT_ARG(1);  //4player
9549 				break;
9550 			case CMD_LEVEL_MP:
9551 				// mp values to put max mp for player by tails
9552 				next.mp = GET_INT_ARG(1);
9553 				break;
9554 			case CMD_LEVEL_SCORE:
9555 				// So score can be overriden in the levels .txt file
9556 				next.score = GET_INT_ARG(1);
9557 				if(next.score < 0) next.score = 0;    // So negative values cannot be added
9558 				next.multiple = GET_INT_ARG(2);
9559 				if(next.multiple < 0) next.multiple = 0;    // So negative values cannot be added
9560 				break;
9561 			case CMD_LEVEL_NOLIFE:
9562 				// Flag to determine if entity life is shown when hit
9563 				next.nolife = GET_INT_ARG(1);
9564 				break;
9565 			case CMD_LEVEL_ALIAS:
9566 				// Alias (name displayed) of entry to be spawned
9567 				strncpy(next.alias, GET_ARG(1), MAX_NAME_LEN);
9568 				break;
9569 			case CMD_LEVEL_MAP:
9570 				// Colourmap for new entry
9571 				next.colourmap = GET_INT_ARG(1);
9572 				break;
9573 			case CMD_LEVEL_ALPHA:
9574 				// Item to be contained by new entry
9575 				next.alpha = GET_INT_ARG(1);
9576 				if(blendfx_is_set==0 && next.alpha) blendfx[next.alpha-1] = 1;
9577 				break;
9578 			case CMD_LEVEL_DYING:
9579 				// Used to store which remake corresponds with the dying flash
9580 				next.dying = GET_INT_ARG(1);
9581 				next.per1 = GET_INT_ARG(2);
9582 				next.per2 = GET_INT_ARG(3);
9583 				break;
9584 			case CMD_LEVEL_ITEM: case CMD_LEVEL_2PITEM: case CMD_LEVEL_3PITEM: case CMD_LEVEL_4PITEM:
9585 				switch(cmd) {
9586 					// Item to be contained by new entry
9587 					case CMD_LEVEL_ITEM:   next.itemplayer_count = 0; break;
9588 					case CMD_LEVEL_2PITEM: next.itemplayer_count = 1; break;
9589 					case CMD_LEVEL_3PITEM: next.itemplayer_count = 2; break;
9590 					case CMD_LEVEL_4PITEM: next.itemplayer_count = 3; break;
9591 					default: assert(0);
9592 				}
9593 				// Load model (if not loaded already)
9594 				cached_model = findmodel(GET_ARG(1));
9595 				if(cached_model)
9596 					tempmodel = cached_model;
9597 				else
9598 					tempmodel = load_cached_model(GET_ARG(1), filename, 0);
9599 				if(tempmodel) {
9600 					next.item = tempmodel->name;
9601 					next.itemindex = get_cached_model_index(next.item);
9602 				}
9603 				break;
9604 			case CMD_LEVEL_ITEMMAP:
9605 				next.itemmap = GET_INT_ARG(1);
9606 				break;
9607 			case CMD_LEVEL_ITEMHEALTH:
9608 				next.itemhealth = GET_INT_ARG(1);
9609 				break;
9610 			case CMD_LEVEL_ITEMALIAS:
9611 				strncpy(next.itemalias, GET_ARG(1), MAX_NAME_LEN);
9612 				break;
9613 			case CMD_LEVEL_WEAPON:
9614 				//spawn with a weapon 2007-2-12 by UTunnels
9615 				// Load model (if not loaded already)
9616 				cached_model = findmodel(GET_ARG(1));
9617 				if(cached_model) tempmodel = cached_model;
9618 				else tempmodel = load_cached_model(GET_ARG(1), filename, 0);
9619 				if(tempmodel) {
9620 					next.weapon = tempmodel->name;
9621 					next.weaponindex = get_cached_model_index(next.weapon);
9622 				}
9623 				break;
9624 			case CMD_LEVEL_AGGRESSION:
9625 				// Aggression can be set per spawn.
9626 				next.aggression = next.aggression + GET_INT_ARG(1);
9627 				break;
9628 			case CMD_LEVEL_CREDIT:
9629 				next.credit = GET_INT_ARG(1);
9630 				break;
9631 			case CMD_LEVEL_ITEMTRANS: case CMD_LEVEL_ITEMALPHA:
9632 				next.itemtrans = GET_INT_ARG(1);
9633 				break;
9634 			case CMD_LEVEL_COORDS:
9635 				next.x = GET_FLOAT_ARG(1);
9636 				next.z = GET_FLOAT_ARG(2);
9637 				next.a = GET_FLOAT_ARG(3);
9638 				break;
9639 			case CMD_LEVEL_SPAWNSCRIPT:
9640 				errormessage = llHandleCommandSpawnscript(&arglist, &next);
9641 				if (errormessage)
9642 					goto lCleanup;
9643 				break;
9644 			case CMD_LEVEL_AT:
9645 				// Place entry on queue
9646 				next.at = GET_INT_ARG(1);
9647 
9648 				if(level->numspawns >= LEVEL_MAX_SPAWNS) {
9649 					errormessage = "too many spawn entries (see LEVEL_MAX_SPAWNS)";
9650 					goto lCleanup;
9651 				}
9652 
9653 				memcpy(&level->spawnpoints[level->numspawns], &next, sizeof(s_spawn_entry));
9654 				level->numspawns++;
9655 
9656 				// And clear...
9657 				memset(&next,0,sizeof(s_spawn_entry));
9658 				break;
9659 			default:
9660 				if(command && command[0]){
9661 					if(!handle_txt_include(command, &arglist, &filename, fnbuf, &buf, &pos, &size))
9662 						printf("Command '%s' not understood in file '%s'!\n", command, filename);
9663 				}
9664 		}
9665 
9666 		// Go to next line
9667 		pos += getNewLineStart(buf + pos);
9668 
9669 		if(isLoadingScreenTypeBar(bgPosi.set) || isLoadingScreenTypeBg(bgPosi.set))
9670 			update_loading(&bgPosi, pos, size);
9671 			//update_loading(bgPosi[0]+videomodes.hShift, bgPosi[1]+videomodes.vShift, bgPosi[2], bgPosi[3]+videomodes.hShift, bgPosi[4]+videomodes.vShift, pos, size, bgPosi[5]);
9672 		else
9673 			update_loading(&loadingbg[1], pos, size);
9674 	}
9675 
9676 	if(level->numpanels < 1) {
9677 		errormessage = "Level error: level has no panels";
9678 		goto lCleanup;
9679 	}
9680 
9681 	if(bgPath[0])
9682 	{
9683 		clearscreen(vscreen);
9684 		spriteq_clear();
9685 		load_background(bgPath, 1);
9686 	}
9687 	else if(background) unload_background();
9688 
9689 	if(level->numlayers) {
9690 
9691 		for(i=0; i<level->numlayers; i++){
9692 			bgl = &(level->layers[i]);
9693 			switch(bgl->oldtype){
9694 			case bgt_water: // default water hack
9695 				bgl->zoffset = background?background->height:level->layers[0].height;
9696 				dm = &(bgl->drawmethod);
9697 				if(level->rocking) {
9698 					dm->water.watermode =3;
9699 					dm->water.beginsize = 1.0;
9700 					dm->water.endsize = 1 + bgl->height/11.0;
9701 					dm->water.perspective = 0;
9702 					bgl->bgspeedratio =2;
9703 				}
9704 				break;
9705 			case bgt_panel:
9706 				panel_width = bgl->width;
9707 				panel_height = bgl->height;
9708 			case bgt_frontpanel:
9709 				if(level->scrolldir&(SCROLL_UP|SCROLL_DOWN))
9710 					bgl->zratio = 1;
9711 				break;
9712 			case bgt_background:
9713 				bgl->gfx.screen=background;
9714 				bgl->width=background->width;
9715 				bgl->height=background->height;
9716 				level->background = bgl;
9717 				break;
9718 			default:
9719 				break;
9720 			}
9721 			load_layer(NULL, i);
9722 		}
9723 
9724 		if(level->background)
9725 		{
9726 			level->layersref[level->numlayersref] = *(level->background);
9727 			level->background = &(level->layersref[level->numlayersref++]);
9728 		}
9729 
9730 
9731 		// non-panel type layers
9732 		for(i=0; i<level->numlayers; i++){
9733 			bgl = &(level->layers[i]);
9734 			if(bgl->oldtype != bgt_panel && bgl->oldtype != bgt_background){
9735 				level->layersref[level->numlayersref] = *bgl;
9736 				bgl = &(level->layersref[level->numlayersref]);
9737 				level->numlayersref++;
9738 				switch(bgl->oldtype){
9739 				case bgt_bglayer:
9740 					level->bglayers[level->numbglayers++] = bgl;
9741 					break;
9742 				case bgt_fglayer:
9743 					level->fglayers[level->numfglayers++] = bgl;
9744 					break;
9745 				case bgt_water:
9746 					level->waters[level->numwaters++] = bgl;
9747 					break;
9748 				case bgt_generic:
9749 					level->genericlayers[level->numgenericlayers++] = bgl;
9750 					break;
9751 				case bgt_frontpanel:
9752 					bgl->xoffset = level->numfrontpanels*bgl->width;
9753 					bgl->xspacing = (frontpanels_loaded-1)*bgl->width;
9754 					level->bglayers[level->numfrontpanels++] = bgl;
9755 					break;
9756 				default:
9757 					break;
9758 				}
9759 			}
9760 		}
9761 
9762 		//panels, normal neon screen
9763 		for(i=0; i<level->numpanels; i++){
9764 			for(j=0; j<3; j++){
9765 				if((bgl=panels[order[i]][j])){
9766 					level->layersref[level->numlayersref] = *bgl;
9767 					bgl = &(level->layersref[level->numlayersref]);
9768 					level->numlayersref++;
9769 					bgl->xoffset = panel_width*i;
9770 					level->panels[i][j] = bgl;
9771 				}
9772 			}
9773 		}
9774 
9775 	}
9776 
9777 	if(musicPath[0]) music(musicPath, 1, musicOffset);
9778 
9779 	timeleft = level->settime * COUNTER_SPEED;    // Feb 24, 2005 - This line moved here to set custom time
9780 	level->width = level->numpanels * panel_width;
9781 
9782 	if(level->width<videomodes.hRes) level->width = videomodes.hRes;
9783 
9784 	if(level->scrolldir&SCROLL_LEFT)
9785 		advancex = (float)(level->width-videomodes.hRes);
9786 	else if(level->scrolldir&SCROLL_INWARD)
9787 		advancey = (float)(panel_height-videomodes.vRes);
9788 
9789 	if(crlf) printf("\n");
9790 	printf("Level Loaded:    '%s'\n", level->name);
9791 	totalram = getSystemRam(BYTES); freeram = getFreeRam(BYTES); usedram = getUsedRam(BYTES);
9792 	printf("Total Ram: %"PRIu64" Bytes\n Free Ram: %"PRIu64" Bytes\n Used Ram: %"PRIu64" Bytes\n", totalram, freeram, usedram);
9793 	printf("Total sprites mapped: %d\n\n", sprites_loaded);
9794 
9795 	lCleanup:
9796 
9797 	if(buf != NULL)
9798 		free(buf);
9799 
9800 	if(errormessage)
9801 		shutdown(1, "ERROR: load_level, file %s, line %d, message: %s", filename, line, errormessage);
9802 }
9803 
9804 
9805 
9806 
9807 
9808 /////////////////////////////////////////////////////////////////////////////
9809 //  Status                                                                  //
9810 /////////////////////////////////////////////////////////////////////////////
bar(int x,int y,int value,int maxvalue,s_barstatus * pstatus)9811 void bar(int x, int y, int value, int maxvalue, s_barstatus* pstatus)
9812 {
9813 	int max = 100, len, alphabg=0, bgindex, colourindex;
9814 	int forex, forey, forew,foreh, bkw, bkh;
9815 
9816 	x += pstatus->offsetx;
9817 	y += pstatus->offsety;
9818 
9819 	if(pstatus->orientation==horizontalbar)    max = pstatus->sizex;
9820 	else if(pstatus->orientation==verticalbar) max = pstatus->sizey;
9821 	else return;
9822 
9823 	if (value < 0) value = 0;
9824 	if (value > maxvalue) value = maxvalue;
9825 
9826 	if(pstatus->type==valuebar)
9827 	{
9828 		if(max>maxvalue) max = maxvalue;
9829 		if(colorbars)
9830 		{
9831 			if(value<=max/4) {bgindex = 0; colourindex = 1;}
9832 			else if(value<=max/2) {bgindex=0; colourindex = 2;}
9833 			else if(value<=max) {bgindex=0; colourindex = 3;}
9834 			else {colourindex = value/(max+1) + 3; bgindex = colourindex-1;}
9835 			if(colourindex>10) colourindex = bgindex = 10;
9836 		}
9837 		else
9838 		{
9839 			colourindex = 2;
9840 			bgindex = value>max? 5:1;
9841 		}
9842 
9843 		len = value%max;
9844 		if(!len && value) len = max;
9845 		alphabg = value>max?0:(BLEND_MULTIPLY+1);
9846 	}
9847 	else if(pstatus->type==percentagebar)
9848 	{
9849 		colourindex = colorbars?(value*5/maxvalue+1):2;
9850 		bgindex = colorbars?8:1;
9851 		len = value * max / maxvalue;
9852 		if(!len && value) len = 1;
9853 		alphabg = BLEND_MULTIPLY+1;
9854 	}
9855 	else return;
9856 
9857 	if(pstatus->orientation==horizontalbar)
9858 	{
9859 		forex = pstatus->direction?(x + max - len):x;
9860 		forey = y;
9861 		forew = len; bkw = max;
9862 		bkh = foreh = pstatus->sizey;
9863 	}
9864 	else if(pstatus->orientation==verticalbar)
9865 	{
9866 		forex = x;
9867 		forey = pstatus->direction?y:(y + max - len);
9868 		bkw = forew = pstatus->sizex;
9869 		foreh = len; bkh = max;
9870 	}
9871 	else return;
9872 
9873 	if(!pstatus->colourtable) pstatus->colourtable = &hpcolourtable;
9874 
9875 	spriteq_add_box(x+1, y+1, bkw, bkh, HUD_Z+1+pstatus->backlayer, (*pstatus->colourtable)[bgindex], alphabg);
9876 	spriteq_add_box(forex+1, forey+1, forew, foreh, HUD_Z+2+pstatus->barlayer, (*pstatus->colourtable)[colourindex], 0);
9877 
9878 	if(pstatus->noborder==0)
9879 	{
9880 		spriteq_add_line(x, y, x+bkw+1, y, HUD_Z+3+pstatus->borderlayer, color_white, 0); //Top border.
9881 		spriteq_add_line(x, y+bkh+1, x+bkw+1, y+bkh+1, HUD_Z+3+pstatus->borderlayer, color_white, 0); //Bottom border.
9882 		spriteq_add_line(x, y+1, x, y+bkh, HUD_Z+3+pstatus->borderlayer, color_white, 0); //Left border.
9883 		spriteq_add_line(x+bkw+1, y+1, x+bkw+1, y+bkh, HUD_Z+3+pstatus->borderlayer, color_white, 0); //Right border.
9884 		spriteq_add_line(x, y+bkh+2, x+bkw+1, y+bkh+2, HUD_Z+pstatus->borderlayer, color_black, 0); //Bottom shadow.
9885 		spriteq_add_line(x+bkw+2, y+1, x+bkw+2, y+bkh+2, HUD_Z+pstatus->borderlayer, color_black, 0); //Right shadow.
9886 	}
9887 }
9888 
9889 
pausemenu()9890 void pausemenu()
9891 {
9892 	int pauselector = 0;
9893 	int quit = 0;
9894 	s_screen* pausebuffer = allocscreen(videomodes.hRes, videomodes.vRes, screenformat);
9895 
9896 	copyscreen(pausebuffer, vscreen);
9897 	spriteq_draw(pausebuffer, 0, MIN_INT, MAX_INT, 0, 0);
9898 	spriteq_clear();
9899 	spriteq_add_screen(0, 0, MIN_INT, pausebuffer, NULL, 0);
9900 	spriteq_lock();
9901 
9902 	pause = 2;
9903 	bothnewkeys = 0;
9904 	while(!quit)
9905 	{
9906 		_menutextm(3, -2, 0, "Pause");
9907 		_menutextm((pauselector==0), -1, 0, "Continue");
9908 		_menutextm((pauselector==1), 0, 0, "End Game");
9909 
9910 		update(1,0);
9911 
9912 		if(bothnewkeys & (FLAG_MOVEUP|FLAG_MOVEDOWN)){
9913 			pauselector ^= 1;
9914 			sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
9915 		}
9916 		if(bothnewkeys & FLAG_START){
9917 			if(pauselector){
9918 				player[0].lives = player[1].lives = player[2].lives = player[3].lives = 0; //4player
9919 				endgame = 1;
9920 			}
9921 			quit = 1;
9922 			sound_pause_music(0);
9923 			sound_pause_sample(0);
9924 			sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
9925 			pauselector = 0;
9926 		}
9927 		if(bothnewkeys & FLAG_ESC){
9928 			quit = 1;
9929 			sound_pause_music(0);
9930 			sound_pause_sample(0);
9931 			sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
9932 			pauselector = 0;
9933 		}
9934 		if(bothnewkeys & FLAG_SCREENSHOT){
9935 			pause = 1;
9936 			sound_pause_music(1);
9937 			sound_pause_sample(1);
9938 			sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
9939 			options();
9940 		}
9941 	}
9942 	pause = 0;
9943 	bothnewkeys = 0;
9944 	spriteq_unlock();
9945 	spriteq_clear();
9946 	freescreen(&pausebuffer);
9947 }
9948 
getFPS(void)9949 unsigned getFPS(void)
9950 {
9951 	static unsigned lasttick=0,framerate = 0;
9952 	unsigned curtick = timer_gettick();
9953 	if(lasttick > curtick) lasttick = curtick;
9954 	framerate = (framerate + (curtick-lasttick))/2;
9955 	lasttick = curtick;
9956 	if(!framerate) return 0;
9957 #ifdef PSP
9958 	return ((10000000/framerate)+9)/10;
9959 #else
9960 	return ((10000000/framerate)+9)/10000;
9961 #endif
9962 }
9963 
updatestatus()9964 void updatestatus(){
9965 
9966 	int dt;
9967 	int tperror=0;
9968 	int i,x;
9969 	s_model * model = NULL;
9970 	s_set_entry *set = levelsets + current_set;
9971 
9972 	for(i=0; i<set->maxplayers; i++)
9973 	{
9974 		if(player[i].ent)
9975 		{
9976 			;
9977 		}
9978 		else if(player[i].joining && player[i].name[0])
9979 		{
9980 			model = findmodel(player[i].name);
9981 			if((player[i].playkeys & FLAG_ANYBUTTON || skipselect[i][0]) && !freezeall && !nojoin)    // Can't join while animations are frozen
9982 			{
9983 				// reports error if players try to use the same character and sameplay mode is off
9984 				if(sameplayer){
9985 					for(x=0; x<set->maxplayers; x++){
9986 						if((strncmp(player[i].name,player[x].name,strlen(player[i].name)) == 0) && (i != x)){
9987 							tperror = i+1;
9988 							break;
9989 						}
9990 					}
9991 				}
9992 
9993 				if (!tperror){    // Fixed so players can be selected if other player is no longer va //4player                        player[i].playkeys = player[i].newkeys = 0;
9994 					player[i].lives = PLAYER_LIVES;            // to address new lives settings
9995 					player[i].joining = 0;
9996 					player[i].hasplayed = 1;
9997 					player[i].spawnhealth = model->health;
9998 					player[i].spawnmp = model->mp;
9999 
10000 					spawnplayer(i);
10001 
10002 					execute_join_script(i);
10003 
10004 					player[i].playkeys = player[i].newkeys = player[i].releasekeys = 0;
10005 
10006 					if(!nodropen) drop_all_enemies();   //27-12-2004  If drop enemies is on, drop all enemies
10007 
10008 					if(!level->noreset) timeleft = level->settime * COUNTER_SPEED;    // Feb 24, 2005 - This line moved here to set custom time
10009 
10010 				}
10011 
10012 			}
10013 			else if(player[i].playkeys & FLAG_MOVELEFT)
10014 			{
10015 				player[i].colourmap = i;
10016 				model = prevplayermodel(model);
10017 				strcpy(player[i].name, model->name);
10018 
10019 				while(   // Keep looping until a non-hmap is found
10020 					((model->maps.hide_start) && (model->maps.hide_end) &&
10021 					player[i].colourmap >= model->maps.hide_start &&
10022 					player[i].colourmap <= model->maps.hide_end)
10023 					)
10024 					{
10025 						player[i].colourmap++;
10026 						if(player[i].colourmap > model->maps_loaded) player[i].colourmap = 0;
10027 					}
10028 
10029 				player[i].playkeys = 0;
10030 			}
10031 			else if(player[i].playkeys & FLAG_MOVERIGHT)
10032 			{
10033 				player[i].colourmap = i;
10034 				model = nextplayermodel(model);
10035 				strcpy(player[i].name, model->name);
10036 
10037 				while(   // Keep looping until a non-hmap is found
10038 					((model->maps.hide_start) && (model->maps.hide_end) &&
10039 					player[i].colourmap >= model->maps.hide_start &&
10040 					player[i].colourmap <= model->maps.hide_end)
10041 					)
10042 					{
10043 						player[i].colourmap++;
10044 						if(player[i].colourmap > model->maps_loaded) player[i].colourmap = 0;
10045 					}
10046 
10047 				player[i].playkeys = 0;
10048 
10049 			}
10050 			// don't like a characters color try a new one!
10051 			else if(player[i].playkeys & FLAG_MOVEUP && colourselect)
10052 			{
10053 
10054 				do{
10055 					player[i].colourmap++;
10056 
10057 					if(player[i].colourmap > model->maps_loaded) player[i].colourmap = 0;
10058 				}
10059 				while(    // Keep looping until a non frozen map is found
10060 					(model->maps.frozen &&
10061 					player[i].colourmap - 1 == model->maps.frozen - 1) ||
10062 					((model->maps.hide_start) && (model->maps.hide_end) &&
10063 					player[i].colourmap - 1 >= model->maps.hide_start - 1 &&
10064 					player[i].colourmap - 1 <= model->maps.hide_end - 1)
10065 					);
10066 
10067 					player[i].playkeys = 0;
10068 			}
10069 			else if(player[i].playkeys & FLAG_MOVEDOWN && colourselect)
10070 			{
10071 
10072 				do{
10073 					player[i].colourmap--;
10074 
10075 					if(player[i].colourmap < 0) player[i].colourmap = model->maps_loaded;
10076 				}
10077 				while(    // Keep looping until a non frozen map is found
10078 					(model->maps.frozen &&
10079 					player[i].colourmap - 1 == model->maps.frozen - 1) ||
10080 					((model->maps.hide_start) && (model->maps.hide_end) &&
10081 					player[i].colourmap - 1 >= model->maps.hide_start - 1 &&
10082 					player[i].colourmap - 1 <= model->maps.hide_end - 1)
10083 					);
10084 
10085 					player[i].playkeys = 0;
10086 			}
10087 		}
10088 		else if(player[i].credits || credits || (!player[i].hasplayed && noshare))
10089 		{
10090 			if(player[i].playkeys & FLAG_START)
10091 			{
10092 				player[i].lives = 0;
10093 				model = skipselect[i][0]?findmodel(skipselect[i]):nextplayermodel(NULL);
10094 				strncpy(player[i].name, model->name, MAX_NAME_LEN);
10095 				player[i].colourmap = i;
10096 				 // Keep looping until a non-hmap is found
10097 				while(model->maps.hide_start && model->maps.hide_end && player[i].colourmap >= model->maps.hide_start && player[i].colourmap <= model->maps.hide_end)
10098 				{
10099 					player[i].colourmap++;
10100 					if(player[i].colourmap > model->maps_loaded) player[i].colourmap = 0;
10101 				}
10102 
10103 				player[i].joining = 1;
10104 				player[i].playkeys = player[i].newkeys = player[i].releasekeys = 0;
10105 
10106 				if(!level->noreset) timeleft = level->settime * COUNTER_SPEED;    // Feb 24, 2005 - This line moved here to set custom time
10107 
10108 				if(!player[i].hasplayed && noshare) player[i].credits = CONTINUES;
10109 
10110 				if(!creditscheat)
10111 				{
10112 					if(noshare) --player[i].credits;
10113 					else --credits;
10114 					if(set->continuescore == 1)player[i].score = 0;
10115 					if(set->continuescore == 2)player[i].score = player[i].score+1;
10116 				}
10117 			}
10118 		}
10119 	}// end of for
10120 
10121 	dt = timeleft/COUNTER_SPEED;
10122 	if(dt>=99)
10123 	{
10124 		dt      = 99;
10125 
10126 		oldtime = 99;
10127 	}
10128 	if(dt<=0)
10129 	{
10130 		dt      = 0;
10131 		oldtime = 99;
10132 	}
10133 
10134 	if(dt < oldtime || oldtime == 0)
10135 	{
10136 		execute_timetick_script(dt, go_time);
10137 		oldtime = dt;
10138 	}
10139 
10140 	timetoshow = dt;
10141 
10142 	if(dt<99) showtimeover = 0;
10143 
10144 	if(go_time>time)
10145 	{
10146 		dt = (go_time-time)%GAME_SPEED;
10147 
10148 		if(dt < GAME_SPEED/2){
10149 			showgo = 1;
10150 			if(gosound == 0 ){
10151 
10152 				if(SAMPLE_GO >= 0) sound_play_sample(SAMPLE_GO, 0, savedata.effectvol,savedata.effectvol, 100);// 26-12-2004 Play go sample as arrow flashes
10153 
10154 				gosound = 1;                // 26-12-2004 Sets sample as already played - stops sample repeating too much
10155 			}
10156 		}else showgo = gosound = 0;    //26-12-2004 Resets go sample after loop so it can be played again next time
10157 	}else showgo = 0;
10158 
10159 }
10160 
predrawstatus()10161 void predrawstatus(){
10162 
10163 	int icon = 0;
10164 	int i;
10165 	unsigned long tmp;
10166 	s_set_entry* set = levelsets+current_set;
10167 	s_model * model = NULL;
10168 	s_drawmethod drawmethod = plainmethod;
10169 
10170 	if(bgicon >= 0) spriteq_add_sprite(videomodes.hShift+bgicon_offsets[0],savedata.windowpos+bgicon_offsets[1], bgicon_offsets[2], bgicon, NULL, 0);
10171 	if(olicon >= 0) spriteq_add_sprite(videomodes.hShift+olicon_offsets[0],savedata.windowpos+olicon_offsets[1], olicon_offsets[2], olicon, NULL, 0);
10172 
10173 	for(i=0; i<set->maxplayers; i++)
10174 	{
10175 		if(player[i].ent)
10176 		{
10177 			tmp = player[i].score; //work around issue on 64bit where sizeof(long) != sizeof(int)
10178 			if(!pscore[i][2] && !pscore[i][3] && !pscore[i][4] && !pscore[i][5])
10179 		    font_printf(videomodes.shiftpos[i]+pscore[i][0], savedata.windowpos+pscore[i][1], pscore[i][6], 0, (scoreformat ? "%s - %09lu" : "%s - %lu"), (char*)(player[i].ent->name), tmp);
10180 			else
10181 			{
10182 				font_printf(videomodes.shiftpos[i]+pscore[i][0], savedata.windowpos+pscore[i][1], pscore[i][6], 0, "%s", player[i].ent->name);
10183 				font_printf(videomodes.shiftpos[i]+pscore[i][2], savedata.windowpos+pscore[i][3], pscore[i][6], 0, "-");
10184 				font_printf(videomodes.shiftpos[i]+pscore[i][4], savedata.windowpos+pscore[i][5], pscore[i][6], 0, (scoreformat ? "%09lu" : "%lu"), tmp);
10185 			}
10186 
10187 			if(player[i].ent->health <= 0) icon = player[i].ent->modeldata.icon.die;
10188 			else if(player[i].ent->inpain) icon = player[i].ent->modeldata.icon.pain;
10189 			else if(player[i].ent->getting) icon = player[i].ent->modeldata.icon.get;
10190 			else icon = player[i].ent->modeldata.icon.def;
10191 
10192 			if(icon>=0)
10193 			{
10194 				drawmethod.table = player[i].ent->colourmap;
10195 				spriteq_add_sprite(videomodes.shiftpos[i]+picon[i][0],savedata.windowpos+picon[i][1],10000, icon, &drawmethod, 0);
10196 			}
10197 
10198 			if(player[i].ent->weapent)
10199 			{
10200 				if(player[i].ent->weapent->modeldata.icon.weapon >= 0)
10201 				{
10202 					drawmethod.table = player[i].ent->weapent->colourmap;
10203 					spriteq_add_sprite(videomodes.shiftpos[i]+piconw[i][0],savedata.windowpos+piconw[i][1],10000, player[i].ent->weapent->modeldata.icon.weapon, &drawmethod, 0);
10204 				}
10205 
10206 				if(player[i].ent->weapent->modeldata.typeshot && player[i].ent->weapent->modeldata.shootnum)
10207 					font_printf(videomodes.shiftpos[i]+pshoot[i][0], savedata.windowpos+pshoot[i][1], pshoot[i][2], 0, "%u", player[i].ent->weapent->modeldata.shootnum);
10208 			}
10209 
10210 			if(player[i].ent->modeldata.mp)
10211 			{
10212 				if(player[i].ent->modeldata.icon.mphigh > 0 && (player[i].ent->oldmp >= (player[i].ent->modeldata.mp * .66))){
10213 					drawmethod.table = player[i].ent->colourmap;
10214 					spriteq_add_sprite(videomodes.shiftpos[i]+mpicon[i][0],savedata.windowpos+mpicon[i][1],10000, player[i].ent->modeldata.icon.mphigh, &drawmethod, 0);
10215 				}
10216 				else if(player[i].ent->modeldata.icon.mpmed > 0 && (player[i].ent->oldmp >= (player[i].ent->modeldata.mp * .33) && player[i].ent->oldmp < (player[i].ent->modeldata.mp * .66))){
10217 					drawmethod.table = player[i].ent->colourmap;
10218 					spriteq_add_sprite(videomodes.shiftpos[i]+mpicon[i][0],savedata.windowpos+mpicon[i][1],10000, player[i].ent->modeldata.icon.mpmed, &drawmethod, 0);
10219 				}
10220 				else if(player[i].ent->modeldata.icon.mplow > 0 && (player[i].ent->oldmp >= 0 && player[i].ent->oldmp < (player[i].ent->modeldata.mp * .33))){
10221 					drawmethod.table = player[i].ent->colourmap;
10222 					spriteq_add_sprite(videomodes.shiftpos[i]+mpicon[i][0],savedata.windowpos+mpicon[i][1],10000, player[i].ent->modeldata.icon.mplow, &drawmethod, 0);
10223 				}
10224 				else if(player[i].ent->modeldata.icon.mphigh > 0 && player[i].ent->modeldata.icon.mpmed == -1 && player[i].ent->modeldata.icon.mplow == -1){
10225 					drawmethod.table = player[i].ent->colourmap;
10226 					spriteq_add_sprite(videomodes.shiftpos[i]+mpicon[i][0],savedata.windowpos+mpicon[i][1],10000, player[i].ent->modeldata.icon.mphigh, &drawmethod, 0);
10227 				}
10228 			}
10229 
10230 			font_printf(videomodes.shiftpos[i]+plifeX[i][0],savedata.windowpos+plifeX[i][1], plifeX[i][2], 0, "x");
10231 			font_printf(videomodes.shiftpos[i]+plifeN[i][0],savedata.windowpos+plifeN[i][1], plifeN[i][2], 0, "%i", player[i].lives);
10232 
10233 			if(rush[0] && player[i].ent->rush[0] > 1 && time <= player[i].ent->rushtime)
10234 			{
10235 				font_printf(videomodes.shiftpos[i]+prush[i][0],prush[i][1], rush[2], 0, "%s", rush_names[0]);
10236 				font_printf(videomodes.shiftpos[i]+prush[i][2],prush[i][3], rush[3], 0, "%i", player[i].ent->rush[0]);
10237 
10238 				if(rush[0] != 2){
10239 					font_printf(videomodes.shiftpos[i]+prush[i][4],prush[i][5], rush[4], 0, "%s", rush_names[1]);
10240 					font_printf(videomodes.shiftpos[i]+prush[i][6],prush[i][7], rush[5], 0, "%i", player[i].ent->rush[1]);
10241 				}
10242 			}
10243 
10244 			if(rush[0] == 2)
10245 			{
10246 				font_printf(videomodes.shiftpos[i]+prush[i][4],prush[i][5], rush[4], 0, "%s", rush_names[1]);
10247 				font_printf(videomodes.shiftpos[i]+prush[i][6],prush[i][7], rush[5], 0, "%i", player[i].ent->rush[1]);
10248 			}
10249 
10250 			if(player[i].ent->opponent && !player[i].ent->opponent->modeldata.nolife)
10251 			{    // Displays life unless overridden by flag
10252 				font_printf(videomodes.shiftpos[i]+ename[i][0], savedata.windowpos+ename[i][1], ename[i][2], 0, player[i].ent->opponent->name);
10253 				if(player[i].ent->opponent->health <= 0) icon = player[i].ent->opponent->modeldata.icon.die;
10254 				else if(player[i].ent->opponent->inpain) icon = player[i].ent->opponent->modeldata.icon.pain;
10255 				else if(player[i].ent->opponent->getting) icon = player[i].ent->opponent->modeldata.icon.get;
10256 				else icon = player[i].ent->opponent->modeldata.icon.def;
10257 
10258 				if(icon>=0)
10259 				{
10260 					drawmethod.table = player[i].ent->opponent->colourmap;
10261 					spriteq_add_sprite(videomodes.shiftpos[i]+eicon[i][0],savedata.windowpos+eicon[i][1],10000, icon, &drawmethod, 0);    // Feb 26, 2005 - Changed to opponent->map so icons don't pallete swap with die animation
10262 				}
10263 			}
10264 		}
10265 		else if(player[i].joining && player[i].name[0])
10266 		{
10267 			model = findmodel(player[i].name);
10268 			font_printf(videomodes.shiftpos[i]+pnameJ[i][0], savedata.windowpos+pnameJ[i][1], pnameJ[i][6], 0, player[i].name);
10269 			if(nojoin) font_printf(videomodes.shiftpos[i]+pnameJ[i][2], savedata.windowpos+pnameJ[i][3], pnameJ[i][6], 0, "Please Wait");
10270 			else font_printf(videomodes.shiftpos[i]+pnameJ[i][2], savedata.windowpos+pnameJ[i][3], pnameJ[i][6], 0, "Select Hero");
10271 			icon = model->icon.def;
10272 
10273 			if(icon>=0)
10274 			{
10275 				drawmethod.table = player[i].colourmap?model->colourmap[player[i].colourmap - 1]:model->palette;
10276 				spriteq_add_sprite(videomodes.shiftpos[i]+picon[i][0],picon[i][1], 10000, icon, &drawmethod, 0);
10277 			}
10278 		}
10279 		else if(player[i].credits || credits || (!player[i].hasplayed && noshare))
10280 		{
10281 			if(player[i].credits && (time/(GAME_SPEED*2)) & 1) font_printf(videomodes.shiftpos[i]+pnameJ[i][4], savedata.windowpos+pnameJ[i][5], pnameJ[i][6], 0, "Credit %i", player[i].credits);
10282 			else if(credits && (time/(GAME_SPEED*2)) & 1) font_printf(videomodes.shiftpos[i]+pnameJ[i][4], savedata.windowpos+pnameJ[i][5], pnameJ[i][6], 0, "Credit %i", credits);
10283 			else if(nojoin) font_printf(videomodes.shiftpos[i]+pnameJ[i][4], savedata.windowpos+pnameJ[i][5], pnameJ[i][6], 0, "Please Wait");
10284 			else font_printf(videomodes.shiftpos[i]+pnameJ[i][4], savedata.windowpos+pnameJ[i][5], pnameJ[i][6], 0, "Press Start");
10285 
10286 		}
10287 		else
10288 		{
10289 			font_printf(videomodes.shiftpos[i]+pnameJ[i][4], savedata.windowpos+pnameJ[i][5], pnameJ[i][6], 0, "GAME OVER");
10290 		}
10291 	}// end of for
10292 
10293 	if(savedata.debuginfo)
10294 	{
10295 		spriteq_add_box(0, videomodes.dOffset-12, videomodes.hRes, videomodes.dOffset+12, 0x0FFFFFFE, 0, 0);
10296 		font_printf(2,                   videomodes.dOffset-10, 0, 0, "FPS: %03d", getFPS());
10297 		font_printf(videomodes.hRes / 2, videomodes.dOffset-10, 0, 0, "Free Ram: %s KBytes", commaprint(freeram/1000));
10298 		font_printf(2,                   videomodes.dOffset,    0, 0, "Total Ram: %s KBytes", commaprint(totalram/1000));
10299 		font_printf(videomodes.hRes / 2, videomodes.dOffset,    0, 0, "Used Ram: %s KBytes", commaprint(usedram/1000));
10300 	}
10301 
10302 	if(timeicon >= 0) spriteq_add_sprite(videomodes.hShift+timeicon_offsets[0], savedata.windowpos+timeicon_offsets[1],10000, timeicon, NULL, 0);
10303 	if(!level->notime) font_printf(videomodes.hShift+timeloc[0]+2, savedata.windowpos+timeloc[1]+2, timeloc[5], 0, "%02i", timetoshow);
10304 	if(showtimeover) font_printf(videomodes.hShift+113, videomodes.vShift+savedata.windowpos+110, timeloc[5], 0, "TIME OVER");
10305 
10306 	if(showgo){
10307 		if(level->scrolldir&SCROLL_LEFT){ //TODO: upward and downward go
10308 
10309 			if(golsprite >= 0) spriteq_add_sprite(40,60+videomodes.vShift,10000, golsprite, NULL, 0); // new sprite for left direction
10310 			else
10311 			{
10312 				drawmethod.table = 0;
10313 				drawmethod.flipx = 1;
10314 				spriteq_add_sprite(40,60+videomodes.vShift,10000, gosprite, &drawmethod, 0);
10315 			}
10316 		}
10317 		else if(level->scrolldir&SCROLL_RIGHT){
10318 			spriteq_add_sprite(videomodes.hRes-40,60+videomodes.vShift,10000, gosprite, NULL, 0);
10319 		}
10320 	}
10321 }
10322 
10323 // draw boss status on screen
drawenemystatus(entity * ent)10324 void drawenemystatus(entity* ent)
10325 {
10326 	s_drawmethod drawmethod;
10327 	int icon;
10328 
10329 	if(ent->modeldata.namex>-1000 && ent->modeldata.namey>-1000) font_printf(ent->modeldata.namex, ent->modeldata.namey, 0, 0, "%s", ent->name);
10330 
10331 	if(ent->modeldata.icon.x>-1000 &&  ent->modeldata.icon.y>-1000)
10332 	{
10333 		if(ent->health <= 0) icon = ent->modeldata.icon.die;
10334 		else if(ent->inpain) icon = ent->modeldata.icon.pain;
10335 		else if(ent->getting) icon = ent->modeldata.icon.get;
10336 		else icon = ent->modeldata.icon.def;
10337 
10338 		if(icon>=0)
10339 		{
10340 			drawmethod = plainmethod;
10341 			drawmethod.table = ent->colourmap;
10342 			spriteq_add_sprite(ent->modeldata.icon.x, ent->modeldata.icon.y, HUD_Z, icon, &drawmethod, 0);
10343 		}
10344 	}
10345 
10346 	if(ent->modeldata.health && ent->modeldata.hpx>-1000 && ent->modeldata.hpy>-1000)
10347 		bar(ent->modeldata.hpx, ent->modeldata.hpy, ent->oldhealth, ent->modeldata.health, &(ent->modeldata.hpbarstatus));
10348 }
10349 
10350 
drawstatus()10351 void drawstatus(){
10352 	int i;
10353 
10354 	for(i=0; i < MAX_PLAYERS; i++)
10355 	{
10356 		if(player[i].ent)
10357 		{
10358 			// Health bars
10359 			bar(videomodes.shiftpos[i]+plife[i][0],savedata.windowpos+plife[i][1], player[i].ent->oldhealth, player[i].ent->modeldata.health, &lbarstatus);
10360 			if(player[i].ent->opponent && !player[i].ent->opponent->modeldata.nolife && player[i].ent->opponent->modeldata.health)
10361 				bar(videomodes.shiftpos[i]+elife[i][0], savedata.windowpos+elife[i][1], player[i].ent->opponent->oldhealth, player[i].ent->opponent->modeldata.health,&olbarstatus); // Tied in with the nolife flag
10362 			// Draw mpbar
10363 			if(player[i].ent->modeldata.mp)
10364 			{
10365 				bar(videomodes.shiftpos[i]+pmp[i][0], savedata.windowpos+pmp[i][1], player[i].ent->oldmp, player[i].ent->modeldata.mp, &mpbarstatus);
10366 			}
10367 		}
10368 	}
10369 
10370 	// Time box
10371 	if(!level->notime && !timeloc[4])    // Only draw if notime is set to 0 or not specified
10372 	{
10373 		spriteq_add_line(videomodes.hShift+timeloc[0],                savedata.windowpos+timeloc[1],                videomodes.hShift+timeloc[0]+timeloc[2],     savedata.windowpos+timeloc[1],                HUD_Z, color_black, 0);
10374 		spriteq_add_line(videomodes.hShift+timeloc[0],                savedata.windowpos+timeloc[1],                videomodes.hShift+timeloc[0],                savedata.windowpos+timeloc[1]+timeloc[3],     HUD_Z,  color_black, 0);
10375 		spriteq_add_line(videomodes.hShift+timeloc[0]+timeloc[2],     savedata.windowpos+timeloc[1],                videomodes.hShift+timeloc[0]+timeloc[2],     savedata.windowpos+timeloc[1]+timeloc[3],     HUD_Z,  color_black, 0);
10376 		spriteq_add_line(videomodes.hShift+timeloc[0],                savedata.windowpos+timeloc[1]+timeloc[3],     videomodes.hShift+timeloc[0]+timeloc[2],     savedata.windowpos+timeloc[1]+timeloc[3],     HUD_Z, color_black, 0);
10377 		spriteq_add_line(videomodes.hShift+timeloc[0] - 1,            savedata.windowpos+timeloc[1] - 1,            videomodes.hShift+timeloc[0]+timeloc[2] - 1, savedata.windowpos+timeloc[1] - 1,            HUD_Z+1,   color_white, 0);
10378 		spriteq_add_line(videomodes.hShift+timeloc[0] - 1,            savedata.windowpos+timeloc[1] - 1,            videomodes.hShift+timeloc[0] - 1,            savedata.windowpos+timeloc[1]+timeloc[3] - 1, HUD_Z+1,  color_white, 0);
10379 		spriteq_add_line(videomodes.hShift+timeloc[0]+timeloc[2] - 1, savedata.windowpos+timeloc[1] - 1,            videomodes.hShift+timeloc[0]+timeloc[2] - 1, savedata.windowpos+timeloc[1]+timeloc[3] - 1, HUD_Z+1,  color_white, 0);
10380 		spriteq_add_line(videomodes.hShift+timeloc[0] - 1,            savedata.windowpos+timeloc[1]+timeloc[3] - 1, videomodes.hShift+timeloc[0]+timeloc[2] - 1, savedata.windowpos+timeloc[1]+timeloc[3] - 1, HUD_Z+1, color_white, 0);
10381 	}
10382 }
10383 
update_loading(s_loadingbar * s,int value,int max)10384 void update_loading(s_loadingbar* s,  int value, int max) {
10385 	static unsigned int lasttick = 0;
10386 	static unsigned int soundtick = 0;
10387 	static unsigned int keybtick = 0;
10388 	int pos_x = s->bx + videomodes.hShift;
10389 	int pos_y = s->by + videomodes.vShift;
10390 	int size_x = s->bsize;
10391 	int text_x = s->tx + videomodes.hShift;
10392 	int text_y = s->ty + videomodes.vShift;
10393 	unsigned int ticks = timer_gettick();
10394 
10395 	if(ticks - soundtick > 20) {
10396 		sound_update_music();
10397 		soundtick = ticks;
10398 	}
10399 
10400 	if(ticks - keybtick > 250) {
10401 		control_update(playercontrolpointers, 1); // Respond to exit and/or fullscreen requests from user/OS
10402 		keybtick = ticks;
10403 	}
10404 
10405 
10406 	if(ticks - lasttick > s->refreshMs || value < 0 || value == max) { // Negative value forces a repaint. used when only bg is drawn for the first time
10407 		spriteq_clear();
10408 		execute_loading_script(value, max);
10409 		if(s->set) {
10410 			if (value < 0) value = 0;
10411 			if(isLoadingScreenTypeBar(s->set)) {
10412 				loadingbarstatus.sizex = size_x;
10413 				bar(pos_x, pos_y, value, max, &loadingbarstatus);
10414 			}
10415 			font_printf(text_x, text_y, s->tf, 0, "Loading...");
10416 			if(isLoadingScreenTypeBg(s->set)) {
10417 				if(background)
10418 					putscreen(vscreen, background, 0, 0, NULL);
10419 				else
10420 					clearscreen(vscreen);
10421 			}
10422 			spriteq_draw(vscreen, 0, MIN_INT, MAX_INT, 0, 0);
10423 			video_copy_screen(vscreen);
10424 			spriteq_clear();
10425 		}
10426 		else if(value < 0) { // Original BOR v1.0029 used this method.  Since loadingbg is optional, we should print this one again.
10427 			clearscreen(vscreen);
10428 			font_printf(120 + videomodes.hShift, 110 + videomodes.vShift, 0, 0, "Loading...");
10429 			spriteq_draw(vscreen, 0, MIN_INT, MAX_INT, 0, 0);
10430 			video_copy_screen(vscreen);
10431 			spriteq_clear();
10432 		}
10433 		lasttick = ticks;
10434 	}
10435 }
10436 
addscore(int playerindex,int add)10437 void addscore(int playerindex, int add){
10438 	unsigned int s ;
10439 	unsigned int next1up;
10440 	ScriptVariant var; // used for execute script
10441 	Script* cs;
10442 
10443 	if(playerindex < 0) return;//dont score if <0, e.g., npc damage enemy, enemy damage enemy
10444 
10445 	playerindex &= 3;
10446 
10447 	s = player[playerindex].score;
10448 	cs = score_script + playerindex;
10449 
10450 	next1up = ((s/lifescore)+1) * lifescore;
10451 
10452 	s += add;
10453 	if(s>999999999) s=999999999;
10454 
10455 	while(s>next1up){
10456 
10457 		if(SAMPLE_1UP >= 0) sound_play_sample(SAMPLE_1UP, 0, savedata.effectvol,savedata.effectvol, 100);
10458 
10459 		player[playerindex].lives++;
10460 		next1up += lifescore;
10461 	}
10462 
10463 	player[playerindex].score = s;
10464 
10465 	//execute a script then
10466 	if(Script_IsInitialized(cs))
10467 	{
10468 		ScriptVariant_Init(&var);
10469 		ScriptVariant_ChangeType(&var, VT_INTEGER);
10470 		var.lVal = (LONG)add;
10471 		Script_Set_Local_Variant(cs, "score", &var);
10472 		Script_Execute(score_script+playerindex);
10473 		ScriptVariant_Clear(&var);
10474 		Script_Set_Local_Variant(cs, "score", &var);
10475 	}
10476 }
10477 
10478 
10479 
10480 
10481 // ---------------------------- Object handling ------------------------------
10482 
free_ent(entity * e)10483 void free_ent(entity* e)
10484 {
10485 	int i;
10486 	if(!e) return;
10487 	clear_all_scripts(e->scripts,2);
10488 	free_all_scripts(&e->scripts);
10489 
10490 	if(e->waypoints) { free(e->waypoints); e->waypoints = NULL;}
10491 	if(e->defense){ free(e->defense); e->defense = NULL; }
10492 	if(e->offense_factors){ free(e->offense_factors); e->offense_factors = NULL; }
10493 	if(e->entvars)
10494 	{
10495 		// Although free_ent will be only called once when the engine is shutting down,
10496 		// just clear those in case we forget something
10497 		for(i=0; i<max_entity_vars; i++)
10498 		{
10499 			ScriptVariant_Clear(e->entvars+i);
10500 		}
10501 		free(e->entvars); e->entvars = NULL;
10502 	}
10503 	free(e);
10504 	e = NULL;
10505 }
10506 
free_ents()10507 void free_ents()
10508 {
10509 	int i;
10510 	if(!ent_list) return;
10511 	for(i=0; i<ent_list_size; i++) free_ent(ent_list[i]);
10512 	free(ent_list);
10513 	ent_list = NULL;
10514 	ent_list_size = ent_max = ent_count = 0;
10515 }
10516 
alloc_ent()10517 entity* alloc_ent()
10518 {
10519 	entity* ent = (entity*)malloc(sizeof(entity));
10520 	if(!ent) return NULL;
10521 	memset(ent, 0, sizeof(entity));
10522 	ent->defense = (s_defense*)malloc(sizeof(s_defense)*max_attack_types);
10523 	memset(ent->defense, 0, sizeof(s_defense)*max_attack_types);
10524 	ent->offense_factors = (float*)malloc(sizeof(float)*max_attack_types);
10525 	memset(ent->offense_factors, 0, sizeof(float)*max_attack_types);
10526 	if(max_entity_vars>0)
10527 	{
10528 		ent->entvars = (ScriptVariant*)malloc(sizeof(ScriptVariant)*max_entity_vars);
10529 		// memset should be OK by know, because VT_EMPTY is zero by value, or else we should use ScriptVariant_Init
10530 		memset(ent->entvars, 0, sizeof(ScriptVariant)*max_entity_vars);
10531 	}
10532 	alloc_all_scripts(&ent->scripts);
10533 	return ent;
10534 }
10535 
10536 
alloc_ents()10537 int alloc_ents()
10538 {
10539 	int i;
10540 
10541 	ent_list_size += MAX_ENTS;
10542 
10543 	if(!ent_list) ent_list = malloc(sizeof(entity*)*ent_list_size);
10544 	else ent_list = realloc(ent_list, sizeof(entity*)*ent_list_size);
10545 
10546 	if(!ent_list) goto alloc_ents_error;
10547 
10548 	for(i=ent_list_size-MAX_ENTS; i<ent_list_size; i++)
10549 	{
10550 		ent_list[i] = alloc_ent();
10551 		if(!ent_list[i])
10552 		{
10553 			 goto alloc_ents_error;
10554 		}
10555 		ent_list[i]->sortid = i*100;
10556 	}
10557 	//ent_count = ent_max = 0;
10558 	return 1;
10559 
10560 alloc_ents_error:
10561 	free_ents();
10562 	return 0;
10563 }
10564 
10565 // this method initialize an entity's A.I. behaviors
ent_default_init(entity * e)10566 void ent_default_init(entity* e)
10567 {
10568 	int dodrop;
10569 	int wall;
10570 	entity *other;
10571 
10572 	if(!e) return;
10573 
10574 	if((!selectScreen && !time) || e->modeldata.type != TYPE_PLAYER )
10575 	{
10576 		if( validanim(e,ANI_SPAWN)) ent_set_anim(e, ANI_SPAWN, 0); // use new playerselect spawn anim
10577 		//else set_idle(e);
10578 	}
10579 	else if(!selectScreen && time && e->modeldata.type == TYPE_PLAYER) // mid-level respawn
10580 	{
10581 		if( validanim(e,ANI_RESPAWN)) ent_set_anim(e, ANI_RESPAWN, 0);
10582 		else if( validanim(e,ANI_SPAWN)) ent_set_anim(e, ANI_SPAWN, 0);
10583 		//else set_idle(e);
10584 	}
10585 	else if(selectScreen && validanim(e,ANI_SELECT)) ent_set_anim(e, ANI_SELECT, 0);
10586 	//else set_idle(e);
10587 
10588 	if(!level)
10589 	{
10590 		if(!e->animation) set_idle(e);
10591 		return;
10592 	}
10593 
10594 	switch(e->modeldata.type){
10595 		case TYPE_ENDLEVEL:
10596 		case TYPE_ITEM:
10597 			e->nograb = 1;
10598 			break;
10599 
10600 		case TYPE_PLAYER:
10601 			//e->direction = (level->scrolldir != SCROLL_LEFT);
10602 			e->takedamage = player_takedamage;
10603 			e->think = player_think;
10604 			e->trymove = player_trymove;
10605 
10606 			if(validanim(e,ANI_SPAWN) || validanim(e,ANI_RESPAWN))
10607 			{
10608 				e->takeaction = common_spawn;
10609 			}
10610 			else if(!e->animation)
10611 			{
10612 				if(time && level->spawn[(int)e->playerindex][2] > e->a)
10613 				{
10614 					e->takeaction = common_drop;
10615 					e->a = (float)level->spawn[(int)e->playerindex][2];
10616 					if(validanim(e, ANI_JUMP))
10617 					ent_set_anim(e, ANI_JUMP, 0);
10618 				}
10619 			}
10620 			if(time && e->modeldata.makeinv)
10621 			{
10622 						// Spawn invincible code
10623 				e->invincible = 1;
10624 				e->blink = (e->modeldata.makeinv > 0);
10625 				e->invinctime = time + ABS(e->modeldata.makeinv);
10626 				e->arrowon = 1;    // Display the image above the player
10627 			}
10628 			break;
10629 		case TYPE_NPC: // use NPC(or A.I. player) instread of an enemy subtype or trap subtype, for further A.I. use
10630 			if(e->modeldata.multiple ==0) e->modeldata.multiple = -1;
10631 
10632 		case TYPE_ENEMY:
10633 			e->think = common_think;
10634 			if(e->modeldata.subtype == SUBTYPE_BIKER)
10635 			{
10636 				e->nograb = 1;
10637 				e->attacking = 1;
10638 				//e->direction = (e->x<0);
10639 				if(e->modeldata.speed)
10640 					e->xdir = (e->direction)?(e->modeldata.speed):(-e->modeldata.speed);
10641 				else
10642 					e->xdir = (e->direction)?(1.7 + randf((float)0.6)):(-(1.7 + randf((float)0.6)));
10643 				e->takedamage = biker_takedamage;
10644 				break;
10645 			}
10646 			// define new subtypes
10647 			else if(e->modeldata.subtype == SUBTYPE_ARROW)
10648 			{
10649 				e->health = 1;
10650 				if(!e->modeldata.speed && !e->modeldata.nomove)
10651 					e->modeldata.speed = 2;    // Set default speed to 2 for arrows
10652 				else if(e->modeldata.nomove)
10653 					e->modeldata.speed = 0;
10654 				if(e->ptype)
10655 					e->base = 0;
10656 				else
10657 					e->base = e->a;
10658 				e->nograb = 1;
10659 				e->attacking = 1;
10660 				e->takedamage = arrow_takedamage;
10661 				break;
10662 			}
10663 			else
10664 			{
10665 				e->trymove = common_trymove;
10666 				// Must just be a regular enemy, set defaults accordingly
10667 				if(!e->modeldata.speed && !e->modeldata.nomove)
10668 					e->modeldata.speed = 1;
10669 				else if(e->modeldata.nomove)
10670 					e->modeldata.speed = 0;
10671 				if(e->modeldata.multiple==0)
10672 					e->modeldata.multiple = 5;
10673 				e->takedamage = common_takedamage;//enemy_takedamage;
10674 			}
10675 
10676 			if(e->modeldata.subtype == SUBTYPE_NOTGRAB) e->nograb = 1;
10677 
10678 			if(validanim(e,ANI_SPAWN) /*|| validanim(e,ANI_RESPAWN)*/)
10679 			{
10680 				e->takeaction = common_spawn;
10681 			}
10682 			else
10683 			{
10684 				dodrop = (e->modeldata.subtype != SUBTYPE_ARROW && level && (level->scrolldir==SCROLL_UP || level->scrolldir==SCROLL_DOWN));
10685 
10686 				if(!nodropspawn && (dodrop || (e->x > advancex-30 && e->x < advancex + videomodes.hRes+30 && e->a == 0)) )
10687 				{
10688 					e->a += videomodes.vRes + randf(40);
10689 				}
10690 				if(inair(e)){
10691 					e->takeaction = common_drop;//enemy_drop;
10692 					if(validanim(e, ANI_JUMP)) ent_set_anim(e, ANI_JUMP, 0);
10693 				}
10694 			}
10695 			break;
10696 		// define trap type
10697 		case TYPE_TRAP:
10698 			e->think = trap_think;
10699 			e->takedamage =  common_takedamage;//enemy_takedamage;
10700 			break;
10701 		case TYPE_OBSTACLE:
10702 			e->nograb = 1;
10703 			if(e->health<=0)
10704 				e->dead = 1; // so it won't get hit
10705 			e->takedamage = obstacle_takedamage;//obstacle_takedamage;
10706 			break;
10707 		case TYPE_STEAMER:
10708 			e->nograb = 1;
10709 			e->think = steamer_think;
10710 			e->base = e->a;
10711 			break;
10712 		case TYPE_TEXTBOX:    // New type for displaying text purposes
10713 			e->nograb = 1;
10714 			e->think = text_think;
10715 			break;
10716 		case TYPE_SHOT:
10717 			e->health = 1;
10718 			e->nograb = 1;
10719 			e->think = common_think;
10720 			e->takedamage = arrow_takedamage;
10721 			e->attacking = 1;
10722 			if(!e->model->speed && !e->modeldata.nomove)
10723 				e->modeldata.speed = 2;    // Set default speed to 2 for arrows
10724 			else if(e->modeldata.nomove)
10725 				e->modeldata.speed = 0;
10726 			if(e->ptype)
10727 				e->base = 0;
10728 			else
10729 				e->base = e->a;
10730 			break;
10731 		case TYPE_NONE:
10732 			e->nograb = 1;
10733 			if(e->modeldata.subject_to_gravity<0) e->modeldata.subject_to_gravity = 1;
10734 			//e->base=e->a; //complained?
10735 			if(e->modeldata.no_adjust_base<0) e->modeldata.no_adjust_base= 1;
10736 
10737 			if(validanim(e,ANI_WALK))
10738 			{
10739 				if(e->direction) e->xdir = e->modeldata.speed;
10740 				else e->xdir = -(e->modeldata.speed);
10741 				e->think = anything_walk;
10742 
10743 				common_walk_anim(e);
10744 				//ent_set_anim(e, ANI_WALK, 0);
10745 			}
10746 			break;
10747 		case TYPE_PANEL:
10748 			e->nograb = 1;
10749 			break;
10750 	}
10751 
10752 	if(!e->animation){
10753 		set_idle(e);
10754 	}
10755 
10756 	if(e->modeldata.multiple < 0)
10757 		e->modeldata.multiple = 0;
10758 
10759 	if(e->modeldata.subject_to_platform>0 && (other=check_platform_below(e->x, e->z, e->a, e)))
10760 		e->base += other->a + other->animation->platform[other->animpos][7];
10761 	else if(e->modeldata.subject_to_wall>0 && (wall=checkwall_below(e->x, e->z, 9999999)) >= 0)
10762 		e->base += level->walls[wall][7];
10763 }
10764 
ent_spawn_ent(entity * ent)10765 void ent_spawn_ent(entity* ent)
10766 {
10767 	entity* s_ent = NULL;
10768 	float* spawnframe = ent->animation->spawnframe;
10769 	float dy = level?4.0:0.0;
10770 	// spawn point relative to current entity
10771 	if(spawnframe[4] == 0)
10772 		s_ent = spawn(ent->x + ((ent->direction)?spawnframe[1]:-spawnframe[1]),ent->z + spawnframe[2], ent->a + spawnframe[3], ent->direction, NULL, ent->animation->subentity, NULL);
10773 	//relative to screen position
10774 	else if(spawnframe[4] == 1)
10775 	{
10776 		if(level && !(level->scrolldir&SCROLL_UP) && !(level->scrolldir&SCROLL_DOWN))
10777 			s_ent = spawn(advancex+spawnframe[1], advancey+spawnframe[2]+dy, spawnframe[3], 0, NULL, ent->animation->subentity, NULL);
10778 		else
10779 			s_ent = spawn(advancex+spawnframe[1], spawnframe[2]+dy, spawnframe[3], 0, NULL, ent->animation->subentity, NULL);
10780 	}
10781 	//absolute position in level
10782 	else s_ent = spawn(spawnframe[1], spawnframe[2], spawnframe[3]+0.001, 0, NULL, ent->animation->subentity, NULL);
10783 
10784 	if(s_ent)
10785 	{
10786 		//ent_default_init(s_ent);
10787 		if(s_ent->modeldata.type & TYPE_SHOT) s_ent->playerindex = ent->playerindex;
10788 		if(s_ent->modeldata.subtype == SUBTYPE_ARROW) s_ent->owner = ent;
10789 		s_ent->parent = ent;  //maybe used by A.I.
10790 		execute_onspawn_script(s_ent);
10791 	}
10792 }
10793 
ent_summon_ent(entity * ent)10794 void ent_summon_ent(entity* ent){
10795 	entity* s_ent = NULL;
10796 	float* spawnframe = ent->animation->summonframe;
10797 	float dy = level?4.0:0.0;
10798 	// spawn point relative to current entity
10799 	if(spawnframe[4] == 0)
10800 		s_ent = spawn(ent->x + ((ent->direction)?spawnframe[1]:-spawnframe[1]),ent->z + spawnframe[2],  ent->a + spawnframe[3], ent->direction, NULL, ent->animation->subentity, NULL);
10801 	//relative to screen position
10802 	else if(spawnframe[4] == 1)
10803 	{
10804 		if(level && !(level->scrolldir&SCROLL_UP) && !(level->scrolldir&SCROLL_DOWN))
10805 			s_ent = spawn(advancex+spawnframe[1], advancey+spawnframe[2]+dy, spawnframe[3], 0, NULL, ent->animation->subentity, NULL);
10806 		else
10807 			s_ent = spawn(advancex+spawnframe[1], spawnframe[2]+dy, spawnframe[3], 0, NULL, ent->animation->subentity, NULL);
10808 	}
10809 	//absolute position in level
10810 	else
10811 		s_ent = spawn(spawnframe[1], spawnframe[2], spawnframe[3], 0, NULL, ent->animation->subentity, NULL);
10812 
10813 	if(s_ent)
10814 	{
10815 		if(!spawnframe[4])
10816 			s_ent->direction = ent->direction;
10817 		//ent_default_init(s_ent);
10818 		if(s_ent->modeldata.type & TYPE_SHOT)
10819 			s_ent->playerindex = ent->playerindex;
10820 		if(s_ent->modeldata.subtype == SUBTYPE_ARROW)
10821 			s_ent->owner = ent;
10822 		//maybe used by A.I.
10823 		s_ent->parent = ent;
10824 		ent->subentity = s_ent;
10825 		execute_onspawn_script(s_ent);
10826 	}
10827 }
10828 
10829 // move here to prevent some duplicated code in ent_sent_anim and update_ents
update_frame(entity * ent,int f)10830 void update_frame(entity* ent, int f)
10831 {
10832 	entity* tempself;
10833 	entity* dust;
10834 	s_attack attack;
10835 	float move, movez, movea;
10836 	int iDelay, iED_Mode, iED_Capmin, iED_CapMax, iED_RangeMin, iED_RangeMax;
10837 	float fED_Factor;
10838 	s_anim* anim = ent->animation;
10839 
10840 	if(f >= anim->numframes) // prevent a crash with invalid frame index.
10841 		return;
10842 
10843 	//important!
10844 	tempself = self;
10845 	self = ent;
10846 
10847 	self->animpos = f;
10848 	//self->currentsprite = self->animation->sprite[f];
10849 
10850 	if(self->animating){
10851 		iDelay          = anim->delay[f];
10852 		iED_Mode        = self->modeldata.edelay.mode;
10853 		fED_Factor      = self->modeldata.edelay.factor;
10854 		iED_Capmin      = self->modeldata.edelay.cap_min;
10855 		iED_CapMax      = self->modeldata.edelay.cap_max;
10856 		iED_RangeMin    = self->modeldata.edelay.range_min;
10857 		iED_RangeMax    = self->modeldata.edelay.range_max;
10858 
10859 		if (iDelay >= iED_RangeMin && iDelay <= iED_RangeMax) //Regular delay within ignore ranges?
10860 		{
10861 			switch(iED_Mode)
10862 			{
10863 				case 1:
10864 					iDelay = (int)(iDelay * fED_Factor);
10865 					break;
10866 				default:
10867 					iDelay += (int)fED_Factor;
10868 					break;
10869 			}
10870 
10871 			if (iED_Capmin && iDelay < iED_Capmin){ iDelay = iED_Capmin; }
10872 			if (iED_CapMax && iDelay > iED_CapMax){ iDelay = iED_CapMax; }
10873 		}
10874 
10875 		self->nextanim = time + iDelay;
10876 		self->pausetime = 0;
10877 		execute_animation_script(self);
10878 	}
10879 
10880 	if(ent->animation!=anim || ent->animpos!=f)
10881 		goto uf_interrupted;
10882 
10883 	if(level && (anim->move || anim->movez))
10884 	{
10885 		move = (float)(anim->move?anim->move[f]:0);
10886 		movez = (float)(anim->movez?anim->movez[f]:0);
10887 		if(self->direction==0) move = -move;
10888 		if(movez || move)
10889 		{
10890 			if(self->trymove)
10891 			{
10892 				self->trymove(move, movez);
10893 			}
10894 			else
10895 			{
10896 				self->x += move;
10897 				self->z += movez;
10898 			}
10899 		}
10900 	}
10901 
10902 	if(anim->seta && anim->seta[0] >= 0 && self->base <= 0)
10903 		ent->base = (float)anim->seta[0];
10904 	else if(!anim->seta || anim->seta[0] < 0)
10905 	{
10906 		movea = (float)(anim->movea?anim->movea[f]:0);
10907 		self->base += movea;
10908 		if(movea!=0) self->altbase += movea;
10909 		else self->altbase = 0;
10910 	}
10911 
10912 	if(anim->flipframe == f) self->direction = !self->direction;
10913 
10914 	if(anim->weaponframe && anim->weaponframe[0] == f)
10915 	{
10916 		dropweapon(2);
10917 		set_weapon(self, anim->weaponframe[1], 0);
10918 		self->idling = 1;
10919 	}
10920 
10921 	if(anim->quakeframe.framestart+anim->quakeframe.cnt == f)
10922 	{
10923 		if(level) {
10924 			if(anim->quakeframe.cnt%2 || anim->quakeframe.v > 0) level->quake = anim->quakeframe.v;
10925 			else level->quake = anim->quakeframe.v * -1;
10926 		}
10927 		if((anim->quakeframe.repeat-anim->quakeframe.cnt) > 1) anim->quakeframe.cnt++;
10928 		else anim->quakeframe.cnt = 0;
10929 	}
10930 
10931 	if(anim->unsummonframe == f)
10932 	{
10933 		if(self->subentity)
10934 		{
10935 			self = self->subentity;
10936 			attack = emptyattack;
10937 			attack.dropv[0] = default_model_dropv[0];
10938 			attack.dropv[1] = default_model_dropv[1];
10939 			attack.dropv[2] = default_model_dropv[2];
10940 			attack.attack_force = self->health;
10941 			attack.attack_type = max_attack_types;
10942 			if(self->takedamage) self->takedamage(self, &attack);
10943 			else kill(self);
10944 			self = ent; // lol ...
10945 			self->subentity = NULL;
10946 		}
10947 	}
10948 
10949 	//spawn / summon /unsummon features
10950 	if(anim->spawnframe && anim->spawnframe[0] == f && anim->subentity) ent_spawn_ent(self);
10951 
10952 	if(anim->summonframe && anim->summonframe[0] == f && anim->subentity)
10953 	{
10954 		//subentity is dead
10955 		if(!self->subentity || self->subentity->dead) ent_summon_ent(self);
10956 	}
10957 
10958 	if(anim->soundtoplay && anim->soundtoplay[f] >= 0)
10959 		sound_play_sample(anim->soundtoplay[f], 0, savedata.effectvol,savedata.effectvol, 100);
10960 
10961 	if(anim->jumpframe.f == f)
10962 	{
10963 		// Set custom jumpheight for jumpframes
10964 		/*if(self->animation->jumpframe.v > 0)*/ toss(self, anim->jumpframe.v);
10965 		self->xdir = self->direction?anim->jumpframe.x:-anim->jumpframe.x;
10966 		self->zdir = anim->jumpframe.z;
10967 
10968 		if(anim->jumpframe.ent>=0)
10969 		{
10970 			dust = spawn(self->x, self->z, self->a, self->direction, NULL, anim->jumpframe.ent, NULL);
10971 			if(dust){
10972 				dust->base = self->a;
10973 				dust->autokill = 2;
10974 				execute_onspawn_script(dust);
10975 			}
10976 		}
10977 	}
10978 
10979 	if(anim->throwframe == f)
10980 	{
10981 		// For backward compatible thing
10982 		// throw stars in the air, hmm, strange
10983 		// custstar custknife in animation should be checked first
10984 		// then if the entity is jumping, check star first, if failed, try knife instead
10985 		// well, try knife at last, if still failed, try star, or just let if shutdown?
10986 #define __trystar star_spawn(self->x + (self->direction ? 56 : -56), self->z, self->a+67, self->direction)
10987 #define __tryknife knife_spawn(NULL, -1, self->x, self->z, self->a + anim->throwa, self->direction, 0, 0)
10988 		if(anim->custknife>=0 || anim->custpshotno>=0)
10989 			__tryknife;
10990 		else if(anim->custstar>=0)
10991 			__trystar;
10992 		else if(self->jumping) {
10993 			if(!__trystar)
10994 				__tryknife;
10995 		}
10996 		else if(!__tryknife)
10997 			__trystar;
10998 		self->reactive=1;
10999 	}
11000 
11001 	if(anim->shootframe == f)
11002 	{
11003 		knife_spawn(NULL, -1, self->x, self->z, self->a, self->direction, 1, 0);
11004 		self->reactive=1;
11005 	}
11006 
11007 	if(anim->tossframe == f)
11008 	{
11009 		bomb_spawn(NULL, -1, self->x, self->z, self->a + anim->throwa, self->direction, 0);
11010 		self->reactive=1;
11011 	}
11012 
11013 uf_interrupted:
11014 
11015 	//important!
11016 	self = tempself;
11017 }
11018 
11019 
ent_set_anim(entity * ent,int aninum,int resetable)11020 void ent_set_anim(entity *ent, int aninum, int resetable)
11021 {
11022 	s_anim *ani = NULL;
11023 	int animpos;
11024 
11025 	if(!ent) {
11026 		//printf("FATAL: tried to set animation with invalid address (no such object)");
11027 		return;
11028 	}
11029 
11030 	if(aninum<0 || aninum>=max_animations) {
11031 		//printf("FATAL: tried to set animation with invalid index (%s, %i)", ent->name, aninum);
11032 		return;
11033 	}
11034 
11035 	if(!validanim(ent, aninum)) {
11036 		//printf("FATAL: tried to set animation with invalid address (%s, %i)", ent->name, aninum);
11037 		return;
11038 	}
11039 
11040 	ani = ent->modeldata.animation[aninum];
11041 
11042 	if(!resetable && ent->animation == ani)
11043 		return;
11044 
11045 	if(ani->numframes == 0)
11046 		return;
11047 
11048 	if(ent->animation && ani->sync>=0 && ent->animation->sync==ani->sync){
11049 		animpos = ent->animpos;
11050 		if(animpos>=ani->numframes)
11051 			animpos = 0;
11052 		ent->animnum = aninum;
11053 		ent->animation = ani;
11054 		ent->animpos=animpos;
11055 	}else{
11056 		if(aninum!=ANI_SLEEP)
11057 			ent->sleeptime = time + ent->modeldata.sleepwait;
11058 		ent->animation = ani;
11059 		ent->animnum = aninum;    // Stored for nocost usage
11060 		ent->animation->animhits = 0;
11061 
11062 		ent->animating = 1;
11063 		ent->lasthit = ent->grabbing;
11064 		ent->altbase = 0;
11065 
11066 		update_frame(ent, 0);
11067 	}
11068 }
11069 
11070 
11071 
11072 // 0 = none, 1+ = alternative
ent_set_colourmap(entity * ent,unsigned int which)11073 void ent_set_colourmap(entity *ent, unsigned int which)
11074 {
11075 	if(which>MAX_COLOUR_MAPS) which = 0;
11076 	if(which==0)
11077 		ent->colourmap = ent->modeldata.palette;
11078 	else
11079 		ent->colourmap = ent->modeldata.colourmap[which-1];
11080 	ent->map = which;
11081 }
11082 
11083 // used by ent_set_model
ent_copy_uninit(entity * ent,s_model * oldmodel)11084 void ent_copy_uninit(entity* ent, s_model* oldmodel)
11085 {
11086 	if(ent->modeldata.multiple<0)
11087 		ent->modeldata.multiple             = oldmodel->multiple;
11088 	if(ent->modeldata.subject_to_wall<0)
11089 		ent->modeldata.subject_to_wall      = oldmodel->subject_to_wall;
11090 	if(ent->modeldata.subject_to_platform<0)
11091 		ent->modeldata.subject_to_platform  = oldmodel->subject_to_platform;
11092 	if(ent->modeldata.subject_to_obstacle<0)
11093 		ent->modeldata.subject_to_obstacle  = oldmodel->subject_to_obstacle;
11094 	if(ent->modeldata.subject_to_hole<0)
11095 		ent->modeldata.subject_to_hole      = oldmodel->subject_to_hole;
11096 	if(ent->modeldata.subject_to_gravity<0)
11097 		ent->modeldata.subject_to_gravity   = oldmodel->subject_to_gravity;
11098 	if(ent->modeldata.subject_to_screen<0)
11099 		ent->modeldata.subject_to_screen    = oldmodel->subject_to_screen;
11100 	if(ent->modeldata.subject_to_minz<0)
11101 		ent->modeldata.subject_to_minz      = oldmodel->subject_to_minz;
11102 	if(ent->modeldata.subject_to_maxz<0)
11103 		ent->modeldata.subject_to_maxz      = oldmodel->subject_to_maxz;
11104 	if(ent->modeldata.no_adjust_base<0)
11105 		ent->modeldata.no_adjust_base       = oldmodel->no_adjust_base;
11106 	if(ent->modeldata.aimove<0)
11107 		ent->modeldata.aimove               = oldmodel->aimove;
11108 	if(ent->modeldata.aiattack<0)
11109 		ent->modeldata.aiattack             = oldmodel->aiattack;
11110 	if(ent->modeldata.hostile<0)
11111 		ent->modeldata.hostile              = oldmodel->hostile;
11112 	if(ent->modeldata.candamage<0)
11113 		ent->modeldata.candamage            = oldmodel->candamage;
11114 	if(ent->modeldata.projectilehit<0)
11115 		ent->modeldata.projectilehit        = oldmodel->projectilehit;
11116 	if(!ent->modeldata.health)
11117 		ent->modeldata.health               = oldmodel->health;
11118 	if(!ent->modeldata.mp)
11119 		ent->modeldata.mp                   = oldmodel->mp;
11120 	if(ent->modeldata.risetime[0]==-1)
11121 		ent->modeldata.risetime[0]          = oldmodel->risetime[0];
11122 	/*
11123 	if(!ent->modeldata.antigrab)
11124 		ent->modeldata.antigrab             = oldmodel->antigrab;
11125 	if(!ent->modeldata.grabforce)
11126 		ent->modeldata.grabforce            = oldmodel->grabforce;
11127 	if(!ent->modeldata.paingrab)
11128 		ent->modeldata.paingrab             = oldmodel->paingrab;*/
11129 
11130 	if(ent->health>ent->modeldata.health)
11131 		ent->health = ent->modeldata.health;
11132 	if(ent->mp>ent->modeldata.mp)
11133 		ent->mp = ent->modeldata.mp;
11134 }
11135 
11136 
11137 //if syncAnim is set, only change animation reference
ent_set_model(entity * ent,char * modelname,int syncAnim)11138 void ent_set_model(entity * ent, char * modelname, int syncAnim)
11139 {
11140 	s_model *m = NULL;
11141 	s_model oldmodel;
11142 	if(ent==NULL) shutdown(1, "FATAL: tried to change model of invalid object");
11143 	m = findmodel(modelname);
11144 	if(m==NULL) shutdown(1, "Model not found: '%s'", modelname);
11145 	oldmodel = ent->modeldata;
11146 	ent->model = m;
11147 	ent->modeldata = *m;
11148 	ent_copy_uninit(ent, &oldmodel);
11149 	ent_set_colourmap(ent, ent->map);
11150 
11151 	if(syncAnim)
11152 	{
11153 		ent->animation = m->animation[ent->animnum];
11154 	}
11155 	else
11156 	{
11157 		ent->attacking = 0;
11158 
11159 		if((!selectScreen && !time) || ent->modeldata.type != TYPE_PLAYER)
11160 		{
11161 			// use new playerselect spawn anim
11162 			if( validanim(ent,ANI_SPAWN))
11163 				ent_set_anim(ent, ANI_SPAWN, 0);
11164 			else
11165 				ent_set_anim(ent, ANI_IDLE, 0);
11166 		}
11167 		else if(!selectScreen && time && ent->modeldata.type == TYPE_PLAYER)
11168 		{
11169 			// mid-level respawn
11170 			if( validanim(ent, ANI_RESPAWN))
11171 				ent_set_anim(ent, ANI_RESPAWN, 0);
11172 			else if( validanim(ent, ANI_SPAWN))
11173 				ent_set_anim(ent, ANI_SPAWN, 0);
11174 			else
11175 				ent_set_anim(ent, ANI_IDLE, 0);
11176 		}
11177 		else if(selectScreen && validanim(ent, ANI_SELECT))
11178 			ent_set_anim(ent, ANI_SELECT, 0);
11179 		else
11180 			ent_set_anim(ent, ANI_IDLE, 0);
11181 	}
11182 }
11183 
11184 
spawn(float x,float z,float a,int direction,char * name,int index,s_model * model)11185 entity * spawn(float x, float z, float a, int direction, char * name, int index, s_model* model)
11186 {
11187 	entity *e = NULL;
11188 	int i, j, id;
11189 	s_defense *dfs;
11190 	float *ofs;
11191 	ScriptVariant* vars;
11192 	s_scripts* scripts;
11193 
11194 	if(!model)
11195 	{
11196 		if(index>=0)
11197 			model = model_cache[index].model;
11198 		else if(name)
11199 			model = findmodel(name);
11200 	}
11201 
11202 	// Be a bit more tolerant...
11203 	if(model==NULL)
11204 	{
11205 		/*
11206 		if(index>=0)
11207 			printf("FATAL: attempt to spawn object with invalid model cache id (%d)!\n", index);
11208 		else if(name)
11209 			printf("FATAL: attempt to spawn object with invalid model name (%s)!\n", name);*/
11210 		return NULL;
11211 	}
11212 
11213 	if(ent_count>=ent_list_size && !alloc_ents()) return NULL; //out of memory ?
11214 
11215 	for(i=0; i<ent_list_size; i++)
11216 	{
11217 		if(!ent_list[i]->exists)
11218 		{
11219 			e = ent_list[i];
11220 			// save these values, or they will loss when memset called
11221 			id      = e->sortid;
11222 			dfs     = e->defense;
11223 			ofs     = e->offense_factors;
11224 			vars    = e->entvars;
11225 			for(j=0; j<max_entity_vars; j++)
11226 				ScriptVariant_Clear(&vars[j]);
11227 			memcpy(dfs, model->defense, sizeof(s_defense)*max_attack_types);
11228 			memcpy(ofs, model->offense_factors, sizeof(float)*max_attack_types);
11229 			// clear up
11230 			clear_all_scripts(e->scripts, 1);
11231 			if(e->waypoints) free(e->waypoints);
11232 
11233 			scripts = e->scripts;
11234 			memset(e, 0, sizeof(entity));
11235 			e->drawmethod = plainmethod;
11236 			e->drawmethod.flag = 0;
11237 
11238 			// add to list and count current entities
11239 			e->exists = 1;
11240 			ent_count++;
11241 
11242 			e->modeldata = *model; // copy the entir model data here
11243 			e->model = model;
11244 			e->defaultmodel = model;
11245 
11246 			e->scripts = scripts;
11247 			// copy from model a fresh script
11248 
11249 			copy_all_scripts(model->scripts, e->scripts, 1);
11250 
11251 			if(ent_count>ent_max) ent_max=ent_count;
11252 			e->timestamp = time; // log time so update function will ignore it if it is new
11253 
11254 			e->health = e->modeldata.health;
11255 			e->mp = e->modeldata.mp;
11256 			e->knockdowncount = e->modeldata.knockdowncount;
11257 			e->x = x;
11258 			e->z = z;
11259 			e->a = a;
11260 			e->direction = direction;
11261 			e->nextthink = time + 1;
11262 			ent_set_colourmap(e, 0);
11263 			e->lifespancountdown = model->lifespan; // new life span countdown
11264 			if((e->modeldata.type & (TYPE_PLAYER|TYPE_SHOT)) && level && (level->nohit || savedata.mode)) e->modeldata.hostile &= ~TYPE_PLAYER;
11265 			if(e->modeldata.type==TYPE_PLAYER) e->playerindex = currentspawnplayer;
11266 
11267 			if(e->modeldata.type == TYPE_TEXTBOX) textbox = e;
11268 
11269 			strncpy(e->name, e->modeldata.name, MAX_NAME_LEN);
11270 			// copy back the value
11271 			e->sortid = id;
11272 			e->defense = dfs;
11273 			e->offense_factors = ofs;
11274 			e->entvars = vars;
11275 			ent_default_init(e);
11276 			return e;
11277 		}
11278 	}
11279 	return NULL;
11280 }
11281 
11282 
11283 
11284 // Break the link an entity has with another one
ent_unlink(entity * e)11285 void ent_unlink(entity *e) {
11286 	if(e->link){
11287 		e->link->link = NULL;
11288 		e->link->grabbing = NULL;
11289 	}
11290 	e->link = NULL;
11291 	e->grabbing = NULL;
11292 }
11293 
11294 
11295 
11296 // Link two entities together
ents_link(entity * e1,entity * e2)11297 void ents_link(entity *e1, entity *e2)
11298 {
11299 	ent_unlink(e1);
11300 	ent_unlink(e2);
11301 	e1->grabbing = e2;    // Added for platform layering
11302 	e1->link = e2;
11303 	e2->link = e1;
11304 }
11305 
11306 
11307 
kill(entity * victim)11308 void kill(entity *victim)
11309 {
11310 	int i = 0;
11311 	s_attack attack;
11312 	entity* tempent = self;
11313 
11314 	execute_onkill_script(victim);
11315 
11316 	if(!victim || !victim->exists)
11317 		return;
11318 
11319 	if(victim->modeldata.type == TYPE_SHOT && player[(int)victim->playerindex].ent)
11320 		player[(int)victim->playerindex].ent->cantfire = 0;
11321 
11322 	ent_unlink(victim);
11323 	victim->weapent = NULL;
11324 	victim->health = 0;
11325 	victim->exists = 0;
11326 	ent_count--;
11327 
11328 	clear_all_scripts(victim->scripts, 1);
11329 
11330 	if(victim->parent && victim->parent->subentity == victim) victim->parent->subentity = NULL;
11331 	victim->parent = NULL;
11332 	if(victim->modeldata.summonkill)
11333 	{
11334 		attack = emptyattack;
11335 		attack.attack_type = max_attack_types;
11336 		attack.dropv[0] = default_model_dropv[0];
11337 		attack.dropv[1] = default_model_dropv[1];
11338 		attack.dropv[2] = default_model_dropv[2];
11339 	}
11340 	// kill minions
11341 	if(victim->modeldata.summonkill == 1 && victim->subentity)
11342 	{
11343 		// kill only summoned one
11344 		victim->subentity->parent = NULL;
11345 		self = victim->subentity;
11346 		attack.attack_force = self->health;
11347 		if(self->takedamage && !level_completed)
11348 			self->takedamage(self, &attack);
11349 		else
11350 			kill(self);
11351 	}
11352 	victim->subentity = NULL;
11353 
11354 	if(victim==player[0].ent) player[0].ent = NULL;
11355 	else if(victim==player[1].ent) player[1].ent = NULL;
11356 	else if(victim==player[2].ent) player[2].ent = NULL;
11357 	else if(victim==player[3].ent) player[3].ent = NULL;
11358 
11359 	if(victim == smartbomber) smartbomber = NULL;
11360 	if(victim == textbox)  textbox = NULL;
11361 
11362 	for(i=0; i<ent_max; i++)
11363 	{
11364 		if(ent_list[i]->exists)
11365 		{
11366 			// kill all minions
11367 			self = ent_list[i];
11368 			if(self->parent == victim)
11369 			{
11370 				self->parent = NULL;
11371 				if(victim->modeldata.summonkill == 2)
11372 				{
11373 					attack.attack_force = self->health;
11374 					if(self->takedamage && !level_completed) self->takedamage(self, &attack);
11375 					else kill(self);
11376 				}
11377 			}
11378 			if(self->owner == victim)
11379 			{
11380 				self->owner = victim->owner;
11381 			}
11382 			if(self->opponent == victim) self->opponent = NULL;
11383 			if(self->bound == victim) self->bound = NULL;
11384 			if(self->landed_on_platform == victim) self->landed_on_platform = NULL;
11385 			if(self->hithead == victim) self->hithead = NULL;
11386 			if(self->lasthit == victim) self->lasthit = NULL;
11387 			if(!textbox && self->modeldata.type == TYPE_TEXTBOX)
11388 			textbox = self;
11389 		}
11390 	}
11391 	self = tempent;
11392 }
11393 
11394 
kill_all()11395 void kill_all()
11396 {
11397 	int i;
11398 	entity *e = NULL;
11399 	for(i=0; i<ent_max; i++)
11400 	{
11401 		e = ent_list[i];
11402 		if (e && e->exists){
11403 			execute_onkill_script(e);
11404 			clear_all_scripts(e->scripts, 1);
11405 		}
11406 		e->exists = 0; // well, no need to use kill function
11407 	}
11408 	textbox = smartbomber = NULL;
11409 	time = 0;
11410 	ent_count = ent_max = 0;
11411 	if(ent_list_size>MAX_ENTS){ //shrinking...
11412 		free_ents();
11413 		alloc_ents(); //this shouldn't return 0, because the list shrinks...
11414 	}
11415 }
11416 
11417 
checkhit(entity * attacker,entity * target,int counter)11418 int checkhit(entity *attacker, entity *target, int counter)
11419 {
11420 	short *coords1;
11421 	short *coords2;
11422 	int x1, x2, y1, y2;
11423 	float medx, medy;
11424 	int debug_coords[2][4];
11425 	int topleast, bottomleast, leftleast, rightleast;
11426 	float zdist = 0;
11427 
11428 	if(attacker == target || !target->animation->bbox_coords ||
11429 	!attacker->animation->attacks || !target->animation->vulnerable[target->animpos] ||
11430 	((attacker->modeldata.type == TYPE_PLAYER && target->modeldata.type == TYPE_PLAYER) && savedata.mode)) return 0;
11431 
11432 
11433 	coords1 = attacker->animation->attacks[attacker->animpos]->attack_coords;
11434 
11435 	if(!counter)
11436 		coords2 = target->animation->bbox_coords[target->animpos];
11437 	else if((target->animation->attacks && target->animation->attacks[target->animpos]) && target->animation->attacks[target->animpos]->counterattack <= attacker->animation->attacks[attacker->animpos]->counterattack)
11438 		coords2 = target->animation->attacks[target->animpos]->attack_coords;
11439 	else return 0;
11440 
11441 	if(coords1[4])
11442 		zdist += coords1[4];
11443 	else
11444 		zdist += attacker->modeldata.grabdistance/3+1;//temporay fix for integer to float conversion
11445 	if(coords2[4])
11446 		zdist += coords2[4];
11447 
11448 	zdist++; // pass >= <= check
11449 
11450 	if(diff(attacker->z,target->z) > zdist)
11451 		return 0;
11452 
11453 	x1 = (int)(attacker->x);
11454 	y1 = (int)(attacker->z - attacker->a);
11455 	x2 = (int)(target->x);
11456 	y2 = (int)(target->z - target->a);
11457 
11458 
11459 	if(attacker->direction==0){
11460 		debug_coords[0][0] = x1-coords1[2];
11461 		debug_coords[0][1] = y1+coords1[1];
11462 		debug_coords[0][2] = x1-coords1[0];
11463 		debug_coords[0][3] = y1+coords1[3];
11464 	}
11465 	else{
11466 		debug_coords[0][0] = x1+coords1[0];
11467 		debug_coords[0][1] = y1+coords1[1];
11468 		debug_coords[0][2] = x1+coords1[2];
11469 		debug_coords[0][3] = y1+coords1[3];
11470 	}
11471 	if(target->direction==0){
11472 		debug_coords[1][0] = x2-coords2[2];
11473 		debug_coords[1][1] = y2+coords2[1];
11474 		debug_coords[1][2] = x2-coords2[0];
11475 		debug_coords[1][3] = y2+coords2[3];
11476 	} else {
11477 		debug_coords[1][0] = x2+coords2[0];
11478 		debug_coords[1][1] = y2+coords2[1];
11479 		debug_coords[1][2] = x2+coords2[2];
11480 		debug_coords[1][3] = y2+coords2[3];
11481 	}
11482 
11483 	if(debug_coords[0][0] > debug_coords[1][2]) return 0;
11484 	if(debug_coords[1][0] > debug_coords[0][2]) return 0;
11485 	if(debug_coords[0][1] > debug_coords[1][3]) return 0;
11486 	if(debug_coords[1][1] > debug_coords[0][3]) return 0;
11487 
11488 	// Find center of attack area
11489 	leftleast = debug_coords[0][0];
11490 	if(leftleast < debug_coords[1][0])
11491 		leftleast = debug_coords[1][0];
11492 	topleast = debug_coords[0][1];
11493 	if(topleast < debug_coords[1][1])
11494 		topleast = debug_coords[1][1];
11495 	rightleast = debug_coords[0][2];
11496 	if(rightleast > debug_coords[1][2])
11497 		rightleast = debug_coords[1][2];
11498 	bottomleast = debug_coords[0][3];
11499 	if(bottomleast > debug_coords[1][3])
11500 		bottomleast = debug_coords[1][3];
11501 
11502 	medx = (float)(leftleast + rightleast) / 2;
11503 	medy = (float)(topleast + bottomleast) / 2;
11504 
11505 	// Now convert these coords to 3D
11506 	lasthitx = medx;
11507 
11508 	if(attacker->z > target->z)
11509 		lasthitz = attacker->z + 1;    // Changed so flashes always spawn in front
11510 	else
11511 		lasthitz = target->z + 1;
11512 
11513 	lasthita = lasthitz - medy;
11514 	lasthitt = attacker->animation->attacks[attacker->animpos]->attack_type;
11515 	lasthitc = 1;
11516 	return 1;
11517 }
11518 
11519 
11520 
11521 /*
11522 Calculates the coef relative to the bottom left point. This is done by figuring out how far the entity is from
11523 the bottom of the platform and multiplying the result by the difference of the bottom left point and the top
11524 left point divided by depth of the platform. The same is done for the right side, and checks to see if they are
11525 within the bottom/top and the left/right area.
11526 */
testhole(int hole,float x,float z)11527 int testhole(int hole, float x, float z)
11528 {
11529 	float coef1, coef2;
11530 	if(z < level->holes[hole][1] && z > level->holes[hole][1] - level->holes[hole][6])
11531 	{
11532 		coef1 = (level->holes[hole][1] - z) * ((level->holes[hole][2] - level->holes[hole][3]) / level->holes[hole][6]);
11533 		coef2 = (level->holes[hole][1] - z) * ((level->holes[hole][4] - level->holes[hole][5]) / level->holes[hole][6]);
11534 		if(x > level->holes[hole][0] + level->holes[hole][3] + coef1 && x < level->holes[hole][0] + level->holes[hole][5] + coef2)
11535 			return 1;
11536 	}
11537 	return 0;
11538 }
11539 
11540 /// find all holes here and return the count
checkholes(float x,float z)11541 int checkholes(float x, float z)
11542 {
11543 	int i, c;
11544 
11545 	for(i=0, c=0; i<level->numholes; i++)
11546 		c += (level->holesfound[i] =  testhole(i, x, z));
11547 
11548 	return c;
11549 }
11550 
11551 // find the 1st hole here
checkhole(float x,float z)11552 int checkhole(float x, float z)
11553 {
11554 	int i;
11555 
11556 	if(level==NULL) return 0;
11557 
11558 	if(level->exit_hole){
11559 		if(x > level->width-(PLAYER_MAX_Z-z)) return 2;
11560 	}
11561 
11562 	for(i=0; i<level->numholes; i++)
11563 	{
11564 		if(testhole(i, x, z))
11565 		{
11566 			holez = i;
11567 			return 1;
11568 		}
11569 	}
11570 	return 0;
11571 }
11572 
11573 /*
11574 Calculates the coef relative to the bottom left point. This is done by figuring out how far the entity is from
11575 the bottom of the platform and multiplying the result by the difference of the bottom left point and the top
11576 left point divided by depth of the platform. The same is done for the right side, and checks to see if they are
11577 within the bottom/top and the left/right area.
11578 */
testwall(int wall,float x,float z)11579 int testwall(int wall, float x, float z)
11580 {
11581 	float coef1, coef2;
11582 //    if(wall >= level->numwalls || wall < 0) return 0;
11583 	if(z < level->walls[wall][1] && z > level->walls[wall][1] - level->walls[wall][6])
11584 	{
11585 		coef1 = (level->walls[wall][1] - z) * ((level->walls[wall][2] - level->walls[wall][3]) / level->walls[wall][6]);
11586 		coef2 = (level->walls[wall][1] - z) * ((level->walls[wall][4] - level->walls[wall][5]) / level->walls[wall][6]);
11587 		if(x > level->walls[wall][0] + level->walls[wall][3] + coef1 && x < level->walls[wall][0] + level->walls[wall][5] + coef2) return 1;
11588 	}
11589 
11590 	return 0;
11591 }
11592 
11593 // find all walls here within altitude1 and 2, return the count
checkwalls(float x,float z,float a1,float a2)11594 int checkwalls(float x, float z, float a1, float a2)
11595 {
11596 	int i, c;
11597 
11598 	for(i=0, c=0; i<level->numwalls; i++)
11599 		c += (level->wallsfound[i] =  (testwall(i, x, z) && level->walls[i][7] >= a1 && level->walls[i][7] <= a2));
11600 
11601 	return c;
11602 }
11603 
11604 // get a highest wall below this altitude
checkwall_below(float x,float z,float a)11605 int checkwall_below(float x, float z, float a)
11606 {
11607 	float maxa;
11608 	int i, ind;
11609 
11610 	if(level==NULL) return -1;
11611 
11612 	maxa = 0;
11613 	ind = -1;
11614 	for(i=0; i<level->numwalls; i++)
11615 	{
11616 		if(testwall(i, x, z) && level->walls[i][7] <= a && level->walls[i][7] > maxa)
11617 		{
11618 			maxa = level->walls[i][7];
11619 			ind = i;
11620 		}
11621 	}
11622 
11623 	return ind;
11624 }
11625 
11626 // return the 1st wall found here
checkwall(float x,float z)11627 int checkwall(float x, float z)
11628 {
11629 	int i;
11630 	if(level==NULL) return -1;
11631 
11632 	for(i=0; i<level->numwalls; i++)
11633 		if(testwall(i, x, z)) return i;
11634 
11635 	return -1;
11636 }
11637 
11638 /*
11639 Calculates the coef relative to the bottom left point. This is done by figuring out how far the entity is from
11640 the bottom of the platform and multiplying the result by the difference of the bottom left point and the top
11641 left point divided by depth of the platform. The same is done for the right side, and checks to see if they are
11642 within the bottom/top and the left/right area.
11643 */
testplatform(entity * plat,float x,float z,entity * exclude)11644 int testplatform(entity* plat, float x, float z, entity* exclude)
11645 {
11646 	float coef1, coef2;
11647 	float offz, offx;
11648 	if(plat==exclude) return 0;
11649 	if(!plat->animation || !plat->animation->platform || !plat->animation->platform[plat->animpos][7]) return 0;
11650 	offz = plat->z+plat->animation->platform[plat->animpos][1];
11651 	offx = plat->x+plat->animation->platform[plat->animpos][0];
11652 	if(z <= offz && z > offz - plat->animation->platform[plat->animpos][6])
11653 	{
11654 		coef1 = (offz - z) * ((plat->animation->platform[plat->animpos][2] -
11655 			plat->animation->platform[plat->animpos][3]) / plat->animation->platform[plat->animpos][6]);
11656 		coef2 = (offz - z) * ((plat->animation->platform[plat->animpos][4] -
11657 			plat->animation->platform[plat->animpos][5]) / plat->animation->platform[plat->animpos][6]);
11658 
11659 		if(x > offx + plat->animation->platform[plat->animpos][3] + coef1 &&
11660 		   x < offx + plat->animation->platform[plat->animpos][5] + coef2) return 1;
11661 	}
11662 	return 0;
11663 }
11664 
11665 
11666 //find the first platform between these 2 altitudes
check_platform_between(float x,float z,float amin,float amax,entity * exclude)11667 entity * check_platform_between(float x, float z, float amin, float amax, entity* exclude)
11668 {
11669 	entity *plat = NULL;
11670 	int i;
11671 
11672 	if(level==NULL) return NULL;
11673 
11674 	for(i=0; i<ent_max; i++)
11675 	{
11676 		if(ent_list[i]->exists && testplatform(ent_list[i], x, z, exclude) )
11677 		{
11678 			plat = ent_list[i];
11679 			if(plat->a <= amax && plat->a + plat->animation->platform[plat->animpos][7] > amin)
11680 			{
11681 				return plat;
11682 			}
11683 		}
11684 	}
11685 	return NULL;
11686 }
11687 
11688 //find a lowest platform above this altitude
check_platform_above(float x,float z,float a,entity * exclude)11689 entity * check_platform_above(float x, float z, float a, entity* exclude)
11690 {
11691 	float mina;
11692 	entity *plat = NULL;
11693 	int i, ind;
11694 
11695 	if(level==NULL) return NULL;
11696 
11697 	mina = 9999999;
11698 	ind = -1;
11699 	for(i=0; i<ent_max; i++)
11700 	{
11701 		if(ent_list[i]->exists && testplatform(ent_list[i], x, z, exclude) )
11702 		{
11703 			plat = ent_list[i];
11704 			if(plat->a >= a && plat->a < mina)
11705 			{
11706 				mina = plat->a;
11707 				ind = i;
11708 			}
11709 		}
11710 	}
11711 	return (ind>=0)?ent_list[ind]:NULL;
11712 }
11713 
11714 //find a highest platform below this altitude
check_platform_below(float x,float z,float a,entity * exclude)11715 entity * check_platform_below(float x, float z, float a, entity* exclude)
11716 {
11717 	float maxa;
11718 	entity *plat = NULL;
11719 	int i, ind;
11720 
11721 	if(level==NULL) return NULL;
11722 
11723 	maxa = MIN_INT;
11724 	ind = -1;
11725 	for(i=0; i<ent_max; i++)
11726 	{
11727 		if(ent_list[i]->exists && testplatform(ent_list[i], x, z, exclude) )
11728 		{
11729 			plat = ent_list[i];
11730 			if(plat->a + plat->animation->platform[plat->animpos][7] <= a &&
11731 			   plat->a + plat->animation->platform[plat->animpos][7] > maxa)
11732 			{
11733 				maxa = plat->a + plat->animation->platform[plat->animpos][7];
11734 				ind = i;
11735 			}
11736 		}
11737 	}
11738 	return (ind>=0)?ent_list[ind]:NULL;
11739 }
11740 
11741 // find the 1st platform entity here
check_platform(float x,float z,entity * exclude)11742 entity * check_platform(float x, float z, entity* exclude)
11743 {
11744 	int i;
11745 	if(level==NULL) return NULL;
11746 
11747 	for(i=0; i<ent_max; i++)
11748 	{
11749 		if(ent_list[i]->exists && testplatform(ent_list[i], x, z, exclude))
11750 		{
11751 			return ent_list[i];
11752 		}
11753 	}
11754 	return NULL;
11755 }
11756 
11757 // for adjust grab position function, test if an entity can move from a to b
11758 // TODO: check points between the two pionts, if necessary
testmove(entity * ent,float sx,float sz,float x,float z)11759 int testmove(entity* ent, float sx, float sz, float x, float z){
11760 	entity *other = NULL;
11761 	int wall, heightvar;
11762 	float xdir, zdir;
11763 
11764 	xdir = x - sx;
11765 	zdir = z - sz;
11766 
11767 	if(!xdir && !zdir) return 1;
11768 
11769 	// -----------bounds checking---------------
11770 	// Subjec to Z and out of bounds? Return to level!
11771 	if (ent->modeldata.subject_to_minz>0)
11772 	{
11773 		if(zdir && z < PLAYER_MIN_Z)
11774 			return 0;
11775 	}
11776 
11777 	if (ent->modeldata.subject_to_maxz>0)
11778 	{
11779 		if(zdir && z > PLAYER_MAX_Z)
11780 			return 0;
11781 	}
11782 
11783 	// End of level is blocked?
11784 	if(level->exit_blocked)
11785 	{
11786 		if(x > level->width-30-(PLAYER_MAX_Z-z)) return 0;
11787 	}
11788 	// screen checking
11789 	if(ent->modeldata.subject_to_screen>0)
11790 	{
11791 		if(x < advancex+10) return 0;
11792 		else if(x > advancex+(videomodes.hRes-10)) return 0;
11793 	}
11794 	//-----------end of bounds checking-----------
11795 
11796 	//-------------hole checking ---------------------
11797 	if(ent->modeldata.subject_to_hole>0)
11798 	{
11799 		if(checkhole(x, z) && checkwall(x, z)<0 && (((other = check_platform(x, z, ent)) &&  ent->base < other->a + other->animation->platform[other->animpos][7]) || other == NULL))
11800 			return 0;
11801 	}
11802 	//-----------end of hole checking---------------
11803 
11804 	//--------------obstacle checking ------------------
11805 	if(ent->modeldata.subject_to_obstacle>0)
11806 	{
11807 		if((other = find_ent_here(ent, x, z, (TYPE_OBSTACLE | TYPE_TRAP), NULL)) &&
11808 		   (!other->animation->platform||!other->animation->platform[other->animpos][7]))
11809 			return 0;
11810 	}
11811 	//-----------end of obstacle checking--------------
11812 
11813 	// ---------------- platform checking----------------
11814 
11815 	if(ent->animation->height) heightvar = ent->animation->height;
11816 	else heightvar = ent->modeldata.height;
11817 
11818 	// Check for obstacles with platform code and adjust base accordingly
11819 	if(ent->modeldata.subject_to_platform>0 && (other = check_platform_between(x, z, ent->a, ent->a+heightvar, ent)) )
11820 	{
11821 		return 0;
11822 	}
11823 	//-----------end of platform checking------------------
11824 
11825 	// ------------------ wall checking ---------------------
11826 	if(ent->modeldata.subject_to_wall>0 && (wall = checkwall(x, z))>=0 && level->walls[wall][7]>ent->a)
11827 	{
11828 		if(validanim(ent,ANI_JUMP) && sz<level->walls[wall][1] && sz>level->walls[wall][1]-level->walls[wall][6]) //Can jump?
11829 		{
11830 			//rmin = (float)ent->modeldata.animation[ANI_JUMP]->range.xmin;
11831 			//rmax = (float)ent->modeldata.animation[ANI_JUMP]->range.xmax;
11832 			if(level->walls[wall][7]<ent->a+ent->modeldata.animation[ANI_JUMP]->range.xmax) return -1;
11833 		}
11834 		return 0;
11835 	}
11836 	//----------------end of wall checking--------------
11837 
11838 	return 1;
11839 
11840 }
11841 
11842 // find real opponent
set_opponent(entity * ent,entity * other)11843 void set_opponent(entity* ent, entity* other)
11844 {
11845 	entity* realself, *realother;
11846 
11847 	if(!ent) return;
11848 
11849 	realself = ent;
11850 	while(realself->owner) realself = realself->owner;
11851 
11852 	realother = other;
11853 	while(realother && realother->owner) realother = realother->owner;
11854 
11855 	realself->opponent = ent->opponent = realother;
11856 	if(realother) realother->opponent = other->opponent = realself;
11857 
11858 }
11859 
11860 
do_attack(entity * e)11861 void do_attack(entity *e)
11862 {
11863 	int them;
11864 	int i;
11865 	int force;
11866 	entity *temp            = NULL;
11867 	entity *flash           = NULL;    // Used so new flashes can be used
11868 	entity *def             = NULL;
11869 	entity *topowner        = NULL;
11870 	entity *otherowner      = NULL;
11871 	int didhit              = 0;
11872 	int didblock            = 0;    // So a different sound effect can be played when an attack is blocked
11873 	int current_attack_id;
11874 	int current_follow_id   = 0;
11875 #define followed (current_anim!=e->animation)
11876 	s_anim* current_anim;
11877 	s_attack* attack = e->animation->attacks[e->animpos];
11878 	static unsigned int new_attack_id = 1;
11879 	int fdefense_blockthreshold = (int)self->defense[(short)attack->attack_type].blockthreshold; //Maximum damage that can be blocked for attack type.
11880 
11881 	// Can't get hit after this
11882 	if(level_completed || !attack) return;
11883 
11884 	topowner = e; // trace the top owner, for projectile combo checking :)
11885 	while(topowner->owner) topowner = topowner->owner;
11886 
11887 	if(e->projectile>0) them = e->modeldata.projectilehit;
11888 	else them = e->modeldata.candamage;
11889 
11890 	// Every attack gets a unique ID to make sure no one
11891 	// gets hit more than once by the same attack
11892 	current_attack_id = e->attack_id;
11893 
11894 	if(!current_attack_id)
11895 	{
11896 		++new_attack_id;
11897 		if(new_attack_id==0) new_attack_id = 1;
11898 		e->attack_id = current_attack_id = new_attack_id;
11899 	}
11900 
11901 	force = attack->attack_force;
11902 	current_anim = e->animation;
11903 
11904 	for(i=0; i<ent_max && !followed; i++)
11905 	{
11906 
11907 		// if #0
11908 		if( ent_list[i]->exists &&
11909 			!ent_list[i]->dead && // dont hit the dead
11910 			(ent_list[i]->invincible != 1 || attack->attack_type == ATK_ITEM) && // so invincible people can get items
11911 			!(current_anim->attackone>0 && e->lasthit && ent_list[i]!=e->lasthit) &&
11912 			(ent_list[i]->modeldata.type & them) &&
11913 			ent_list[i]->pain_time<time && //(ent_list[i]->pain_time<time || current_anim->fastattack) &&
11914 			ent_list[i]->takedamage &&
11915 			ent_list[i]->hit_by_attack_id != current_attack_id &&
11916 			((ent_list[i]->takeaction != common_lie && attack->otg < 2) || (attack->otg >= 1 && ent_list[i]->takeaction == common_lie)) && //over the ground hit
11917 			((ent_list[i]->falling == 0 && attack->jugglecost >= 0) || (ent_list[i]->falling == 1 && attack->jugglecost <= ent_list[i]->modeldata.jugglepoints.current)) && // juggle system
11918 			(checkhit(e, ent_list[i], 0) || // normal check bbox
11919 			 (attack->counterattack && checkhit(e, ent_list[i], 1)))  )// check counter, e.g. upper
11920 		{
11921 			temp = self;
11922 			self = ent_list[i];
11923 
11924 			execute_ondoattack_script(self, e, force, attack->attack_drop, attack->attack_type, attack->no_block, attack->guardcost, attack->jugglecost, attack->pause_add, 0, current_attack_id);	//Execute on defender.
11925 			execute_ondoattack_script(e, self, force, attack->attack_drop, attack->attack_type, attack->no_block, attack->guardcost, attack->jugglecost, attack->pause_add, 1, current_attack_id);	//Execute on attacker.
11926 
11927 			if(!lasthitc){	return;	}	//12312010, DC: Allows modder to cancel engine's attack handling. Useful for parry systems, alternate blocking, or other scripted hit events.
11928 
11929 			didhit = 1;
11930 
11931 			otherowner = self; // trace top owner for opponent
11932 			while(otherowner->owner) otherowner = otherowner->owner;
11933 
11934 			//if #01, if they are fired by the same owner, or the owner itself
11935 			if(topowner == otherowner) didhit = 0;
11936 
11937 			//if #02 , ground missle checking, and bullets wont hit each other
11938 			if( (e->owner && self->owner) ||
11939 				(e->modeldata.ground && inair(e))  )
11940 			{
11941 				didhit = 0;
11942 			}//end of if #02
11943 
11944 			//if #05,   blocking code section
11945 			if(didhit)
11946 			{
11947 				if(attack->attack_type == ATK_ITEM){
11948 					 execute_didhit_script(e, self, force, attack->attack_drop, self->modeldata.subtype, attack->no_block, attack->guardcost, attack->jugglecost, attack->pause_add, 1);
11949 					 didfind_item(e);
11950 					 return;
11951 				}
11952 				//if #051
11953 				if(self->toexplode == 1) self->toexplode = 2;    // Used so the bomb type entity explodes when hit
11954 				//if #052
11955 				if(e->toexplode == 1) e->toexplode = 2;    // Used so the bomb type entity explodes when hitting
11956 
11957 				if(inair(self)) self->modeldata.jugglepoints.current = self->modeldata.jugglepoints.current - attack->jugglecost; //reduce available juggle points.
11958 
11959 				//if #053
11960 				if( !self->modeldata.nopassiveblock && // cant block by itself
11961 					validanim(self,ANI_BLOCK) && // of course, move it here to avoid some useless checking
11962 					((self->modeldata.guardpoints.maximum == 0) || (self->modeldata.guardpoints.maximum > 0 && self->modeldata.guardpoints.current > 0)) &&
11963 					!(self->link ||
11964 					inair(self) ||
11965 					self->frozen ||
11966 					(self->direction == e->direction && self->modeldata.blockback < 1) ||                       // Can't block an attack that is from behind unless blockback flag is enabled
11967 					(!self->idling && self->attacking>=0)) &&                                                   // Can't block if busy, attack <0 means the character is preparing to attack, he can block during this time
11968 					attack->no_block <= self->defense[attack->attack_type].blockpower &&       // If unblockable, will automatically hit
11969 					(rand32()&self->modeldata.blockodds) == 1 &&                                                // Randomly blocks depending on blockodds (1 : blockodds ratio)
11970 					(!self->modeldata.thold || (self->modeldata.thold > 0 && self->modeldata.thold > force))&&
11971 					(!fdefense_blockthreshold ||                                                                //Specific attack type threshold.
11972 					(fdefense_blockthreshold > force)))
11973 				{   //execute the didhit script
11974 					execute_didhit_script(e, self, force, attack->attack_drop, attack->attack_type, attack->no_block, attack->guardcost, attack->jugglecost, attack->pause_add, 1);
11975 					self->takeaction = common_block;
11976 					set_blocking(self);
11977 					self->xdir = self->zdir = 0;
11978 					ent_set_anim(self, ANI_BLOCK, 0);
11979 					execute_didblock_script(self, e, force, attack->attack_drop, attack->attack_type, attack->no_block, attack->guardcost, attack->jugglecost, attack->pause_add);
11980 					if(self->modeldata.guardpoints.maximum > 0) self->modeldata.guardpoints.current = self->modeldata.guardpoints.current - attack->guardcost;
11981 					++current_anim->animhits;
11982 					didblock = 1;    // Used for when playing the block.wav sound
11983 					// Spawn a flash
11984 					//if #0531
11985 					if(!attack->no_flash)
11986 					{
11987 						if(!self->modeldata.noatflash)
11988 						{
11989 							if(attack->blockflash>=0) flash = spawn(lasthitx, lasthitz, lasthita, 0, NULL, attack->blockflash, NULL); // custom bflash
11990 							else flash = spawn(lasthitx,lasthitz,lasthita, 0, NULL, ent_list[i]->modeldata.bflash, NULL);    // New block flash that can be smaller
11991 						}
11992 						else flash = spawn(lasthitx,lasthitz,lasthita, 0, NULL, self->modeldata.bflash, NULL);
11993 						//ent_default_init(flash); // initiliaze this because there're no default values now
11994 
11995 						if(flash) execute_onspawn_script(flash);
11996 					}
11997 					//end of if #0531
11998 				}
11999 				else if(self->modeldata.nopassiveblock && // can block by itself
12000 					self->blocking &&  // of course he must be blocking
12001 					((self->modeldata.guardpoints.maximum == 0) || (self->modeldata.guardpoints.maximum > 0 && self->modeldata.guardpoints.current > 0)) &&
12002 					!((self->direction == e->direction && self->modeldata.blockback < 1)|| self->frozen) &&    // Can't block if facing the wrong direction (unless blockback flag is enabled) or frozen in the block animation or opponent is a projectile
12003 					attack->no_block <= self->defense[(short)attack->attack_type].blockpower &&    // Make sure you are actually blocking and that the attack is blockable
12004 					(!self->modeldata.thold ||
12005 					(self->modeldata.thold > 0 &&
12006 					self->modeldata.thold > force))&&
12007 					(!self->defense[(short)attack->attack_type].blockthreshold ||                   //Specific attack type threshold.
12008 					(self->defense[(short)attack->attack_type].blockthreshold > force)))
12009 				{    // Only block if the attack is less than the players threshold
12010 					//execute the didhit script
12011 					execute_didhit_script(e, self, force, attack->attack_drop, attack->attack_type, attack->no_block, attack->guardcost, attack->jugglecost, attack->pause_add, 1);
12012 					if(self->modeldata.guardpoints.maximum > 0) self->modeldata.guardpoints.current = self->modeldata.guardpoints.current - attack->guardcost;
12013 					++current_anim->animhits;
12014 					didblock = 1;    // Used for when playing the block.wav sound
12015 
12016 					if(self->modeldata.blockpain && self->modeldata.blockpain <= force && self->animation == self->modeldata.animation[ANI_BLOCK]) //Blockpain 1 and in block animation?
12017 					{
12018 						set_blockpain(self, attack->attack_type, 0);
12019 					}
12020 					execute_didblock_script(self, e, force, attack->attack_drop, attack->attack_type, attack->no_block, attack->guardcost, attack->jugglecost, attack->pause_add);
12021 
12022 					// Spawn a flash
12023 					if(!attack->no_flash)
12024 					{
12025 						if(!self->modeldata.noatflash)
12026 						{
12027 							if(attack->blockflash>=0) flash = spawn(lasthitx, lasthitz, lasthita, 0, NULL, attack->blockflash, NULL); // custom bflash
12028 							else flash = spawn(lasthitx,lasthitz,lasthita, 0, NULL, ent_list[i]->modeldata.bflash, NULL);    // New block flash that can be smaller
12029 						}
12030 						else flash = spawn(lasthitx,lasthitz,lasthita, 0, NULL, self->modeldata.bflash, NULL);
12031 						//ent_default_init(flash); // initiliaze this because there're no default values now
12032 						if(flash) execute_onspawn_script(flash);
12033 					}
12034 				}
12035 				else if((self->animpos >= self->animation->counterrange.framestart && self->animpos <= self->animation->counterrange.frameend)  &&	//Within counter range?
12036 					!self->frozen)// &&																								//Not frozen?
12037 					//(self->animation->counterrange.condition <= 1 && e->modeldata.type & them)) //&&												//Friend/foe?
12038 					//(self->animation->counterrange.condition <= 3 && !attack->no_block) &&														//Counter attack self couldn't block?
12039 					//self->animation->counterrange.condition <= 2 ||
12040 					//self->animation->counterrange.condition <= 2 || !(self->direction == e->direction)) //&&										//Direction check.
12041 					//(self->animation->counterrange.condition <= 3 || !attack->freeze))															//Freeze attacks?
12042 
12043 					//&& (!self->animation->counterrange.damaged || self->health > force))													// Does damage matter?
12044 				{
12045 					if(self->animation->counterrange.damaged) self->health -= force;					// Take damage?
12046 					current_follow_id = animfollows[self->animation->followanim - 1];
12047 					if(validanim(self,current_follow_id))
12048 					{
12049 						if(self->modeldata.animation[current_follow_id]->attackone==-1)
12050 							self->modeldata.animation[current_follow_id]->attackone = self->animation->attackone;
12051 						ent_set_anim(self, current_follow_id, 0);
12052 						self->hit_by_attack_id = current_attack_id;
12053 					}
12054 
12055 					if(!attack->no_flash)
12056 					{
12057 						if(!self->modeldata.noatflash)
12058 						{
12059 							if(attack->blockflash>=0) flash = spawn(lasthitx, lasthitz, lasthita, 0, NULL, attack->blockflash, NULL); // custom bflash
12060 							else flash = spawn(lasthitx,lasthitz,lasthita, 0, NULL, ent_list[i]->modeldata.bflash, NULL);    // New block flash that can be smaller
12061 						}
12062 						else flash = spawn(lasthitx,lasthitz,lasthita, 0, NULL, self->modeldata.bflash, NULL);
12063 						//ent_default_init(flash); // initiliaze this because there're no default values now
12064 						if(flash) execute_onspawn_script(flash);
12065 					}
12066 				}
12067 				else if(self->takedamage(e, attack))
12068 				{    // Didn't block so go ahead and take the damage
12069 					execute_didhit_script(e, self, force, attack->attack_drop, attack->attack_type, attack->no_block, attack->guardcost, attack->jugglecost, attack->pause_add, 0);
12070 					++e->animation->animhits;
12071 
12072 					e->lasthit = self;
12073 
12074 					// Spawn a flash
12075 					if(!attack->no_flash)
12076 					{
12077 						if(!self->modeldata.noatflash)
12078 						{
12079 							if(attack->hitflash>=0) flash = spawn(lasthitx, lasthitz, lasthita, 0, NULL, attack->hitflash, NULL);
12080 							else flash = spawn(lasthitx, lasthitz, lasthita, 0, NULL, e->modeldata.flash, NULL);
12081 						}
12082 						else flash = spawn(lasthitx,lasthitz,lasthita, 0, NULL, self->modeldata.flash, NULL);
12083 						if(flash) execute_onspawn_script(flash);
12084 					}
12085 					topowner->combotime = time + combodelay; // well, add to its owner's combo
12086 
12087 					if(e->pausetime<time || (inair(e) && !equalairpause))          // if equalairpause is set, inair(e) is nolonger a condition for extra pausetime
12088 					{    // Adds pause to the current animation
12089 						e->toss_time += attack->pause_add;      // So jump height pauses in midair
12090 						e->nextanim += attack->pause_add;       //Pause animation for a bit
12091 						e->nextthink += attack->pause_add;      // So anything that auto moves will pause
12092 						e->pausetime = time + attack->pause_add ; //UT: temporary solution
12093 					}
12094 
12095 					self->toss_time += attack->pause_add;       // So jump height pauses in midair
12096 					self->nextanim += attack->pause_add;        //Pause animation for a bit
12097 					self->nextthink += attack->pause_add;       // So anything that auto moves will pause
12098 
12099 				}
12100 				else
12101 				{
12102 					didhit = 0;
12103 					continue;
12104 				}
12105 				// end of if #053
12106 
12107 				// if #054
12108 				if(flash)
12109 				{
12110 					if(flash->modeldata.toflip) flash->direction = (e->x > self->x);    // Now the flash will flip depending on which side the attacker is on
12111 
12112 					flash->base = lasthita;
12113 					flash->autokill = 2;
12114 				}//end of if #054
12115 
12116 				// 2007 3 24, hmm, def should be like this
12117 				if(didblock && !def)  def = self;
12118 				//if #055
12119 				if((e->animation->followanim) &&                                        // follow up?
12120 					(e->animation->counterrange.framestart == -1) &&                                // This isn't suppossed to be a counter, right?
12121 					((e->animation->followcond < 2) || (self->modeldata.type & e->modeldata.hostile)) &&    // Does type matter?
12122 					((e->animation->followcond < 3) || ((self->health > 0) &&
12123 					!didblock)) &&                   // check if health or blocking matters
12124 					((e->animation->followcond < 4) || cangrab(e,self))  )// check if nograb matters
12125 				{
12126 					current_follow_id = animfollows[e->animation->followanim-1];
12127 					if(validanim(e,current_follow_id))
12128 					{
12129 						if(e->modeldata.animation[current_follow_id]->attackone==-1)
12130 							e->modeldata.animation[current_follow_id]->attackone = e->animation->attackone;
12131 						ent_set_anim(e, current_follow_id, 1);          // Then go to it!
12132 					}
12133 					//followed = 1; // quit loop, animation is changed
12134 				}//end of if #055
12135 
12136 				self->hit_by_attack_id = current_attack_id;
12137 				if(self==def) self->blocking = didblock; // yeah, if get hit, stop blocking
12138 
12139 				//2011/11/24 UT: move the pain_time logic here,
12140 				// because block needs this as well otherwise blockratio causes instant death
12141 				self->pain_time = time + (attack->pain_time?attack->pain_time:(GAME_SPEED / 5));
12142 				self->nextattack = 0; // reset this, make it easier to fight back
12143 			}//end of if #05
12144 			self = temp;
12145 		}//end of if #0
12146 
12147 	}//end of for
12148 
12149 
12150 	// if ###
12151 	if(didhit)
12152 	{
12153 		// well, dont check player or not - UTunnels. TODO: take care of that healthcheat
12154 		if(e==topowner && current_anim->energycost.cost > 0 && nocost && !healthcheat) e->tocost = 1;    // Set flag so life is subtracted when animation is finished
12155 		else if(e!=topowner && current_anim->energycost.cost > 0 && nocost && !healthcheat && !e->tocost) // if it is not top, then must be a shot
12156 		{
12157 			if(current_anim->energycost.mponly != 2 && topowner->mp > 0)
12158 			{
12159 				topowner->mp -= current_anim->energycost.cost;
12160 				if(topowner->mp < 0) topowner->mp = 0;
12161 			}
12162 			else
12163 			{
12164 				topowner->health -= current_anim->energycost.cost;
12165 				if(topowner->health <= 0) topowner->health = 1;
12166 			}
12167 
12168 			topowner->cantfire = 0;    // Life subtracted, so go ahead and allow firing
12169 			e->tocost = 1;    // Little backwards, but set to 1 so cost doesn't get subtracted multiple times
12170 		}
12171 		// New blocking checks
12172 		//04/27/2008 Damon Caskey: Added checks for defense property specfic blockratio and type. Could probably use some cleaning.
12173 		if(didblock)
12174 		{
12175 			if(blockratio || def->defense[(short)attack->attack_type].blockratio) // Is damage reduced?
12176 			{
12177 				if (def->defense[(short)attack->attack_type].blockratio){                      //Typed blockratio?
12178 					force = (int)(force * def->defense[(short)attack->attack_type].blockratio);
12179 				}else{                                                                            //No typed. Use static block ratio.
12180 					force = force / 4;
12181 				}
12182 
12183 				if(mpblock && !def->defense[(short)attack->attack_type].blocktype){                                                                                 // Drain MP bar first?
12184 					def->mp -= force;
12185 					if(def->mp < 0)
12186 					{
12187 						force = -def->mp;
12188 						def->mp = 0;
12189 					}
12190 					else force = 0;                                                               // Damage removed from MP!
12191 				}else if(def->defense[(short)attack->attack_type].blocktype==1){                //Damage from MP only for this attack type.
12192 					def->mp -= force;
12193 					if(def->mp < 0){
12194 						force = -def->mp;
12195 						def->mp = 0;
12196 					}
12197 					else force = 0;                                                               // Damage removed from MP!
12198 				}else if(def->defense[(short)attack->attack_type].blocktype==2){              //Damage from both HP and MP at once.
12199 					def->mp -= force;
12200 				}else if(def->defense[(short)attack->attack_type].blocktype==-1){             //Health only?
12201 					//Do nothing. This is so modders can overidde energycost.mponly 1 with health only.
12202 				}
12203 
12204 				if(force < def->health)                    // If an attack won't deal damage, this line won't do anything anyway.
12205 					def->health -= force;
12206 				else if(nochipdeath)                       // No chip deaths?
12207 					def->health = 1;
12208 				else
12209 				{
12210 					temp = self;
12211 					self = def;
12212 					self->takedamage(e, attack);           // Must be a fatal attack, then!
12213 					self = temp;
12214 				}
12215 			}
12216 		}
12217 
12218 		if(!didblock)
12219 		{
12220 			topowner->rushtime = time + (GAME_SPEED*rush[1]);
12221 			topowner->rush[0]++;
12222 			if(topowner->rush[0] > topowner->rush[1] && topowner->rush[0] > 1) topowner->rush[1] = topowner->rush[0];
12223 		}
12224 
12225 		if(didblock)
12226 		{
12227 			if(attack->blocksound >= 0) sound_play_sample(attack->blocksound, 0, savedata.effectvol,savedata.effectvol, 100); // New custom block sound effect
12228 			else if(SAMPLE_BLOCK >= 0) sound_play_sample(SAMPLE_BLOCK, 0, savedata.effectvol,savedata.effectvol, 100);    // Default block sound effect
12229 		}
12230 		else if(e->projectile > 0 && SAMPLE_INDIRECT >= 0) sound_play_sample(SAMPLE_INDIRECT, 0, savedata.effectvol,savedata.effectvol, 100);
12231 		else
12232 		{
12233 			if(noslowfx)
12234 			{
12235 				if(attack->hitsound >= 0) sound_play_sample(attack->hitsound, 0, savedata.effectvol,savedata.effectvol, 100);
12236 			}
12237 			else
12238 			{
12239 				if(attack->hitsound >= 0) sound_play_sample(attack->hitsound, 0, savedata.effectvol,savedata.effectvol, 105 - force);
12240 			}
12241 		}
12242 
12243 		if(e->remove_on_attack) kill(e);
12244 	}//end of if ###
12245 #undef followed
12246 }
12247 
12248 
check_gravity()12249 void check_gravity()
12250 {
12251 	int heightvar;
12252 	entity* other, *dust;
12253 	s_attack attack;
12254 	float gravity;
12255 	float fmin,fmax;
12256 
12257 	if(!is_frozen(self) )// Incase an entity is in the air, don't update animations
12258 	{
12259 		if((self->falling || self->tossv || self->a!=self->base) && self->toss_time <= time)
12260 		{
12261 			if(self->modeldata.subject_to_platform>0 && self->tossv>0)
12262 				other = check_platform_above(self->x, self->z, self->a+self->tossv, self);
12263 			else other = NULL;
12264 
12265 			if(self->animation->height) heightvar = self->animation->height;
12266 			else heightvar = self->modeldata.height;
12267 
12268 			if( other && other->a<=self->a+heightvar)
12269 			{
12270 				if(self->hithead == NULL) // bang! Hit the ceiling.
12271 				{
12272 					self->tossv = 0;
12273 					self->hithead = other;
12274 					execute_onblocka_script(self, other);
12275 				}
12276 			}
12277 			else self->hithead = NULL;
12278 			// gravity, antigravity factors
12279 			self->a += self->tossv;
12280 			if(self->animation->dive) gravity = 0;
12281 			else gravity = (level?level->gravity:default_level_gravity) * (1.0-self->modeldata.antigravity-self->antigravity);
12282 			if(self->modeldata.subject_to_gravity>0)
12283 				self->tossv += gravity;
12284 
12285 			fmin = (level?level->maxfallspeed:default_level_maxfallspeed);
12286 			fmax = (level?level->maxtossspeed:default_level_maxtossspeed);
12287 
12288 			if(self->tossv < fmin)
12289 			{
12290 				self->tossv = fmin;
12291 			}
12292 			else if(self->tossv > fmax)
12293 			{
12294 				self->tossv = fmax;
12295 			}
12296 			if(self->animation->dropframe>=0 && self->tossv<=0 && self->animpos<self->animation->dropframe) // begin dropping
12297 			{
12298 				update_frame(self, self->animation->dropframe);
12299 			}
12300 			if (self->tossv) execute_onmovea_script(self); //Move A event.
12301 
12302 			if(self->idling && validanim(self, ANI_WALKOFF))
12303 			{
12304 				self->idling = 0;
12305 				self->takeaction = common_walkoff;
12306 				ent_set_anim(self, ANI_WALKOFF, 0);
12307 			}
12308 
12309 			// UTunnels: tossv <= 0 means land, while >0 means still rising, so
12310 			// you wont be stopped if you are passing the edge of a wall
12311 			if( (self->a<=self->base || !inair(self)) && self->tossv <= 0)
12312 			{
12313 				self->a = self->base;
12314 				self->falling = 0;
12315 				//self->projectile = 0;
12316 				// cust dust entity
12317 				if(self->modeldata.dust[0]>=0 && self->tossv < -1 && self->drop)
12318 				{
12319 					dust = spawn(self->x, self->z, self->a, self->direction, NULL, self->modeldata.dust[0], NULL);
12320 					if(dust){
12321 						dust->base = self->a;
12322 						dust->autokill = 2;
12323 						execute_onspawn_script(dust);
12324 					}
12325 				}
12326 				// bounce/quake
12327 				if(tobounce(self) && self->modeldata.bounce)
12328 				{
12329 					int i;
12330 					self->xdir /= self->animation->bounce;
12331 					self->zdir /= self->animation->bounce;
12332 					toss(self, (-self->tossv)/self->animation->bounce);
12333 					if(level && !self->modeldata.noquake) level->quake = 4;    // Don't shake if specified
12334 					if(SAMPLE_FALL >= 0) sound_play_sample(SAMPLE_FALL, 0, savedata.effectvol,savedata.effectvol, 100);
12335 					if(self->modeldata.type == TYPE_PLAYER) control_rumble(self->playerindex, 100*(int)self->tossv/2);
12336 					for(i=0; i<MAX_PLAYERS; i++) control_rumble(i, 75*(int)self->tossv/2);
12337 				}
12338 				else if((!self->animation->seta || self->animation->seta[self->animpos]<0) &&
12339 					(!self->animation->movea || self->animation->movea[self->animpos]<=0))
12340 					self->xdir = self->zdir = self->tossv= 0;
12341 				else self->tossv = 0;
12342 
12343 				if(self->animation->landframe.frame>=0                                 //Has landframe?
12344                     && self->animation->landframe.frame<= self->animation->numframes   //Not over animation frame count?
12345                     && self->animpos < self->animation->landframe.frame)               //Not already past landframe?
12346 				{
12347 					if(self->animation->landframe.ent>=0)
12348 					{
12349 						dust = spawn(self->x, self->z, self->a, self->direction, NULL, self->animation->landframe.ent, NULL);
12350 						if(dust){
12351 							dust->base = self->a;
12352 							dust->autokill = 2;
12353 							execute_onspawn_script(dust);
12354 						}
12355 					}
12356 					update_frame(self, self->animation->landframe.frame);
12357 				}
12358 
12359 				// takedamage if thrown or basted
12360 				if(self->damage_on_landing > 0 && !self->dead)
12361 				{
12362 					if(self->takedamage)
12363 
12364 					{
12365 						attack              = emptyattack;
12366 						attack.attack_force = self->damage_on_landing;
12367 						attack.attack_type  = self->damagetype;
12368 						self->takedamage(self, &attack);
12369 					}
12370 					else
12371 					{
12372 						self->health -= self->damage_on_landing;
12373 						if(self->health <=0 ) kill(self);
12374 						self->damage_on_landing = 0;
12375 					}
12376 				}
12377 				// in case landing, set hithead to NULL
12378 				self->hithead = NULL;
12379 			}// end of if - land checking
12380 			self->toss_time = time + (GAME_SPEED/100);
12381 		}// end of if  - in-air checking
12382 
12383 	}//end of if
12384 }
12385 
check_lost()12386 void check_lost()
12387 {
12388 	s_attack attack;
12389 	int osk = self->modeldata.offscreenkill?self->modeldata.offscreenkill:DEFAULT_OFFSCREEN_KILL;
12390 
12391 	if((self->z!=100000 && (advancex - self->x>osk || self->x - advancex - videomodes.hRes>osk ||
12392 		(level->scrolldir!=SCROLL_UP && level->scrolldir!=SCROLL_DOWN && (advancey - self->z + self->a>osk || self->z - self->a - advancey - videomodes.vRes>osk)) ||
12393 		((level->scrolldir==SCROLL_UP || level->scrolldir==SCROLL_DOWN) && (self->z-self->a<-osk || self->z-self->a>videomodes.vRes + osk))		) )
12394 		|| self->a < 2*PIT_DEPTH) //self->z<100000, so weapon item won't be killed
12395 	{
12396 		if(self->modeldata.type==TYPE_PLAYER)
12397 		player_die();
12398 		else
12399 		kill(self);
12400 		return;
12401 	}
12402 	// fall in to a pit
12403 	if(self->a < PIT_DEPTH || self->lifespancountdown<0)
12404 	{
12405 		if(!self->takedamage) kill(self);
12406 		else
12407 		{
12408 			attack              = emptyattack;
12409 			attack.dropv[0] = default_model_dropv[0];
12410 			attack.dropv[1] = default_model_dropv[1];
12411 			attack.dropv[2] = default_model_dropv[2];
12412 			attack.attack_force = self->health;
12413 			attack.attack_type  = max_attack_types;
12414 			self->health = 0;
12415 			self->takedamage(self, &attack);
12416 		}
12417 		return;
12418 	}//else
12419 	// Doom count down
12420 	if(!is_frozen(self) && self->lifespancountdown != (float)0xFFFFFFFF) self->lifespancountdown--;
12421 }
12422 
12423 // grab walk check
check_link_move(float xdir,float zdir)12424 void check_link_move(float xdir, float zdir)
12425 {
12426 	float x, z, gx, gz;
12427 	int tryresult;
12428 	entity* tempself = self;
12429 	gx = self->grabbing->x; gz = self->grabbing->z;
12430 	x = self->x; z = self->z;
12431 	self = self->grabbing;
12432 	tryresult = self->trymove(xdir, zdir);
12433 	self = tempself;
12434 	if(tryresult!=1) // changed
12435 	{
12436 		xdir = self->grabbing->x - gx;
12437 		zdir = self->grabbing->z - gz;
12438 	}
12439 	tryresult = self->trymove(xdir, zdir);
12440 	if(tryresult != 1)
12441 	{
12442 		self->grabbing->x = self->x - x + gx;
12443 		self->grabbing->z = self->z - z + gz;
12444 	}
12445 }
12446 
check_ai()12447 void check_ai()
12448 {
12449 	entity* plat;
12450 	// check moving platform
12451 	if((plat=self->landed_on_platform) &&
12452 		(plat->xdir || plat->zdir) &&
12453 		(plat->nextthink <= time || (plat->update_mark & 2)) &&// plat is updated before self or will be updated this loop
12454 		testplatform(plat,self->x,self->z, NULL) &&
12455 		self->a <= plat->a + plat->animation->platform[plat->animpos][7] ) // on the platform?
12456 	{
12457 		// passive move with the platform
12458 		if(self->trymove )
12459 		{
12460 			// grab walk check
12461 			if(self->grabbing && self->grabwalking && self->grabbing->trymove)
12462 			{
12463 				check_link_move(plat->xdir, plat->zdir);
12464 			}
12465 			else self->trymove(plat->xdir, plat->zdir);
12466 		}
12467 		else
12468 		{
12469 			self->x += plat->xdir;
12470 			self->z += plat->zdir;
12471 		}
12472 	}
12473 
12474 	if(self->nextthink <= time && !endgame)
12475 	{
12476 		self->update_mark |= 2; //mark it
12477 		// take actions
12478 		if(self->takeaction) self->takeaction();
12479 
12480 		// A.I. think
12481 		if(self->think)
12482 		{
12483 			if(self->nextthink<=time) self->nextthink = time + THINK_SPEED;
12484 			// use noaicontrol flag to turn of A.I. think
12485 			if(!self->noaicontrol) self->think();
12486 		}
12487 
12488 		// Execute think script
12489 		execute_think_script(self);
12490 
12491 		// A.I. move
12492 		if (self->xdir || self->zdir)
12493 		{
12494 			if(self->trymove)
12495 			{
12496 				// grab walk check
12497 				if(self->grabbing && self->grabwalking && self->grabbing->trymove)
12498 				{
12499 					check_link_move(self->xdir, self->zdir);
12500 				}
12501 				else if(self->trymove(self->xdir, self->zdir)!=1 && self->idling)
12502 				{
12503 					self->pathblocked++; // for those who walk against wall or borders
12504 				}
12505 				else
12506 				{
12507 					self->pathblocked = 0;
12508 				}
12509 			}
12510 			else
12511 			{
12512 				self->x += self->xdir;
12513 				self->z += self->zdir;
12514 			}
12515 		}
12516 		// Used so all entities can have a spawn animation, and then just changes to the idle animation when done
12517 		// move here to so players wont get stuck
12518 		if((self->animation == self->modeldata.animation[ANI_SPAWN] || self->animation == self->modeldata.animation[ANI_RESPAWN]) && !self->animating /*&& (!inair(self)||!self->modeldata.subject_to_gravity)*/) set_idle(self);
12519 	}
12520 }
12521 
12522 
update_animation()12523 void update_animation()
12524 {
12525 	int f, wall, hole;
12526 	float move, movez, seta;
12527 	entity *other = NULL;
12528 
12529 	if(level)
12530 	{
12531 		if(self->modeldata.facing == 1 || level->facing == 1) self->direction = 1;
12532 		else if(self->modeldata.facing == 2 || level->facing == 2) self->direction = 0;
12533 		else if((self->modeldata.facing == 3 || level->facing == 3) && (level->scrolldir & SCROLL_RIGHT)) self->direction = 1;
12534 		else if((self->modeldata.facing == 3 || level->facing == 3) && (level->scrolldir & SCROLL_LEFT)) self->direction = 0;
12535 		if(self->modeldata.type == TYPE_PANEL)
12536 		{
12537 			self->x += scrolldx * ((float)(self->modeldata.speed));
12538 			if(level->scrolldir==SCROLL_UP)
12539 			{
12540 				self->a += scrolldy * ((float)(self->modeldata.speed));
12541 			}
12542 			else if(level->scrolldir==SCROLL_DOWN)
12543 			{
12544 				self->a -= scrolldy * ((float)(self->modeldata.speed));
12545 			}
12546 			else
12547 			{
12548 				self->a -= scrolldy * ((float)(self->modeldata.speed));
12549 			}
12550 		}
12551 		if(self->modeldata.scroll)
12552 		{
12553 			self->x += scrolldx * ((float)(self->modeldata.scroll));
12554 			if(level->scrolldir==SCROLL_UP)
12555 			{
12556 				self->a += scrolldy * ((float)(self->modeldata.scroll));
12557 			}
12558 			else if(level->scrolldir==SCROLL_DOWN)
12559 			{
12560 				self->a -= scrolldy * ((float)(self->modeldata.scroll));
12561 			}
12562 			else
12563 			{
12564 				self->a -= scrolldy * ((float)(self->modeldata.scroll));
12565 			}
12566 		}
12567 	}
12568 
12569 	if(self->invincible && time >= self->invinctime)    // Invincible time has run out, turn off
12570 	{
12571 		self->invincible    = 0;
12572 		self->blink         = 0;
12573 		self->invinctime    = 0;
12574 		self->arrowon       = 0;
12575 	}
12576 
12577 	if(self->freezetime && time >= self->freezetime)
12578 	{
12579 		unfrozen(self);
12580 	}
12581 
12582 	if(self->maptime && time >= self->maptime)
12583 	{
12584 		ent_set_colourmap(self, self->map);
12585 	}
12586 
12587 	if(self->sealtime && time >= self->sealtime) //Remove seal, special moves are available again.
12588 	{
12589 		self->seal = 0;
12590 	}
12591 	// Reset their escapecount if they aren't being spammed anymore.
12592 	if(self->modeldata.escapehits && !self->inpain) self->escapecount = 0;
12593 
12594 	if(self->nextanim == time ||
12595 		(self->modeldata.type == TYPE_TEXTBOX && self->modeldata.subtype != SUBTYPE_NOSKIP &&
12596 		 (bothnewkeys&(FLAG_JUMP|FLAG_ATTACK|FLAG_ATTACK2|FLAG_ATTACK3|FLAG_ATTACK4|FLAG_SPECIAL))))// Textbox will autoupdate if a valid player presses an action button
12597 	{    // Now you can display text and cycle through with any jump/attack/special unless SUBTYPE_NOSKIP
12598 
12599 		f = self->animpos + self->animating;
12600 
12601 		//Specified loop break frame.
12602 		if(self->animation->loop.mode && self->animation->loop.frameend)
12603 		{
12604 			if (f == self->animation->loop.frameend)
12605 			{
12606 				if(f<0) f = self->animation->numframes-1;
12607 				else f = 0;
12608 
12609 				if (self->animation->loop.framestart)
12610 				{
12611 					f = self->animation->loop.framestart;
12612 				}
12613 			}
12614 			else if((unsigned)f >= (unsigned)self->animation->numframes)
12615 			{
12616 				self->animating = 0;
12617 
12618 				if(self->autokill)
12619 				{
12620 					kill(self);
12621 					return;
12622 				}
12623 			}
12624 		}
12625 		else if((unsigned)f >= (unsigned)self->animation->numframes)
12626 		{
12627 			if(f<0) f = self->animation->numframes-1;
12628 			else f = 0;
12629 
12630 			if(!self->animation->loop.mode)
12631 			{
12632 				self->animating = 0;
12633 
12634 				if(self->autokill)
12635 				{
12636 					kill(self);
12637 					return;
12638 				}
12639 			}
12640 			else
12641 			{
12642 				if (self->animation->loop.framestart)
12643 				{
12644 					f = self->animation->loop.framestart;
12645 				}
12646 			}
12647 		}
12648 
12649 		if(self->animating)
12650 		{
12651 			//self->nextanim = time + (self->animation->delay[f]);
12652 			self->update_mark |= 1; // frame updated, mark it
12653 			// just switch frame to f, if frozen, expand_time will deal with it well
12654 			update_frame(self, f);
12655 		}
12656 	}
12657 
12658 	if(self->modeldata.subject_to_platform>0)
12659 	{
12660 		other = self->landed_on_platform;
12661 		if(other && testplatform(other, self->x, self->z, NULL) && self->a <= other->a + other->animation->platform[other->animpos][7])
12662 		{
12663 			self->a = self->base = other->a + other->animation->platform[other->animpos][7];
12664 		}
12665 		else other = check_platform_below(self->x, self->z, self->a, self);
12666 	}
12667 	else other = NULL;
12668 	self->landed_on_platform = other;
12669 	// adjust base
12670 	if(self->modeldata.no_adjust_base<=0)
12671 	{
12672 		seta = (float)((self->animation->seta)?(self->animation->seta[self->animpos]):(-1));
12673 
12674 		// Checks to see if entity is over a wall and or obstacle, and adjusts the base accordingly
12675 		//wall = checkwall_below(self->x, self->z);
12676 		//find a wall below us
12677 		if(self->modeldata.subject_to_wall>0)
12678 			wall = checkwall_below(self->x, self->z, self->a);
12679 		else wall = -1;
12680 
12681 		if(self->modeldata.subject_to_hole>0)
12682 		{
12683 			hole = (wall<0&&!other)?checkhole(self->x, self->z):0;
12684 
12685 			if(seta<0 && hole)
12686 			{
12687 				self->base=-1000;
12688 				ent_unlink(self);
12689 			}
12690 			else if(!hole && self->base == -1000)
12691 			{
12692 				 if(self->a>=0) self->base = 0;
12693 				 else
12694 				 {
12695 					 self->xdir = self->zdir = 0; // hit the hole border
12696 				 }
12697 			}
12698 		}
12699 
12700 		if(self->base != -1000 || wall>=0)
12701 		{
12702 			if(other != NULL && other != self )
12703 			{
12704 				self->base = (seta + self->altbase >=0 ) * (seta+self->altbase) + (other->a + other->animation->platform[other->animpos][7]);
12705 			}
12706 			else if(wall >= 0)
12707 			{
12708 				//self->modeldata.subject_to_wall &&//we move this up to avoid some checking time
12709 				self->base = (seta + self->altbase >=0 ) * (seta+self->altbase) + (self->a >= level->walls[wall][7]) * level->walls[wall][7];
12710 			}
12711 			else if(seta >= 0) self->base = (seta + self->altbase >=0 ) * (seta+self->altbase);
12712 			else if(self->animation != self->modeldata.animation[ANI_VAULT] && (!self->animation->movea || self->animation->movea[self->animpos] == 0))
12713 			{
12714 				// Don't want to adjust the base if vaulting
12715 				// No obstacle/wall or seta, so just set to 0
12716 				self->base = 0;
12717 			}
12718 		}
12719 	}
12720 
12721 	// Code for when entities move (useful for moving platforms, etc)
12722 	if(other && other != self )
12723 	{
12724 		// a bit complex, other->nextanim == time means other is behind self and not been updated,
12725 		// update_mark & 1 means other is updated in this loop and before self
12726 		if((other->nextanim == time || (other->update_mark & 1)) && self->a <= other->a + other->animation->platform[other->animpos][7])
12727 		{
12728 			if(other->update_mark & 1) f = other->animpos;
12729 			else f = other->animpos + other->animating;
12730 			if(f >= other->animation->numframes)
12731 			{
12732 				if(f<0) f = other->animation->numframes-1;
12733 				else f = 0;
12734 			}
12735 			//printf("%d %d %d\n", other->nextanim, time, other->update_mark);
12736 			move = (float)(other->animation->move?other->animation->move[f]:0);
12737 			movez = (float)(other->animation->movez?other->animation->movez[f]:0);
12738 			if(other->direction==0) move = -move;
12739 			if(move||movez)
12740 			{
12741 				if(self->trymove)
12742 				{
12743 					self->trymove(move, movez);
12744 				}
12745 				else
12746 				{
12747 					self->z += movez;
12748 					self->x += move;
12749 				}
12750 			}
12751 		}
12752 	}
12753 }
12754 
check_attack()12755 void check_attack()
12756 {
12757 	// a normal fall
12758 	if(self->falling && !self->projectile)
12759 	{
12760 		self->attack_id = 0;
12761 		return;
12762 	}
12763 	// on ground
12764 	if(self->drop && !self->falling)
12765 	{
12766 		self->attack_id= 0;
12767 		return;
12768 	}
12769 
12770 	// Can't hit an opponent if you are frozen
12771 	if(!is_frozen(self) && self->animation->attacks &&
12772 		self->animation->attacks[self->animpos])
12773 	{
12774 		do_attack(self);
12775 		return;
12776 	}
12777 	self->attack_id = 0;
12778 }
12779 
12780 
update_health()12781 void update_health()
12782 {
12783 	//12/30/2008: Guardrate by OX. Guardpoints increase over time.
12784 	if(self->modeldata.guardpoints.maximum > 0 && time >= self->guardtime) // If this is > 0 then guardpoints are set..
12785 	{
12786 		if(self->blocking)
12787 		{
12788 			self->modeldata.guardpoints.current += (self->modeldata.guardrate/2);
12789 			if(self->modeldata.guardpoints.current > self->modeldata.guardpoints.maximum) self->modeldata.guardpoints.current = self->modeldata.guardpoints.maximum;
12790 		}
12791 		else
12792 		{
12793 			self->modeldata.guardpoints.current += self->modeldata.guardrate;
12794 			if(self->modeldata.guardpoints.current > self->modeldata.guardpoints.maximum) self->modeldata.guardpoints.current = self->modeldata.guardpoints.maximum;
12795 		}
12796 		self->guardtime = time + GAME_SPEED;    //Reset guardtime.
12797 	}
12798 
12799 	common_dot();   //Damage over time.
12800 
12801 	// this is for restoring mp by time by tails
12802 	// Cleaning and addition of mpstable by DC, 08172008.
12803 	// stabletype 4 added by OX 12272008
12804 	if(magic_type == 0 && !self->charging)
12805 	{
12806 		if(time >= self->magictime)
12807 		{
12808 
12809 			// 1 Only recover MP > mpstableval.
12810 			// 2 No recover. Drop MP if MP < mpstableval.
12811 			// 3 Both: recover if MP if MP < mpstableval and drop if MP > mpstableval.
12812 			// 0 Default. Recover MP at all times.
12813 
12814 
12815 			if (self->modeldata.mpstable == 1){
12816 				if (self->mp < self->modeldata.mpstableval) self->mp += self->modeldata.mprate;
12817 			}else if(self->modeldata.mpstable == 2){
12818 				if (self->mp > self->modeldata.mpstableval) self->mp -= self->modeldata.mpdroprate;
12819 			}else if (self->modeldata.mpstable == 3){
12820 				if (self->mp < self->modeldata.mpstableval)
12821 				{
12822 
12823 					self->mp += self->modeldata.mprate;
12824 				}
12825 				else if (self->mp > self->modeldata.mpstableval)
12826 				{
12827 					self->mp -= self->modeldata.mpdroprate;
12828 				}
12829 			}
12830 
12831 			// OX. Stabletype 4. Gain mp until it reaches max. Then it drops down to mpstableval.
12832 			else if (self->modeldata.mpstable == 4)
12833 			{
12834 				if(self->mp <= self->modeldata.mpstableval) self->modeldata.mpswitch = 0;
12835 				else if(self->mp == self->modeldata.mp) self->modeldata.mpswitch = 1;
12836 
12837 				if(self->modeldata.mpswitch == 1)
12838 				{
12839 					self->mp -= self->modeldata.mpdroprate;
12840 				}
12841 				else if(self->modeldata.mpswitch == 0)
12842 				{
12843 					self->mp += self->modeldata.mprate;
12844 				}
12845 			}
12846 			else
12847 			{
12848 				self->mp += self->modeldata.mprate;
12849 			}
12850 
12851 			self->magictime = time + GAME_SPEED;    //Reset magictime.
12852 		}
12853 	}
12854 	if(self->charging && time >= self->mpchargetime)
12855 	{
12856 		self->mp += self->modeldata.chargerate;
12857 		self->mpchargetime = time + (GAME_SPEED / 4);
12858 	}
12859 	if(self->mp > self->modeldata.mp) self->mp = self->modeldata.mp; // Don't want to add more than the max
12860 
12861 	if(self->oldhealth < self->health) self->oldhealth++;
12862 	else if(self->oldhealth > self->health) self->oldhealth--;
12863 
12864 	if(self->oldmp < self->mp) self->oldmp++;
12865 	else if(self->oldmp > self->mp) self->oldmp--;
12866 }
12867 
common_dot()12868 void common_dot()
12869 {
12870 	//common_dot
12871 	//Damon V. Caskey
12872 	//06172009
12873 	//Mitigates damage over time (dot). Moved here from update_health().
12874 
12875 	int         iFForce;    //Final force; total damage after defense and offense factors are applied.
12876 	int         iType;      //Attack type.
12877 	int         iIndex;     //Dot index.
12878 	int         iDot;       //Dot mode.
12879 	int         iDot_time;  //Dot expire time.
12880 	int         iDot_cnt;   //Dot next tick time.
12881 	int         iDot_rate;  //Dot tick rate.
12882 	int         iForce;     //Unmodified force.
12883 	float       fOffense;   //Owner's offense.
12884 	float       fDefense;   //Self defense.
12885 	entity*     eOpp;       //Owner of dot effect.
12886 	s_attack    attack;     //Attack struct.
12887 
12888 	for(iIndex=0; iIndex<MAX_DOTS; iIndex++)                                                   //Loop through all DOT indexes.
12889 	{
12890 		iDot_time   =   self->dot_time[iIndex];                                                 //Get expire time.
12891 		iDot_cnt    =   self->dot_cnt[iIndex];                                                  //Get next tick time.
12892 		iDot_rate   =   self->dot_rate[iIndex];                                                 //Get tick rate.
12893 
12894 		if(iDot_time)                                                                           //Dot time present?
12895 		{
12896 			if(time > iDot_time)                                                                //Dot effect expired? Then clear variants.
12897 			{
12898 				self->dot[iIndex]       = 0;
12899 				self->dot_atk[iIndex]   = 0;
12900 				self->dot_cnt[iIndex]   = 0;
12901 				self->dot_rate[iIndex]  = 0;
12902 				self->dot_time[iIndex]  = 0;
12903 				self->dot_force[iIndex] = 0;
12904 			}
12905 			else if(time >= iDot_cnt && self->health>=0)                                        //Time for a dot tick and alive?
12906 			{
12907 				self->dot_cnt[iIndex] = time + (iDot_rate * GAME_SPEED / 100);                  //Reset next tick time.
12908 
12909 				iDot    =   self->dot[iIndex];                                                  //Get dot mode.
12910 				iForce  =   self->dot_force[iIndex];                                            //Get dot force.
12911 
12912 				if(iDot==1 || iDot==3 || iDot==4 || iDot==5)                                    //HP?
12913 				{
12914 					eOpp        = self->dot_owner[iIndex];                                      //Get dot effect owner.
12915 					iType       = self->dot_atk[iIndex];                                        //Get attack type.
12916 					iFForce     = iForce;                                                       //Initialize final force.
12917 					fOffense    = eOpp->offense_factors[iType];                       //Get owner's offense.
12918 					fDefense    = self->defense[iType].factor;                       //Get Self defense.
12919 
12920 					if (fOffense){  iFForce = (int)(iForce  * fOffense);    }                   //Apply offense factors.
12921 					if (fDefense){  iFForce = (int)(iFForce * fDefense);    }                   //Apply defense factors.
12922 
12923 					if(iFForce >= self->health && (iDot==4 || iDot==5))                         //Total force lethal?
12924 					{
12925 						attack              = emptyattack;                                      //Clear struct.
12926 						attack.attack_type  = iType;                                            //Set type.
12927 						attack.attack_force = iForce;                                           //Set force. Use unmodified force here; takedamage applys damage mitigation.
12928 						attack.dropv[0]     = default_model_dropv[0];                           //Apply drop Y.
12929 						attack.dropv[1]     = default_model_dropv[1];                           //Apply drop X
12930 						attack.dropv[2]     = default_model_dropv[2];                           //Apply drop Z
12931 
12932 						if(self->takedamage)                                                    //Defender uses takedamage()?
12933 						{
12934 							self->takedamage(eOpp, &attack);                                    //Apply attack to kill defender.
12935 						}
12936 						else
12937 						{
12938 							kill(self);                                                         //Kill defender instantly.
12939 						}
12940 					}
12941 					else                                                                        //Total force less then health or using non lethal setting.
12942 					{
12943 						if (self->health > iFForce)                                             //Final force less then health?
12944 						{
12945 							self->health -= iFForce;                                            //Reduce health directly. Using takedamage() breaks grabs and spams defender's status in HUD.
12946 						}
12947 						else
12948 						{
12949 							self->health = 1;                                                   //Set minimum health.
12950 						}
12951 						execute_takedamage_script(self, eOpp, iForce, 0, iType, 0, 0, 0, 0);    //Execute the takedamage script.
12952 					}
12953 				}
12954 
12955 				if(iDot==2 || iDot==3 || iDot==5)                                               //MP?
12956 				{
12957 					self->mp -= iForce;                                                         //Subtract force from MP.
12958 					if(self->mp<0) self->mp = 0;                                                //Stablize MP at 0.
12959 				}
12960 			}
12961 		}
12962 	}
12963 }
12964 
adjust_bind(entity * e)12965 void adjust_bind(entity* e)
12966 {
12967 	if(e->bindanim)
12968 	{
12969 		if(e->animnum!=e->bound->animnum)
12970 		{
12971 			if(!validanim(e,e->bound->animnum))
12972 			{
12973 				if(e->bindanim&4)
12974 				{
12975 				   kill(e);
12976 				}
12977 				e->bound=NULL;
12978 				return;
12979 			}
12980 			ent_set_anim(e, e->bound->animnum, 1);
12981 		}
12982 		if(e->animpos!=e->bound->animpos && e->bindanim&2)
12983 		{
12984 			update_frame(e, e->bound->animpos);
12985 		}
12986 	}
12987 	e->z = e->bound->z +e->bindoffset[1];
12988 	e->a = e->bound->a + e->bindoffset[2];
12989 	switch(e->bindoffset[3])
12990 	{
12991 	case 0:
12992 		if(e->bound->direction) e->x = e->bound->x + e->bindoffset[0];
12993 		else e->x = e->bound->x - e->bindoffset[0];
12994 		break;
12995 	case 1:
12996 		e->direction = e->bound->direction;
12997 		if(e->bound->direction) e->x = e->bound->x + e->bindoffset[0];
12998 		else e->x = e->bound->x - e->bindoffset[0];
12999 		break;
13000 	case -1:
13001 		e->direction = !e->bound->direction;
13002 		if(e->bound->direction) e->x = e->bound->x + e->bindoffset[0];
13003 		else e->x = e->bound->x - e->bindoffset[0];
13004 		break;
13005 	case 2:
13006 		e->direction = 1;
13007 		e->x = e->bound->x + e->bindoffset[0];
13008 		break;
13009 	case -2:
13010 		e->direction = 0;
13011 		e->x = e->bound->x + e->bindoffset[0];
13012 		break;
13013 	default:
13014 		e->x = e->bound->x + e->bindoffset[0];
13015 		break;
13016 	// the default is no change :), just give a value of 12345 or so
13017 	}
13018 }
13019 
13020 // arrenge the list reduce its length
arrange_ents()13021 void arrange_ents()
13022 {
13023 	int i, ind=-1;
13024 	entity* temp;
13025 	if(ent_count == 0) return;
13026 	if(ent_max == ent_count)
13027 	{
13028 		for(i=0; i<ent_max; i++)
13029 		{
13030 			ent_list[i]->update_mark = 0;
13031 			if(ent_list[i]->exists && ent_list[i]->bound)
13032 			{
13033 				adjust_bind(ent_list[i]);
13034 			}
13035 		}
13036 	}
13037 	else
13038 	{
13039 		for(i=0; i<ent_max; i++)
13040 		{
13041 			if(!ent_list[i]->exists && ind<0)
13042 				ind = i;
13043 			else if(ent_list[i]->exists && ind>=0)
13044 			{
13045 				temp = ent_list[i];
13046 				ent_list[i] = ent_list[ind];
13047 				ent_list[ind] = temp;
13048 				ind++;
13049 			}
13050 			ent_list[i]->update_mark = 0;
13051 			if(ent_list[i]->exists && ent_list[i]->bound)
13052 			{
13053 				adjust_bind(ent_list[i]);
13054 			}
13055 		}
13056 		ent_max = ent_count;
13057 	}
13058 }
13059 
13060 // Update all entities that wish to think or animate in this cycle.
13061 // All loops are separated because "self" might die during a pass.
update_ents()13062 void update_ents()
13063 {
13064 	int i;
13065 	for(i=0; i<ent_max; i++)
13066 	{
13067 		if(ent_list[i]->exists && time != ent_list[i]->timestamp)// dont update fresh entity
13068 		{
13069 			self = ent_list[i];
13070 			self->update_mark = 0;
13071 			if(level) check_lost();// check lost caused by level scrolling or lifespan
13072 			if(!self->exists) continue;
13073 			// expand time incase being frozen
13074 			if(is_frozen(self)){expand_time(self);}
13075 			else
13076 			{
13077 				execute_updateentity_script(self);// execute a script
13078 				if(!self->exists) continue;
13079 				check_ai();// check ai
13080 				if(!self->exists) continue;
13081 				check_gravity();// check gravity
13082 				if(!self->exists) continue;
13083 				update_animation(); // if not frozen, update animation
13084 				if(!self->exists) continue;
13085 				check_attack();// Collission detection
13086 				if(!self->exists) continue;
13087 				update_health();// Update displayed health
13088 			}
13089 		}
13090 	}//end of for
13091 	arrange_ents();
13092 	/*
13093 	if(time>=nextplan){
13094 		plan();
13095 		nextplan = time+GAME_SPEED/2;
13096 	}*/
13097 }
13098 
13099 
display_ents()13100 void display_ents()
13101 {
13102 	unsigned f;
13103 	int i, z, wall = 0, wall2;
13104 	entity *e = NULL;
13105 	entity *other = NULL;
13106 	int qx, qy, sy,sz, alty;
13107 	int sortid;
13108 	float temp1, temp2;
13109 	int useshadow = 0;
13110 	int can_mirror = 0;
13111 	int shadowz;
13112 	s_drawmethod* drawmethod = NULL;
13113 	s_drawmethod commonmethod;
13114 	s_drawmethod shadowmethod;
13115 	int use_mirror = (level && level->mirror);
13116 
13117 	int scrx = screenx - gfx_x_offset, scry = screeny - gfx_y_offset;
13118 
13119 	if(level) shadowz = SHADOW_Z;
13120 	else shadowz = MIN_INT + 100;
13121 
13122 	for(i=0; i<ent_max; i++)
13123 	{
13124 		if(ent_list[i] && ent_list[i]->exists)
13125 		{
13126 			e = ent_list[i];
13127 			if(e->modeldata.hpbarstatus.sizex)
13128 			{
13129 				drawenemystatus(e);
13130 
13131 			}
13132 			sortid = e->sortid;
13133 			if(freezeall || !(e->blink && (time%(GAME_SPEED/10))<(GAME_SPEED/20)))
13134 			{    // If special is being executed, display all entities regardless
13135 				f = e->animation->sprite[e->animpos];
13136 
13137 				other = check_platform(e->x, e->z, e);
13138 				wall = checkwall(e->x, e->z);
13139 
13140 				if(f<sprites_loaded)
13141 				{
13142 					// var "z" takes into account whether it has a setlayer set, whether there are other entities on
13143 					// the same "z", in which case there is a layer offset, whether the entity is on an obstacle, and
13144 					// whether the entity is grabbing someone and has grabback set
13145 
13146 					z = (int)e->z;    // Set the layer offset
13147 
13148 					if(e->bound) sortid = e->bound->sortid-1;
13149 
13150 					if(e->grabbing && e->modeldata.grabback)
13151 						sortid = e->link->sortid - 1;    // Grab animation displayed behind
13152 					else if(!e->modeldata.grabback && e->grabbing)
13153 						sortid = e->link->sortid + 1;
13154 /*
13155 					if(e->bound && e->bound->grabbing==e)
13156 					{
13157 						if(e->bound->modeldata.grabback) z--;
13158 						else                             z++;
13159 					}
13160 */
13161 					if(other && e->a >= other->a + other->animation->platform[other->animpos][7] && !other->modeldata.setlayer)
13162 					{
13163 						if(
13164 							e->link &&
13165 							((e->modeldata.grabback &&
13166 							!e->grabbing) ||
13167 							(e->link->modeldata.grabback &&
13168 							e->link->grabbing) ||
13169 							e->grabbing)
13170 							)
13171 							z = (int)(other->z + 2);    // Make sure entities get displayed in front of obstacle and grabbee
13172 
13173 						else z = (int)(other->z + 1);    // Entity should always display in front of the obstacle
13174 
13175 					}
13176 
13177 					if(e->owner) sortid = e->owner->sortid+1;    // Always in front
13178 
13179 					if(e->modeldata.setlayer) z = HOLE_Z + e->modeldata.setlayer;    // Setlayer takes precedence
13180 
13181 					if(checkhole(e->x, e->z)==2) z = PANEL_Z-1;        // place behind panels
13182 
13183 					drawmethod = e->animation->drawmethods?getDrawMethod(e->animation, e->animpos):NULL;
13184 		    //drawmethod = e->animation->drawmethods?e->animation->drawmethods[e->animpos]:NULL;
13185 					if(e->drawmethod.flag) drawmethod = &(e->drawmethod);
13186 					if(!drawmethod)
13187 						commonmethod = plainmethod;
13188 					else
13189 						commonmethod = *drawmethod;
13190 					drawmethod = &commonmethod;
13191 
13192 					if(e->modeldata.alpha >=1 && e->modeldata.alpha <= MAX_BLENDINGS)
13193 					{
13194 						if(drawmethod->alpha<0)
13195 						{
13196 							drawmethod->alpha = e->modeldata.alpha;
13197 						}
13198 					}
13199 
13200 					if(!drawmethod->table){
13201 
13202 						if(drawmethod->remap>=1 && drawmethod->remap<=e->modeldata.maps_loaded)
13203 						{
13204 							drawmethod->table = e->modeldata.colourmap[drawmethod->remap-1];
13205 						}
13206 
13207 						if(e->colourmap)
13208 						{
13209 							if(drawmethod->remap<0) drawmethod->table = e->colourmap;
13210 						}
13211 						if(!drawmethod->table) drawmethod->table = e->modeldata.palette;
13212 						if(e->modeldata.globalmap)
13213 						{
13214 							if(level&&current_palette)
13215 								drawmethod->table = level->palettes[current_palette-1];
13216 							else drawmethod->table = pal;
13217 						}
13218 					}
13219 					if(e->dying)    // Code for doing dying flash
13220 					{
13221 						if((e->health <= e->per1 && e->health > e->per2 && (time %(GAME_SPEED / 5)) < (GAME_SPEED / 10)) ||
13222 							(e->health <= e->per2 && (time %(GAME_SPEED / 10)) < (GAME_SPEED / 20)))
13223 						{
13224 							if(e->health > 0 )
13225 							{
13226 								drawmethod->table = e->modeldata.colourmap[e->dying - 1];
13227 							}
13228 						}
13229 					}
13230 
13231 					if(!e->direction)
13232 					{
13233 						drawmethod->flipx = !drawmethod->flipx;
13234 						if(drawmethod->fliprotate && drawmethod->rotate)
13235 							drawmethod->rotate = 360-drawmethod->rotate;
13236 					}
13237 
13238 					if(!use_mirror || z > MIRROR_Z) // don't display if behind the mirror
13239 					{
13240 						spriteq_add_sprite((int)(e->x - scrx), (int)(e->z-e->a - scry), z, f, drawmethod, sortid);
13241 					}
13242 
13243 					can_mirror = (use_mirror && self->z>MIRROR_Z);
13244 					if(can_mirror)
13245 					{
13246 						spriteq_add_sprite((int)(e->x-scrx), (int)((2*MIRROR_Z - e->z)-e->a-scry), 2*PANEL_Z - z , f, drawmethod, ent_list_size*100 - sortid);
13247 					}
13248 				}//end of if(f<sprites_loaded)
13249 
13250 				if(e->modeldata.gfxshadow==1 && f<sprites_loaded)//gfx shadow
13251 				{
13252 					useshadow = (e->animation->shadow?e->animation->shadow[e->animpos]:1) && shadowcolor && light[1];
13253 					//printf("\n %d, %d, %d\n", shadowcolor, light[0], light[1]);
13254 					if(useshadow && e->a>=0 && (!e->modeldata.aironly || (e->modeldata.aironly && inair(e))))
13255 					{
13256 						wall = checkwall_below(e->x, e->z, e->a);
13257 						if(wall<0)
13258 						{
13259 							alty = (int)e->a;
13260 							temp1 = -1*e->a*light[0]/256; // xshift
13261 							temp2 = (float)(-alty*light[1]/256);                   // zshift
13262 							qx = (int)(e->x - scrx/* + temp1*/);
13263 							qy = (int)(e->z - scry/* +  temp2*/);
13264 						}
13265 						else
13266 						{
13267 							alty = (int)(e->a-level->walls[wall][7]);
13268 							temp1 = -1*(e->a-level->walls[wall][7])*light[0]/256; // xshift
13269 							temp2 = (float)(-alty*light[1]/256);                   // zshift
13270 							qx = (int)(e->x - scrx/* + temp1*/);
13271 							qy = (int)(e->z - scry /*+  temp2*/ - level->walls[wall][7]);
13272 						}
13273 
13274 						wall2=checkwall_below(e->x + temp1, e->z + temp2, e->a); // check if the shadow drop into a hole or fall on another wall
13275 
13276 						//TODO check platforms, don't want to go through the entity list again right now
13277 						if(!(checkhole(e->x + temp1, e->z + temp2) && wall2<0 && !other) )//&& !(wall>=0 && level->walls[wall][7]>e->a))
13278 						{
13279 							if(wall>=0 && wall2 >= 0)
13280 							{
13281 							   alty += (int)(level->walls[wall][7] - level->walls[wall2][7]);
13282 							   /*qx += -1*(level->walls[wall][7]-level->walls[wall2][7])*light[0]/256;
13283 							   qy += (level->walls[wall][7]-level->walls[wall2][7]) - (level->walls[wall][7]-level->walls[wall2][7])*light[1]/256;*/
13284 							}
13285 							else if(wall>=0)
13286 							{
13287 							   alty += (int)(level->walls[wall][7]);
13288 							   /*qx += -1*level->walls[wall][7]*light[0]/256;
13289 							   qy += level->walls[wall][7] - level->walls[wall][7]*light[1]/256;*/
13290 							}
13291 							else if(wall2>=0)
13292 							{
13293 							   alty -= (int)(level->walls[wall2][7]);
13294 							   /*qx -= -1*level->walls[wall2][7]*light[0]/256;
13295 							   qy -= level->walls[wall2][7] - level->walls[wall2][7]*light[1]/256;*/
13296 							}
13297 							sy = (2*MIRROR_Z - qy) - 2*scry;
13298 							z = shadowz;
13299 							sz = PANEL_Z-HUD_Z;
13300 							if(e->animation->shadow_coords)
13301 							{
13302 								if(e->direction) qx += e->animation->shadow_coords[e->animpos][0];
13303 								else qx -= e->animation->shadow_coords[e->animpos][0];
13304 								qy += e->animation->shadow_coords[e->animpos][1];
13305 								sy -= e->animation->shadow_coords[e->animpos][1];
13306 							}
13307 							shadowmethod = plainmethod;
13308 							shadowmethod.fillcolor = (shadowcolor>0?shadowcolor:0);
13309 							shadowmethod.alpha = shadowalpha;
13310 							shadowmethod.scalex = drawmethod->scalex;
13311 							shadowmethod.flipx = drawmethod->flipx;
13312 							shadowmethod.scaley = light[1]*drawmethod->scaley/256;
13313 							shadowmethod.flipy = drawmethod->flipy;
13314 							shadowmethod.centery += alty;
13315 							if(shadowmethod.flipy) shadowmethod.centery = -shadowmethod.centery;
13316 							if(shadowmethod.scaley<0)
13317 							{
13318 								shadowmethod.scaley = -shadowmethod.scaley;
13319 								shadowmethod.flipy = !shadowmethod.flipy;
13320 							}
13321 							shadowmethod.rotate = drawmethod->rotate;
13322 							shadowmethod.shiftx = drawmethod->shiftx + light[0];
13323 
13324 							spriteq_add_sprite(qx, qy, z, f, &shadowmethod, 0);
13325 							if(use_mirror)
13326 							{
13327 								shadowmethod.flipy = !shadowmethod.flipy;
13328 								shadowmethod.centery = -shadowmethod.centery;
13329 								spriteq_add_sprite(qx, sy, sz, f, &shadowmethod, 0);
13330 							}
13331 						}
13332 					}//end of gfxshadow
13333 				}
13334 				else //plain shadow
13335 				{
13336 					useshadow = e->animation->shadow?e->animation->shadow[e->animpos]:e->modeldata.shadow;
13337 					if(useshadow<0) {useshadow=e->modeldata.shadow;}
13338 					if(useshadow && e->a>=0 && !(checkhole(e->x, e->z) && checkwall_below(e->x, e->z, e->a)<0) && (!e->modeldata.aironly || (e->modeldata.aironly && inair(e))))
13339 					{
13340 						if(other && other != e && e->a >= other->a + other->animation->platform[other->animpos][7])
13341 						{
13342 							qx = (int)(e->x - scrx);
13343 							qy = (int)(e->z - other->a - other->animation->platform[other->animpos][7] - scry);
13344 							sy = (int)((2*MIRROR_Z - e->z) - other->a - other->animation->platform[other->animpos][7] - scry);
13345 							z = (int)(other->z + 1);
13346 							sz = 2*PANEL_Z - z;
13347 						}
13348 						else if(level && wall >= 0)// && e->a >= level->walls[wall][7])
13349 						{
13350 							qx = (int)(e->x - scrx);
13351 							qy = (int)(e->z - level->walls[wall][7] - scry);
13352 							sy = (int)((2*MIRROR_Z - e->z)  - level->walls[wall][7] - scry);
13353 							z = shadowz;
13354 							sz = PANEL_Z-HUD_Z;
13355 						}
13356 						else
13357 						{
13358 							qx = (int)(e->x - scrx);
13359 							qy = (int)(e->z - scry);
13360 							sy = (int)((2*MIRROR_Z - e->z) - scry);
13361 							z = shadowz;
13362 							sz = PANEL_Z-HUD_Z;
13363 						}
13364 						if(e->animation->shadow_coords)
13365 						{   if(e->direction) qx += e->animation->shadow_coords[e->animpos][0];
13366 							else qx -= e->animation->shadow_coords[e->animpos][0];
13367 							qy += e->animation->shadow_coords[e->animpos][1];
13368 							sy -= e->animation->shadow_coords[e->animpos][1];
13369 						}
13370 						shadowmethod=plainmethod;
13371 						shadowmethod.alpha = BLEND_MULTIPLY+1;
13372 						shadowmethod.flipx = !e->direction;
13373 						spriteq_add_sprite(qx, qy, z, shadowsprites[useshadow-1], &shadowmethod, 0);
13374 						if(use_mirror)
13375 						spriteq_add_sprite(qx, sy, sz, shadowsprites[useshadow-1], &shadowmethod, 0);
13376 					}//end of plan shadow
13377 				}
13378 			}// end of blink checking
13379 
13380 			if(e->arrowon)    // Display the players image while invincible to indicate player number
13381 			{
13382 				if(e->modeldata.parrow[(int)e->playerindex][0] && e->invincible == 1)
13383 					spriteq_add_sprite((int)(e->x - scrx + e->modeldata.parrow[(int)e->playerindex][1]), (int)(e->z-e->a-scry + e->modeldata.parrow[(int)e->playerindex][2]), (int)e->z, e->modeldata.parrow[(int)e->playerindex][0], NULL, sortid*2);
13384 			}
13385 		}// end of if(ent_list[i]->exists)
13386 	}// end of for
13387 }
13388 
13389 
13390 
toss(entity * ent,float lift)13391 void toss(entity *ent, float lift)
13392 {
13393 	if(!lift) return; //zero?
13394 	ent->toss_time = time + 1;
13395 	ent->tossv = lift;
13396 	ent->a += 0.5;        // Get some altitude (needed for checks)
13397 }
13398 
13399 
13400 
findent(int types)13401 entity * findent(int types)
13402 {
13403 	int i;
13404 	for(i=0; i<ent_max; i++)
13405 	{ // 2007-12-18, remove all nodieblink checking, because dead corpse with nodieblink 3 will be changed to TYPE_NONE
13406 	  // so if it is "dead" and TYPE_NONE, it must be a corpse
13407 		if(ent_list[i]->exists && (ent_list[i]->modeldata.type & types) && !(ent_list[i]->dead && ent_list[i]->modeldata.type==TYPE_NONE))
13408 		{
13409 				return ent_list[i];
13410 		}
13411 	}
13412 	return NULL;
13413 }
13414 
13415 
13416 
count_ents(int types)13417 int count_ents(int types)
13418 {
13419 	int i;
13420 	int count = 0;
13421 	for(i=0; i<ent_max; i++)
13422 	{ // 2007-12-18, remove all nodieblink checking, because dead corpse with nodieblink 3 will be changed to TYPE_NONE
13423 	  // so if it is "dead" and TYPE_NONE, it must be a corpse
13424 		count += (ent_list[i]->exists && (ent_list[i]->modeldata.type & types) && !(ent_list[i]->dead && ent_list[i]->modeldata.type==TYPE_NONE));
13425 	}
13426 	return count;
13427 }
13428 
isItem(entity * e)13429 int isItem(entity* e) {
13430 	return e->modeldata.type & TYPE_ITEM;
13431 }
13432 
isSubtypeTouch(entity * e)13433 int isSubtypeTouch(entity* e) {
13434 	return e->modeldata.subtype == SUBTYPE_TOUCH;
13435 }
13436 
isSubtypeWeapon(entity * e)13437 int isSubtypeWeapon(entity* e) {
13438 	return e->modeldata.subtype == SUBTYPE_WEAPON;
13439 }
13440 
isSubtypeProjectile(entity * e)13441 int isSubtypeProjectile(entity* e) {
13442 	return e->modeldata.subtype == SUBTYPE_PROJECTILE;
13443 }
13444 
canBeDamaged(entity * who,entity * bywhom)13445 int canBeDamaged(entity* who, entity* bywhom) {
13446 	return (who->modeldata.candamage & bywhom->modeldata.type) == bywhom->modeldata.type;
13447 }
13448 
13449 //check if an item is usable by the entity
normal_test_item(entity * ent,entity * item)13450 int normal_test_item(entity* ent, entity* item){
13451 	return (
13452 		isItem(item) &&
13453 		(item->modeldata.stealth.hide <= ent->modeldata.stealth.detect) &&
13454 		diff(item->x,ent->x) + diff(item->z,ent->z)< videomodes.hRes/2 &&
13455 		item->animation->vulnerable[item->animpos] && !item->blink &&
13456 		(validanim(ent,ANI_GET) || (isSubtypeTouch(item) && canBeDamaged(item, ent))) &&
13457 		(
13458 			(isSubtypeWeapon(item) && !ent->weapent && ent->modeldata.weapon &&
13459 			 ent->modeldata.numweapons>=item->modeldata.weapnum && ent->modeldata.weapon[item->modeldata.weapnum-1]>=0)
13460 			||(isSubtypeProjectile(item) && !ent->weapent)
13461 			||(item->health && (ent->health < ent->modeldata.health) && ! isSubtypeProjectile(item) && ! isSubtypeWeapon(item))
13462 		)
13463 	);
13464 }
13465 
test_item(entity * ent,entity * item)13466 int test_item(entity* ent, entity* item){
13467 	if (!(
13468 		isItem(item) &&
13469 		item->animation->vulnerable[item->animpos] && !item->blink &&
13470 		(validanim(ent,ANI_GET) || (isSubtypeTouch(item) && canBeDamaged(item, ent)))
13471 	)) return 0;
13472 	if(isSubtypeProjectile(item) && ent->weapent) return 0;
13473 	if(isSubtypeWeapon(item) &&
13474 		(ent->weapent || !ent->modeldata.weapon ||
13475 		ent->modeldata.numweapons<item->modeldata.weapnum ||
13476 		ent->modeldata.weapon[item->modeldata.weapnum-1]<0)
13477 	) return 0;
13478 	return 1;
13479 }
13480 
player_test_pickable(entity * ent,entity * item)13481 int player_test_pickable(entity* ent, entity* item){
13482 	if(isSubtypeTouch(item)) return 0;
13483 	if(isSubtypeWeapon(item) && ent->modeldata.animal==2) return 0;
13484 	if(diff(ent->base , item->a)>0.1) return 0;
13485 	return test_item(ent, item);
13486 }
13487 
player_test_touch(entity * ent,entity * item)13488 int player_test_touch(entity* ent, entity* item){
13489 	if(!isSubtypeTouch(item)) return 0;
13490 	if(isSubtypeWeapon(item) && ent->modeldata.animal==2) return 0;
13491 	if(diff(ent->base , item->a)>1) return 0;
13492 	return test_item(ent, item);
13493 }
13494 
find_ent_here(entity * exclude,float x,float z,int types,int (* test)(entity *,entity *))13495 entity * find_ent_here(entity *exclude, float x, float z, int types, int (*test)(entity*,entity*))
13496 {
13497 	int i;
13498 	for(i=0; i<ent_max; i++)
13499 	{
13500 		if( ent_list[i]->exists
13501 			&& ent_list[i] != exclude
13502 			&& (ent_list[i]->modeldata.type & types)
13503 			&& diff(ent_list[i]->x,x)<(self->modeldata.grabdistance*0.83333)
13504 			&& diff(ent_list[i]->z,z)<(self->modeldata.grabdistance/3)
13505 			&& ent_list[i]->animation->vulnerable[ent_list[i]->animpos]
13506 			&& (!test || test(exclude,ent_list[i]))
13507 		)
13508 		{
13509 			return ent_list[i];
13510 		}
13511 	}
13512 	return NULL;
13513 }
13514 
set_idle(entity * ent)13515 int set_idle(entity* ent)
13516 {
13517 	//int ani = ANI_IDLE;
13518 	//if(validanim(ent,ANI_FAINT) && ent->health <= ent->modeldata.health / 4) ani = ANI_FAINT;
13519 	//if(validanim(ent,ani)) ent_set_anim(ent, ani, 0);
13520 	if (common_idle_anim(ent))
13521 	{
13522 	}
13523 	else return 0;
13524 	ent->idling = 1;
13525 	ent->attacking = 0;
13526 	ent->inpain = 0;
13527 	ent->jumping = 0;
13528 	ent->blocking = 0;
13529 	return 1;
13530 }
13531 
set_death(entity * iDie,int type,int reset)13532 int set_death(entity *iDie, int type, int reset)
13533 {
13534 	//iDie->xdir = iDie->zdir = iDie->tossv = 0; // stop the target
13535 	if(iDie->blocking && validanim(iDie, ANI_CHIPDEATH)){
13536 		ent_set_anim(iDie,ANI_CHIPDEATH,reset);
13537 		iDie->idling = 0;
13538 		iDie->getting = 0;
13539 		iDie->jumping = 0;
13540 		iDie->charging = 0;
13541 		iDie->attacking = 0;
13542 		iDie->blocking = 0;
13543 		return 1;
13544 	}
13545 	if(type < 0 || type >= max_attack_types || !validanim(iDie,animdies[type])) type = 0;
13546 	if(validanim(iDie,animdies[type])) ent_set_anim(iDie, animdies[type], reset);
13547 	else return 0;
13548 
13549 	iDie->idling = 0;
13550 	iDie->getting = 0;
13551 	iDie->jumping = 0;
13552 	iDie->charging = 0;
13553 	iDie->attacking = 0;
13554 	iDie->blocking = 0;
13555 	if(iDie->frozen) unfrozen(iDie);
13556 	return 1;
13557 }
13558 
13559 
set_fall(entity * iFall,int type,int reset,entity * other,int force,int drop,int noblock,int guardcost,int jugglecost,int pauseadd)13560 int set_fall(entity *iFall, int type, int reset, entity* other, int force, int drop, int noblock, int guardcost, int jugglecost, int pauseadd)
13561 {
13562 	if(type < 0 || type >= max_attack_types || !validanim(iFall,animfalls[type])) type = 0;
13563 	if(validanim(iFall,animfalls[type])) ent_set_anim(iFall, animfalls[type], reset);
13564 	else return 0;
13565 	iFall->drop = 1;
13566 	iFall->inpain = 0;
13567 	iFall->idling = 0;
13568 	iFall->falling = 1;
13569 	iFall->jumping = 0;
13570 	iFall->getting = 0;
13571 	iFall->charging = 0;
13572 	iFall->attacking = 0;
13573 	iFall->blocking = 0;
13574 	iFall->nograb = 1;
13575 	if(iFall->frozen) unfrozen(iFall);
13576 	execute_onfall_script(iFall, other, force, drop, type, noblock, guardcost, jugglecost, pauseadd);
13577 
13578 	return 1;
13579 }
13580 
set_rise(entity * iRise,int type,int reset)13581 int set_rise(entity *iRise, int type, int reset)
13582 {
13583 	if(type < 0 || type >= max_attack_types || !validanim(iRise,animrises[type])) type = 0;
13584 	if(validanim(iRise,animrises[type])) ent_set_anim(iRise, animrises[type], reset);
13585 	else return 0;
13586 	iRise->takeaction = common_rise;
13587 	// Get up again
13588 	iRise->drop = 0;
13589 	iRise->falling = 0;
13590 	iRise->projectile = 0;
13591 	iRise->nograb = 0;
13592 	iRise->xdir = self->zdir = self->tossv = 0;
13593 	iRise->modeldata.jugglepoints.current = iRise->modeldata.jugglepoints.maximum; //reset jugglepoints
13594 	return 1;
13595 }
13596 
set_riseattack(entity * iRiseattack,int type,int reset)13597 int set_riseattack(entity *iRiseattack, int type, int reset)
13598 {
13599 	if(!validanim(iRiseattack,animriseattacks[type]) && iRiseattack->modeldata.riseattacktype == 1) type = 0;
13600 	if(iRiseattack->modeldata.riseattacktype == 0 || type < 0 || type >= max_attack_types) type = 0;
13601 	if(!validanim(iRiseattack,animriseattacks[type])) return 0;
13602 
13603 	iRiseattack->takeaction = common_attack_proc;
13604 	self->staydown.riseattack_stall = 0;			//Reset riseattack delay.
13605 	set_attacking(iRiseattack);
13606 	iRiseattack->drop = 0;
13607 	iRiseattack->nograb = 0;
13608 	iRiseattack->modeldata.jugglepoints.current = iRiseattack->modeldata.jugglepoints.maximum; //reset jugglepoints
13609 	ent_set_anim(iRiseattack, animriseattacks[type], 0);
13610 	return 1;
13611 }
13612 
set_blockpain(entity * iBlkpain,int type,int reset)13613 int set_blockpain(entity *iBlkpain, int type, int reset)
13614 {
13615 	if(!validanim(iBlkpain,ANI_BLOCKPAIN)){
13616 		iBlkpain->takeaction = common_pain;
13617 		return 1;
13618 	}
13619 	if(type < 0 || type >= max_attack_types || !validanim(iBlkpain,animblkpains[type])) type = 0;
13620 	if(!validanim(iBlkpain,animblkpains[type])) return 0;
13621 	iBlkpain->takeaction = common_block;
13622 	set_attacking(iBlkpain);
13623 	ent_set_anim(iBlkpain, animblkpains[type], reset);
13624 	return 1;
13625 }
13626 
set_pain(entity * iPain,int type,int reset)13627 int set_pain(entity *iPain, int type, int reset)
13628 {
13629 	int pain = 0;
13630 
13631 	iPain->xdir = iPain->zdir = iPain->tossv = 0; // stop the target
13632 	if(iPain->modeldata.guardpoints.maximum > 0 && iPain->modeldata.guardpoints.current <= 0) pain = ANI_GUARDBREAK;
13633 	else if(type == -1 || type >= max_attack_types) pain = ANI_GRABBED;
13634 	else pain = animpains[type];
13635 	if(validanim(iPain,pain))              ent_set_anim(iPain, pain, reset);
13636 	else if(validanim(iPain,animpains[0])) ent_set_anim(iPain, animpains[0], reset);
13637 	else if(validanim(iPain,ANI_IDLE))     ent_set_anim(iPain, ANI_IDLE, reset);
13638 	else return 0;
13639 
13640 	if(pain == ANI_GRABBED) iPain->inpain = 0;
13641 	else iPain->inpain = 1;
13642 
13643 	iPain->idling = 0;
13644 	iPain->falling = 0;
13645 	iPain->projectile = 0;
13646 	iPain->drop = 0;
13647 	iPain->attacking = 0;
13648 	iPain->getting = 0;
13649 	iPain->charging = 0;
13650 	iPain->jumping = 0;
13651 	iPain->blocking = 0;
13652 	if(iPain->modeldata.guardpoints.maximum > 0 && iPain->modeldata.guardpoints.current <= 0) iPain->modeldata.guardpoints.current = iPain->modeldata.guardpoints.maximum;
13653 	if(iPain->frozen) unfrozen(iPain);
13654 
13655 	execute_onpain_script(iPain, type, reset);
13656 	return 1;
13657 }
13658 
13659 
13660 //change model, anim_flag 1: reset animation 0: use original animation
set_model_ex(entity * ent,char * modelname,int index,s_model * newmodel,int anim_flag)13661 void set_model_ex(entity* ent, char* modelname, int index, s_model* newmodel, int anim_flag)
13662 {
13663 	s_model* model = NULL;
13664 	int   i;
13665 	int   type = ent->modeldata.type;
13666 
13667 	model = ent->model;
13668 	if(!newmodel)
13669 	{
13670 		if(index>=0) newmodel = model_cache[index].model;
13671 		else newmodel = findmodel(modelname);
13672 	}
13673 	if(!newmodel) shutdown(1, "Can't set model for entity '%s', model not found.\n", ent->name);
13674 	if(newmodel==model) return;
13675 
13676 	if(!(newmodel->model_flag & MODEL_NO_COPY))
13677 	{
13678 		if(!newmodel->speed) newmodel->speed = model->speed;
13679 		if(!newmodel->runspeed)
13680 		{
13681 			newmodel->runspeed = model->runspeed;
13682 			newmodel->runjumpheight = model->runjumpheight;
13683 			newmodel->runjumpdist = model->runjumpdist;
13684 			newmodel->runupdown = model->runupdown;
13685 			newmodel->runhold = model->runhold;
13686 		}
13687 		if(newmodel->icon.def           <   0)  newmodel->icon.def          = model->icon.def;
13688 		if(newmodel->icon.pain       <   0)  newmodel->icon.pain      = model->icon.pain;
13689 		if(newmodel->icon.get        <   0)  newmodel->icon.get       = model->icon.get;
13690 		if(newmodel->icon.die        <   0)  newmodel->icon.die       = model->icon.die;
13691 		if(newmodel->shadow         <   0)  newmodel->shadow        = model->shadow;
13692 		if(newmodel->knife          <   0)  newmodel->knife         = model->knife;
13693 		if(newmodel->pshotno        <   0)  newmodel->pshotno       = model->pshotno;
13694 		if(newmodel->bomb           <   0)  newmodel->bomb          = model->bomb;
13695 		if(newmodel->star           <   0)  newmodel->star          = model->star;
13696 		if(newmodel->flash          <   0)  newmodel->flash         = model->flash;
13697 		if(newmodel->bflash         <   0)  newmodel->bflash        = model->bflash;
13698 		if(newmodel->dust[0]        <   0)  newmodel->dust[0]       = model->dust[0];
13699 		if(newmodel->dust[1]        <   0)  newmodel->dust[1]       = model->dust[1];
13700 		if(newmodel->diesound       <   0)  newmodel->diesound      = model->diesound;
13701 
13702 		for(i=0; i<max_animations; i++)
13703 		{
13704 			if(!newmodel->animation[i] && model->animation[i] && model->animation[i]->numframes>0)
13705 				newmodel->animation[i] = model->animation[i];
13706 		}
13707 		// copy the weapon list if model flag is not set to use its own weapon list
13708 		if(!(newmodel->model_flag & MODEL_NO_WEAPON_COPY))
13709 		{
13710 			newmodel->weapnum = model->weapnum;
13711 			if(!newmodel->weapon) {
13712 				newmodel->weapon = model->weapon;
13713 				newmodel->numweapons = model->numweapons;
13714 			}
13715 		}
13716 	}
13717 
13718 	ent_set_model(ent, newmodel->name, anim_flag);
13719 
13720 	ent->modeldata.type = type;
13721 
13722 	if((newmodel->model_flag & MODEL_NO_SCRIPT_COPY))
13723 		clear_all_scripts(ent->scripts, 0);
13724 
13725 	copy_all_scripts(newmodel->scripts, ent->scripts, 0);
13726 	memcpy(ent->defense, ent->modeldata.defense, sizeof(s_defense)*max_attack_types);
13727 	memcpy(ent->offense_factors, ent->modeldata.offense_factors, sizeof(float)*max_attack_types);
13728 
13729 	ent_set_colourmap(ent, ent->map);
13730 }
13731 
set_weapon(entity * ent,int wpnum,int anim_flag)13732 void set_weapon(entity* ent, int wpnum, int anim_flag) // anim_flag added for scripted midair weapon changing
13733 {
13734 	if(!ent) return;
13735 //printf("setweapon: %d \n", wpnum);
13736 
13737 	if(ent->modeldata.weapon && wpnum > 0 && wpnum <= ent->modeldata.numweapons && ent->modeldata.weapon[wpnum-1])
13738 		set_model_ex(ent, NULL, ent->modeldata.weapon[wpnum-1], NULL, !anim_flag);
13739 	else set_model_ex(ent, NULL, -1, ent->defaultmodel, 1);
13740 
13741 	if(ent->modeldata.type == TYPE_PLAYER) // save current weapon for player's weaploss 3
13742 	{
13743 		if(ent->modeldata.weaploss[0] >= 3) player[(int)ent->playerindex].weapnum = wpnum;
13744 		else player[(int)ent->playerindex].weapnum = level->setweap;
13745 	}
13746 }
13747 
13748 //////////////////////////////////////////////////////////////////////////
13749 //                  common A.I. code for enemies & NPCs
13750 //////////////////////////////////////////////////////////////////////////
13751 
13752 
melee_find_target()13753 entity* melee_find_target()
13754 {
13755 	return NULL;
13756 }
13757 
long_find_target()13758 entity* long_find_target()
13759 {
13760 	return NULL;
13761 }
13762 
block_find_target(int anim,int iDetect)13763 entity* block_find_target(int anim, int iDetect){
13764 	int i , min, max;
13765 	int index = -1;
13766 	min = 0;
13767 	max = 9999;
13768 	float diffx, diffz, diffd, diffo = 0;
13769 
13770     iDetect += self->modeldata.stealth.detect;
13771 
13772 	//find the 'nearest' attacking one
13773 	for(i=0; i<ent_max; i++)
13774 	{
13775 		if( ent_list[i]->exists && ent_list[i] != self //cant target self
13776 			&& (ent_list[i]->modeldata.candamage & self->modeldata.type)
13777 			&& (anim<0||(anim>=0 && check_range(self, ent_list[i], anim)))
13778 			&& !ent_list[i]->dead &&  ent_list[i]->attacking//must be alive
13779 			&& ent_list[i]->animation->attacks && (!ent_list[i]->animation->attacks[ent_list[i]->animpos]
13780 			|| ent_list[i]->animation->attacks[ent_list[i]->animpos]->no_block==0)
13781 			&& (diffd=(diffx=diff(ent_list[i]->x,self->x))+ (diffz=diff(ent_list[i]->z,self->z))) >= min
13782 			&& diffd <= max
13783 			&& (ent_list[i]->modeldata.stealth.hide <= iDetect) //Stealth factor less then perception factor (allows invisibility).
13784 			  )
13785 		{
13786 
13787 			if(index <0 || diffd < diffo)
13788 			{
13789 				index = i;
13790 				diffo = diffd;
13791 			}
13792 		}
13793 	}
13794 	if( index >=0) {return ent_list[index];}
13795 	return NULL;
13796 }
13797 
normal_find_target(int anim,int iDetect)13798 entity* normal_find_target(int anim, int iDetect)
13799 {
13800 
13801     /*
13802     normal_find_target
13803     Author unknown
13804     Date unknown
13805     ~Damon Caskey, 2011_07_22: Add support for detect adjustment.
13806 
13807     int anim:       Animation find range will be calculated by. Default to current animation if not passed.
13808     int iDetect:    Local detection adjustment. Allows lesser or greater penetration of target's stealth for location.
13809     */
13810 
13811 	int i , min, max;
13812 	int index = -1;
13813 	min = 0;
13814 	max = 9999;
13815 	float diffx, diffz, diffd, diffo = 0;
13816 
13817     iDetect += self->modeldata.stealth.detect;
13818 
13819 	//find the 'nearest' one
13820 	for(i=0; i<ent_max; i++)
13821 	{
13822 		if( ent_list[i]->exists && ent_list[i] != self //cant target self
13823 			&& (ent_list[i]->modeldata.type & self->modeldata.hostile)
13824 			&& (anim<0||(anim>=0 && check_range(self, ent_list[i], anim)))
13825 			&& !ent_list[i]->dead //must be alive
13826 			&& (diffd=(diffx=diff(ent_list[i]->x,self->x))+ (diffz=diff(ent_list[i]->z,self->z))) >= min
13827 			&& diffd <= max
13828 			&& (ent_list[i]->modeldata.stealth.hide <= iDetect) //Stealth factor less then perception factor (allows invisibility).
13829 			  )
13830 		{
13831 
13832 			if(index <0 || (index>=0 && (!ent_list[index]->animation->vulnerable[ent_list[index]->animpos] || ent_list[index]->invincible == 1)) ||
13833 				(
13834 					(self->x < ent_list[i]->x) == (self->direction) && // don't turn to the one on the back
13835 					//ent_list[i]->x >= advancex-10 && ent_list[i]->x<advancex+videomodes.hRes+10 && // don't turn to an offscreen target
13836 					//ent_list[i]->z >= advancey-10 && ent_list[i]->z<advancey+videomodes.vRes+10 &&
13837 					diffd < diffo
13838 				)
13839 			)
13840 			{
13841 				index = i;
13842 				diffo = diffd;
13843 			}
13844 		}
13845 	}
13846 	if( index >=0) {return ent_list[index];}
13847 	return NULL;
13848 }
13849 
13850 //Used by default A.I. pattern
13851 // A.I. characters try to find a pickable item
normal_find_item()13852 entity * normal_find_item(){
13853 
13854 	int i;
13855 	int index = -1;
13856 	entity* ce = NULL;
13857 	//find the 'nearest' one
13858 	for(i=0; i<ent_max; i++){
13859 		ce = ent_list[i];
13860 
13861 		if( ce->exists && normal_test_item(self, ce) ){
13862 			if(index <0 || diff(ce->x, self->x) + diff(ce->z, self->z) < diff(ent_list[index]->x, self->x) + diff(ent_list[index]->z, self->z))
13863 				index = i;
13864 		}
13865 	}
13866 	if( index >=0) return ent_list[index];
13867 	return NULL;
13868 }
13869 
long_attack()13870 int long_attack()
13871 {
13872 	return 0;
13873 }
13874 
melee_attack()13875 int melee_attack()
13876 {
13877 	return 0;
13878 }
13879 
13880 // chose next attack in atchain, if succeeded, return 1, otherwise return 0.
perform_atchain()13881 int perform_atchain()
13882 {
13883 	int pickanim = 0;
13884 	if(self->combotime > time)
13885 		self->combostep[0]++;
13886 	else self->combostep[0] = 1;
13887 
13888 	if(self->modeldata.atchain[self->combostep[0]-1]==0) // 0 means the chain ends
13889 	{
13890 		self->combostep[0] = 0;
13891 		return 0;
13892 	}
13893 
13894 	if(validanim(self,animattacks[self->modeldata.atchain[self->combostep[0]-1]-1]) )
13895 	{
13896 		if(((self->combostep[0]==1||!(self->modeldata.combostyle&1)) && self->modeldata.type==TYPE_PLAYER) ||  // player should use attack 1st step without checking range
13897 		   (!(self->modeldata.combostyle&1) && normal_find_target(animattacks[self->modeldata.atchain[0]-1],0)) || // normal chain just checks the first attack in chain(guess no one like it)
13898 		   ((self->modeldata.combostyle&1) && normal_find_target(animattacks[self->modeldata.atchain[self->combostep[0]-1]-1],0))) // combostyle 1 checks all anyway
13899 		{
13900 			pickanim = 1;
13901 		}
13902 		else if((self->modeldata.combostyle&1) && self->combostep[0]!=1) // ranged combo? search for a valid attack
13903 		{
13904 			while(++self->combostep[0]<=self->modeldata.chainlength)
13905 			{
13906 				if(self->modeldata.atchain[self->combostep[0]-1] &&
13907 				   validanim(self,animattacks[self->modeldata.atchain[self->combostep[0]-1]-1]) &&
13908 				   (self->combostep[0]==self->modeldata.chainlength ||
13909 					normal_find_target(animattacks[self->modeldata.atchain[self->combostep[0]-1]-1],0)))
13910 				{
13911 					pickanim = 1;
13912 					break;
13913 				}
13914 			}
13915 		}
13916 	}
13917 	else self->combostep[0] = 0;
13918 	if(pickanim)
13919 	{
13920 		self->takeaction = common_attack_proc;
13921 		set_attacking(self);
13922 		ent_set_anim(self, animattacks[self->modeldata.atchain[self->combostep[0]-1]-1], 1);
13923 	}
13924 	if(!pickanim || self->combostep[0] > self->modeldata.chainlength) self->combostep[0] = 0;
13925 	if((self->modeldata.combostyle&2)) self->combotime = time + combodelay;
13926 	return pickanim;
13927 }
13928 
normal_prepare()13929 void normal_prepare()
13930 {
13931 	int i, j;
13932 	int found = 0, special = 0;
13933 	int predir = self->direction;
13934 
13935 	entity* target = normal_find_target(-1,0);
13936 
13937 	self->xdir = self->zdir = 0; //stop
13938 
13939 	if(!target)
13940 	{
13941 		self->idling = 1;
13942 		self->takeaction = NULL;
13943 		return;
13944 	}
13945 
13946 	//check if target is behind, so we can perform a turn back animation
13947 	if(!self->modeldata.noflip) self->direction = (self->x < target->x);
13948 	if(predir != self->direction && validanim(self,ANI_TURN))
13949 
13950 	{
13951 		self->takeaction = common_turn;
13952 		self->direction = predir;
13953 		set_turning(self);
13954 		ent_set_anim(self, ANI_TURN, 0);
13955 		return;
13956 	}
13957 
13958 	// Wait...
13959 	if(time < self->stalltime) return;
13960 
13961 
13962 	// let go the projectile, well
13963 	if( self->weapent && self->weapent->modeldata.subtype == SUBTYPE_PROJECTILE &&
13964 		validanim(self,ANI_THROWATTACK) &&
13965 		check_range(self, target, ANI_THROWATTACK))
13966 	{
13967 		self->takeaction = common_attack_proc;
13968 		set_attacking(self);
13969 		ent_set_anim(self, ANI_THROWATTACK, 0);
13970 		return ;
13971 	}
13972 
13973 	// move freespecial check here
13974 
13975 	for(i=0; i<max_freespecials; i++) {
13976 		if(validanim(self,animspecials[i]) &&
13977 		   (check_energy(1, animspecials[i]) ||
13978 			check_energy(0, animspecials[i])) &&
13979 			check_range(self, target, animspecials[i]))
13980 		{
13981 			atkchoices[found++] = animspecials[i];
13982 		}
13983 	}
13984 	if((rand32()&7) < 2)
13985 	{
13986 		if(found && check_costmove(atkchoices[(rand32()&0xffff)%found], 1, 0) ){
13987 			return;
13988 		}
13989 	}
13990 	special = found;
13991 
13992 	if(self->modeldata.chainlength > 1) // have a chain?
13993 	{
13994 		if(perform_atchain()) return;
13995 	}
13996 	else // dont have a chain so just select an attack randomly
13997 	{
13998 		// Pick an attack
13999 		for(i=0; i<max_attacks; i++)
14000 		{
14001 			if( validanim(self,animattacks[i]) &&
14002 				check_range(self, target, animattacks[i]))
14003 			{
14004 				// a trick to make attack 1 has a greater chance to be chosen
14005 				// 6 5 4 3 2 1 1 1 1 1 ....
14006 				for(j=((5-i)>=0?(5-i):0); j>=0; j--) atkchoices[found++] = animattacks[i];
14007 			}
14008 		}
14009 		if(found>special){
14010 			self->takeaction = common_attack_proc;
14011 			set_attacking(self);
14012 			ent_set_anim(self, atkchoices[special + (rand32()&0xffff)%(found-special)], 0);
14013 			return ;
14014 		}
14015 	}
14016 
14017 	// if no attack was picked, just choose a random one from the valid list
14018 	if(special && check_costmove(atkchoices[(rand32()&0xffff)%special], 1, 0)){
14019 		return;
14020 	}
14021 
14022 	// No attack to perform, return to A.I. root
14023 	self->idling = 1;
14024 	self->takeaction = NULL;
14025 }
14026 
common_jumpland()14027 void common_jumpland()
14028 {
14029 	if(self->animating) return;
14030 	self->takeaction = NULL;
14031 	set_idle(self);
14032 }
14033 
14034 //A.I characters play the jump animation
common_jump()14035 void common_jump()
14036 {
14037 	entity* dust;
14038 
14039 	if(inair(self))
14040 	{
14041 		return;
14042 	}
14043 
14044 	if(self->tossv<=0) // wait if it is still go up
14045 	{
14046 		self->tossv = 0;
14047 		self->a = self->base;
14048 
14049 		self->jumping = 0;
14050 		self->attacking = 0;
14051 
14052 		if(!self->modeldata.runhold) self->running = 0;
14053 
14054 		self->zdir = self->xdir = 0;
14055 
14056 		if(validanim(self,ANI_JUMPLAND) && self->animation->landframe.frame == -1) // check if jumpland animation exists and not using landframe
14057 		{
14058 			self->takeaction = common_jumpland;
14059 			ent_set_anim(self, ANI_JUMPLAND, 0);
14060 			if(self->modeldata.dust[1]>=0)
14061 			{
14062 				dust = spawn(self->x, self->z, self->a, self->direction, NULL, self->modeldata.dust[1], NULL);
14063 				if(dust){
14064 					dust->base = self->a;
14065 					dust->autokill = 2;
14066 					execute_onspawn_script(dust);
14067 				}
14068 			}
14069 		}
14070 		else
14071 		{
14072 			if(self->modeldata.dust[1]>=0 && self->animation->landframe.frame == -1)
14073 			{
14074 				dust = spawn(self->x, self->z, self->a, self->direction, NULL, self->modeldata.dust[1], NULL);
14075 				if(dust){
14076 					dust->base = self->a;
14077 					dust->autokill = 2;
14078 					execute_onspawn_script(dust);
14079 				}
14080 			}
14081 			if(self->animation->landframe.frame >= 0 && self->animating) return;
14082 
14083 			self->takeaction = NULL; // back to A.I. root
14084 			set_idle(self);
14085 		}
14086 	}
14087 }
14088 
14089 //A.I. characters spawn
common_spawn()14090 void common_spawn()
14091 {
14092 	self->idling = 0;
14093 	if(self->animating) return;
14094 	self->takeaction = NULL; // come to life
14095 	set_idle(self);
14096 }
14097 
14098 //A.I. characters drop from the sky
common_drop()14099 void common_drop()
14100 {
14101 	if(inair(self)) return;
14102 	self->idling = 1;
14103 	self->takeaction = NULL;
14104 	if(self->health<=0) kill(self);
14105 }
14106 
14107 //Similar as above, walk off a wall/cliff
common_walkoff()14108 void common_walkoff()
14109 {
14110 	if(inair(self) || self->animating) return;
14111 	self->takeaction = NULL;
14112 	set_idle(self);
14113 }
14114 
14115 // play turn animation and then flip
common_turn()14116 void common_turn()
14117 {
14118 	if(!self->animating)
14119 	{
14120 		self->takeaction = NULL;
14121 		self->xdir = self->zdir = 0;
14122 		self->direction = !self->direction;
14123 		set_idle(self);
14124 	}
14125 }
14126 
14127 // switch to land animation, land safely
doland()14128 void doland()
14129 {
14130 	self->xdir = self->zdir = 0;
14131 	self->drop = 0;
14132 	self->projectile = 0;
14133 	self->damage_on_landing = 0;
14134 	if(validanim(self,ANI_LAND))
14135 	{
14136 		self->takeaction = common_land;
14137 		self->direction = !self->direction;
14138 		ent_set_anim(self, ANI_LAND, 0);
14139 	}
14140 	else
14141 	{
14142 		self->takeaction = NULL;
14143 		set_idle(self);
14144 	}
14145 }
14146 
common_fall()14147 void common_fall()
14148 {
14149 	// Still falling?
14150 	if(self->falling ||  inair(self) || self->tossv)
14151 	{
14152 		return;
14153 	}
14154 
14155 
14156 	//self->xdir = self->zdir;
14157 
14158 	// Landed
14159 	if(self->projectile > 0)
14160 	{
14161 		if(self->projectile == 2)
14162 		{   // damage_on_landing==-2 means a player has pressed up+jump and has a land animation
14163 			if((autoland == 1 && self->damage_on_landing == -1) ||self->damage_on_landing == -2)
14164 			{
14165 				// Added autoland option for landing
14166 				doland();
14167 				return;
14168 			}
14169 		}
14170 		//self->projectile = 0;
14171 		self->falling = 0;
14172 	}
14173 
14174 	// Drop Weapon due to Enemy Falling.
14175 	//if(self->modeldata.weaploss[0] == 1) dropweapon(1);
14176 
14177 	if(self->boss && level_completed) tospeedup = 1;
14178 
14179 	// Pause a bit...
14180 	self->takeaction	= common_lie;
14181 	self->stalltime		= time + MAX(0, (int)(self->staydown.rise + GAME_SPEED - self->modeldata.risetime[0]));	//Set rise delay.
14182 	self->staydown.riseattack_stall	= time + MAX(0, (int)(self->staydown.riseattack - self->modeldata.risetime[1]));					//Set rise attack delay.
14183 	self->staydown.rise = 0; //Reset staydown.
14184 	self->staydown.riseattack = 0; //Reset staydown atk.
14185 }
14186 
common_try_riseattack()14187 void common_try_riseattack()
14188 {
14189 	entity * target;
14190 	if(!validanim(self,ANI_RISEATTACK)) return;
14191 
14192 	target = normal_find_target(ANI_RISEATTACK,0);
14193 	if(!target)
14194 	{
14195 		self->direction = !self->direction;
14196 		target = normal_find_target(ANI_RISEATTACK,0);
14197 		self->direction = !self->direction;
14198 	}
14199 
14200 	if(target)
14201 	{
14202 		self->direction = (target->x > self->x);    // Stands up and swings in the right direction depending on chosen target
14203 		set_riseattack(self, self->damagetype, 0);
14204 	}
14205 }
14206 
common_lie()14207 void common_lie()
14208 {
14209 	// Died?
14210 	if(self->health <= 0)
14211 	{
14212 		if(self->modeldata.falldie == 2) set_death(self, self->damagetype, 0);
14213 		if(!self->modeldata.nodieblink || (self->modeldata.nodieblink == 1 && !self->animating))
14214 		{    // Now have the option to blink or not
14215 			self->takeaction = (self->modeldata.type == TYPE_PLAYER)?player_blink:suicide;
14216 			self->blink = 1;
14217 			self->stalltime  = time + GAME_SPEED * 2;
14218 		}
14219 		else if(self->modeldata.nodieblink == 2  && !self->animating)
14220 		{
14221 			self->takeaction = (self->modeldata.type == TYPE_PLAYER)?player_die:suicide;
14222 
14223 		}
14224 		else if(self->modeldata.nodieblink == 3  && !self->animating)
14225 		{
14226 			if(self->modeldata.type == TYPE_PLAYER)
14227 			{
14228 				self->takeaction = player_die;
14229 
14230 			}
14231 			else
14232 			{
14233 				self->modeldata.type = TYPE_NONE;
14234 				self->noaicontrol = 1;
14235 			}
14236 		}
14237 
14238 		if (self->modeldata.maps.ko)                                                           //Have a KO map?
14239 		{
14240 			if (self->modeldata.maps.kotype)                                                       //Wait for fall/death animation to finish?
14241 			{
14242 				if (!self->animating)
14243 				{
14244 					self->colourmap = self->modeldata.colourmap[self->modeldata.maps.ko-1];    //If finished animating, apply map.
14245 				}
14246 			}
14247 			else                                                                                //Don't bother waiting.
14248 			{
14249 				self->colourmap = self->modeldata.colourmap[self->modeldata.maps.ko-1];        //Apply map.
14250 			}
14251 		}
14252 
14253 		return;
14254 	}
14255 
14256 	if(time < self->stalltime || self->a!=self->base || self->tossv) return;
14257 
14258 	//self->takeaction = common_rise;
14259 	// Get up again
14260 	//self->drop = 0;
14261 	//self->falling = 0;
14262 	//self->projectile = 0;
14263 	//self->xdir = self->zdir = self->tossv = 0;
14264 
14265 	set_rise(self, self->damagetype, 0);
14266 }
14267 
14268 // rise proc
common_rise()14269 void common_rise()
14270 {
14271 	if(self->animating) return;
14272 	self->takeaction = NULL;
14273 	self->staydown.riseattack_stall = 0;	//Reset riseattack delay.
14274 	if(self->modeldata.riseinv)
14275 	{
14276 		self->blink = self->modeldata.riseinv>0;
14277 		self->invinctime = time + ABS(self->modeldata.riseinv);
14278 		self->invincible = 1;
14279 	}
14280 	set_idle(self);
14281 }
14282 
14283 // pain proc
common_pain()14284 void common_pain()
14285 {
14286 	//self->xdir = self->zdir = 0; // complained
14287 
14288 	if(self->animating || inair(self)) return;
14289 
14290 	self->inpain = 0;
14291 	if(self->link){
14292 //        set_pain(self, -1, 0);
14293 		self->takeaction = common_grabbed;
14294 	}
14295 	else if(self->blocking)
14296 	{
14297 		self->takeaction = common_block;
14298 		ent_set_anim(self, ANI_BLOCK, 1);
14299 	}
14300 	else
14301 	{
14302 		self->takeaction = NULL;
14303 		set_idle(self);
14304 	}
14305 }
14306 
doprethrow()14307 void doprethrow()
14308 {
14309 	entity * other = self->link;
14310 	other->takeaction = common_prethrow;
14311 	self->takeaction = common_throw_wait;
14312 	self->xdir = self->zdir = self->tossv = other->xdir = other->zdir = other->tossv = 0;
14313 	ent_set_anim(self, ANI_THROW, 0);
14314 }
14315 
14316 // 1 grabattack 2 grabforward 3 grabup 4 grabdown 5 grabbackward
14317 // other means grab finisher at once
dograbattack(int which)14318 void dograbattack(int which)
14319 {
14320 	entity * other = self->link;
14321 	self->takeaction = common_grabattack;
14322 	self->attacking = 1;
14323 	other->xdir = other->zdir = self->xdir = self->zdir = 0;
14324 	if(which<5 && which>=0)
14325 	{
14326 		++self->combostep[which];
14327 		if(self->combostep[which] < 3)
14328 			ent_set_anim(self, grab_attacks[which][0], 0);
14329 		else
14330 		{
14331 			memset(self->combostep, 0, sizeof(int)*5);
14332 			if(validanim(self,grab_attacks[which][1])) ent_set_anim(self, grab_attacks[which][1], 0);
14333 			else ent_set_anim(self, ANI_ATTACK3, 0);
14334 		}
14335 	}
14336 	else
14337 	{
14338 		memset(self->combostep, 0, sizeof(int)*5);
14339 		if(validanim(self,grab_attacks[0][1])) ent_set_anim(self, grab_attacks[0][1], 0);
14340 		else if(validanim(self,ANI_ATTACK3)) ent_set_anim(self, ANI_ATTACK3, 0);
14341 	}
14342 }
14343 
dovault()14344 void dovault()
14345 {
14346 	int heightvar;
14347 	entity * other = self->link;
14348 	self->takeaction = common_vault;
14349 	self->link->xdir = self->link->zdir = self->xdir = self->zdir = 0;
14350 
14351 	self->attacking = 1;
14352 	self->x = other->x;
14353 
14354 	if(other->animation->height) heightvar = other->animation->height;
14355 	else heightvar = other->modeldata.height;
14356 
14357 	self->base = other->base + heightvar;
14358 	ent_set_anim(self, ANI_VAULT, 0);
14359 }
14360 
common_grab_check()14361 void common_grab_check()
14362 {
14363 	int rnum, which;
14364 	entity * other = self->link;
14365 
14366 	if(other == NULL || (self->modeldata.grabfinish && self->animating && !self->grabwalking)) return;
14367 
14368 	if(self->base != other->base)
14369 	{       // Change this from ->a to ->base
14370 		self->takeaction = NULL;
14371 		ent_unlink(self);
14372 		set_idle(self);
14373 		return;
14374 	}
14375 
14376 	if(!nolost && self->modeldata.weaploss[0] <= 0) dropweapon(1);
14377 
14378 	self->attacking = 0; //for checking
14379 
14380 	rnum = rand32()&31;
14381 
14382 	if(time > self->releasetime)
14383 	{
14384 		if(rnum < 12)
14385 		{
14386 			// Release
14387 			self->takeaction = NULL;
14388 			ent_unlink(self);
14389 			set_idle(self);
14390 			return;
14391 		}
14392 		else self->releasetime = time + (GAME_SPEED/2);
14393 	}
14394 
14395 	if(validanim(self,ANI_THROW) && rnum < 7)
14396 	{
14397 		if(self->modeldata.throwframewait >= 0)
14398 			doprethrow();
14399 		else
14400 			dothrow();
14401 		return;
14402 	}
14403 	//grab finisher
14404 	if(rnum < 4)
14405 	{
14406 		 dograbattack(-1);
14407 		 return;
14408 	}
14409 	which = rnum%5;
14410 	// grab attacks
14411 	if(rnum > 12 && validanim(self,grab_attacks[which][0]))
14412 	{
14413 		dograbattack(which);
14414 		return;
14415 	}
14416 	// Vaulting.
14417 	if(rnum < 8 && validanim(self,ANI_VAULT))
14418 	{
14419 		dovault();
14420 		return;
14421 	}
14422 }
14423 
14424 //grabbing someone
common_grab()14425 void common_grab()
14426 {
14427 	// if(self->link) return;
14428 	if(self->link || (self->modeldata.grabfinish && self->animating && !self->grabwalking)) return;
14429 
14430 	self->takeaction = NULL;
14431 	self->attacking = 0;
14432 	memset(self->combostep, 0, sizeof(int)*5);
14433 	set_idle(self);
14434 }
14435 
14436 // being grabbed
common_grabbed()14437 void common_grabbed()
14438 {
14439 	// Just check if we're still grabbed...
14440 	if(self->link) return;
14441 
14442 	self->stalltime=0;
14443 	self->takeaction = NULL;
14444 	set_idle(self);
14445 }
14446 
14447 // picking up something
common_get()14448 void common_get()
14449 {
14450 	if(self->animating) return;
14451 
14452 	self->getting = 0;
14453 	self->takeaction = NULL;
14454 	set_idle(self);
14455 }
14456 
14457 // A.I. characters do the block
common_block()14458 void common_block()
14459 {
14460 	if(self->animating) return;
14461 
14462 	self->blocking = 0;
14463 	self->takeaction = NULL;
14464 	set_idle(self);
14465 }
14466 
14467 
common_charge()14468 void common_charge()
14469 {
14470 	if(self->animating) return;
14471 
14472 	self->charging = 0;
14473 	self->takeaction = NULL;
14474 	set_idle(self);
14475 }
14476 
14477 
14478 // common code for entities hold an item
drop_item(entity * e)14479 entity* drop_item(entity* e)
14480 {
14481 	s_spawn_entry p;
14482 	entity* item;
14483 	memset(&p, 0, sizeof(s_spawn_entry));
14484 
14485 	p.index = e->item;
14486 	p.itemindex = p.weaponindex = -1;
14487 	strcpy(p.alias, e->itemalias);
14488 	p.a = e->a+0.01; // for check, or an enemy "item" will drop from the sky
14489 	p.health[0] = e->itemhealth;
14490 	p.alpha = e->itemtrans;
14491 	p.colourmap = e->itemmap;
14492 	p.flip = e->direction;
14493 
14494 	item = smartspawn(&p);
14495 
14496 	if(item)
14497 	{
14498 		item->x = e->x;
14499 		item->z = e->z;
14500 		if(item->x < advancex) item->x = advancex + 10;
14501 		else if(item->x > advancex + videomodes.hRes) item->x = advancex + videomodes.hRes - 10;
14502 		if(!(level->scrolldir &(SCROLL_UP|SCROLL_DOWN)))
14503 		{
14504 			if(item->z-item->a < advancey) item->z = advancey + 10;
14505 			else if(item->z-item->a > advancey + videomodes.vRes) item->z = advancey + videomodes.vRes - 10;
14506 		}
14507 		if(e->boss && item->modeldata.type==TYPE_ENEMY) item->boss = 1;
14508 	}
14509 	return item;
14510 }
14511 
14512 //drop the driver, just spawn, dont takedamage
14513 // damage will adjust by the biker
drop_driver(entity * e)14514 entity* drop_driver(entity* e)
14515 {
14516 	int i;
14517 	s_spawn_entry p;
14518 	entity* driver;
14519 	memset(&p, 0, sizeof(s_spawn_entry));
14520 
14521 	if(e->modeldata.rider>=0) p.index = e->modeldata.rider;
14522 	else         return NULL; // should not happen, just in case
14523 	/*p.x = e->x - advancex; p.z = e->z; */p.a = e->a + 10;
14524 	p.itemindex = e->item;
14525 	p.weaponindex = -1;
14526 	strcpy(p.itemalias, e->itemalias);
14527 	strcpy(p.alias, e->name);
14528 	p.itemmap = e->itemmap;
14529 	p.itemtrans = e->itemtrans;
14530 	p.itemhealth = e->itemhealth;
14531 	p.itemplayer_count = e->itemplayer_count;
14532 	//p.colourmap = e->map;
14533 	for(i=0; i<MAX_PLAYERS; i++) p.health[i] = e->modeldata.health;
14534 	p.boss = e->boss;
14535 
14536 	driver = smartspawn(&p);
14537 	if(driver)
14538 	{
14539 		driver->x = e->x;
14540 		driver->z = e->z;
14541 	}
14542 	return driver;
14543 }
14544 
14545 
checkdeath()14546 void checkdeath()
14547 {
14548 	if(self->health>0) return;
14549 	self->dead = 1;
14550 	//be careful, since the opponent can be other types
14551 	if(self->opponent && self->opponent->modeldata.type == TYPE_PLAYER)
14552 	{
14553 		addscore(self->opponent->playerindex, self->modeldata.score);    // Add score to the player
14554 	}
14555 	self->nograb = 1;
14556 	self->idling = 0;
14557 
14558 	if(self->modeldata.diesound >= 0) sound_play_sample(self->modeldata.diesound, 0, savedata.effectvol,savedata.effectvol, 100);
14559 
14560 	// drop item
14561 	if(self->item && count_ents(TYPE_PLAYER) > self->itemplayer_count)
14562     {
14563 		drop_item(self);
14564 	}
14565 
14566 	if(self->boss){
14567 		self->boss = 0;
14568 		--level->bosses;
14569 		if(!level->bosses && self->modeldata.type == TYPE_ENEMY){
14570 			kill_all_enemies();
14571 			level_completed = 1;
14572 		}
14573 	}
14574 }
14575 
checkdamageflip(entity * other,s_attack * attack)14576 void checkdamageflip(entity* other, s_attack* attack)
14577 {
14578 	if(other == NULL || other==self || (!self->drop && (attack->no_pain || self->modeldata.nopain || (self->defense[(short)attack->attack_type].pain && attack->attack_force < self->defense[(short)attack->attack_type].pain)))) return;
14579 
14580 	if(!self->frozen && !self->modeldata.noflip)// && !inair(self))
14581 	{
14582 		if(attack->force_direction == 0)
14583 		{
14584 			if(self->x < other->x) self->direction = 1;
14585 			else if(self->x > other->x) self->direction = 0;
14586 		}
14587 		else if(attack->force_direction == 1)
14588 		{
14589 			self->direction = other->direction;
14590 		}
14591 		else if(attack->force_direction == -1)
14592 		{
14593 			self->direction = !other->direction;
14594 		}
14595 		else if(attack->force_direction == 2)
14596 		{
14597 			self->direction = 1;
14598 		}
14599 		else if(attack->force_direction == -2)
14600 		{
14601 			self->direction = 0;
14602 		}
14603 	}
14604 }
14605 
checkdamageeffects(s_attack * attack)14606 void checkdamageeffects(s_attack* attack)
14607 {
14608 #define _freeze         attack->freeze
14609 #define _maptime        attack->maptime
14610 #define _freezetime     attack->freezetime
14611 #define _remap          attack->forcemap
14612 #define _blast          attack->blast
14613 #define _steal          attack->steal
14614 #define _seal           attack->seal
14615 #define _sealtime       attack->sealtime
14616 #define _dot            attack->dot
14617 #define _dot_index      attack->dot_index
14618 #define _dot_time       attack->dot_time
14619 #define _dot_force      attack->dot_force
14620 #define _dot_rate       attack->dot_rate
14621 #define _staydown0      attack->staydown[0]
14622 #define _staydown1		attack->staydown[1]
14623 
14624 	entity* opp = self->opponent;
14625 
14626 	if(_steal && opp && opp!=self)
14627 	{
14628 		if(self->health >= attack->attack_force) opp->health += attack->attack_force;
14629 		else opp->health += self->health;
14630 		if(opp->health > opp->modeldata.health)
14631 			opp->health = opp->modeldata.health;
14632 	}
14633 	if(_freeze && !self->frozen && !self->owner && !self->modeldata.nomove)
14634 	{    // New freeze attack - If not frozen, freeze entity unless it's a projectile
14635 		self->frozen = 1;
14636 		if(self->freezetime == 0) self->freezetime = time + _freezetime;
14637 		if(_remap == -1 && self->modeldata.maps.frozen != -1) self->colourmap = self->modeldata.colourmap[self->modeldata.maps.frozen-1];    //12/14/2007 Damon Caskey: If opponents frozen map = -1 or only stun, then don't change the color map.
14638 		self->drop = 0;
14639 	}
14640 	else if(self->frozen)
14641 	{
14642 		unfrozen(self);
14643 		self->drop = 1;
14644 	}
14645 
14646 	if(_remap>0 && !_freeze)
14647 	{
14648 		self->maptime = time + _maptime;
14649 		self->colourmap = self->modeldata.colourmap[_remap-1];
14650 	}
14651 
14652 	if(_seal)                                                                       //Sealed: Disable special moves.
14653 	{
14654 		self->sealtime  = time + _sealtime;                                         //Set time to apply seal. No specials for you!
14655 		self->seal      = _seal;                                                    //Set seal. Any animation with energycost > seal is disabled.
14656 	}
14657 
14658 	if(_dot)                                                                        //dot: Damage over time effect.
14659 	{
14660 		self->dot_owner[_dot_index] = self->opponent;                               //dot owner.
14661 		self->dot[_dot_index]       = _dot;                                         //Mode: 1. HP (non lethal), 2. MP, 3. HP (non lethal) & MP, 4. HP, 5. HP & MP.
14662 		self->dot_time[_dot_index]  = time + (_dot_time * GAME_SPEED / 100);        //Gametime dot will expire.
14663 		self->dot_force[_dot_index] = _dot_force;                                   //How much to dot each tick.
14664 		self->dot_rate[_dot_index]  = _dot_rate;                                    //Delay between dot ticks.
14665 		self->dot_atk[_dot_index]   = attack->attack_type;                          //dot attack type.
14666 	}
14667 
14668 
14669 	if(self->modeldata.nodrop) self->drop = 0;                                      // Static enemies/nodrop enemies cannot be knocked down
14670 
14671 	if(inair(self) && !self->frozen && self->modeldata.nodrop<2) self->drop = 1;
14672 
14673 	if(attack->no_pain) self->drop = 0;
14674 
14675 	self->projectile = _blast;
14676 
14677 	if(self->drop)
14678 	{
14679 		self->staydown.rise	= _staydown0;                                            //Staydown: Add to risetime until next rise.
14680 		self->staydown.riseattack   = _staydown1;
14681 	}
14682 
14683 #undef _freeze
14684 #undef _maptime
14685 #undef _freezetime
14686 #undef _remap
14687 #undef _blast
14688 #undef _steal
14689 #undef _seal
14690 #undef _sealtime
14691 #undef _dot
14692 #undef _dot_index
14693 #undef _dot_time
14694 #undef _dot_force
14695 #undef _dot_rate
14696 #undef _staydown0
14697 #undef _staydown1
14698 }
14699 
checkdamagedrop(s_attack * attack)14700 void checkdamagedrop(s_attack* attack)
14701 {
14702 	int attackdrop = attack->attack_drop;
14703 	float fdefense_knockdown = self->defense[(short)attack->attack_type].knockdown;
14704 	if(self->modeldata.animal) self->drop = 1;
14705 	if(self->modeldata.guardpoints.maximum > 0 && self->modeldata.guardpoints.current <= 0) attackdrop = 0; //guardbreak does not knock down.
14706 	if(self->drop || attack->no_pain) return; // just in case, if we already fall, dont check fall again
14707 	// reset count if knockdowntime expired.
14708 	if(self->knockdowntime && self->knockdowntime<time)
14709 		self->knockdowncount = self->modeldata.knockdowncount;
14710 
14711 	self->knockdowncount -= (attackdrop * fdefense_knockdown);
14712 	self->knockdowntime = time + GAME_SPEED;
14713 	self->drop = (self->knockdowncount<0); // knockdowncount < 0 means knocked down
14714 }
14715 
checkmpadd()14716 void checkmpadd()
14717 {
14718 	entity* other = self->opponent;
14719 	if(other == NULL || other == self) return;
14720 
14721 	if(magic_type == 1 )
14722 	{
14723 		other->mp += other->modeldata.mprate;
14724 
14725 		if(other->mp > other->modeldata.mp) other->mp = other->modeldata.mp;
14726 		else if(other->mp < 0) other->mp = 0;
14727 	}
14728 }
14729 
checkhitscore(entity * other,s_attack * attack)14730 void checkhitscore(entity* other, s_attack* attack)
14731 {
14732 	entity* opp = self->opponent;
14733 	if(!opp) return;
14734 	if(opp && opp!=self && opp->modeldata.type == TYPE_PLAYER)
14735 	{    // Added obstacle so explosions can hurt enemies
14736 		addscore(opp->playerindex, attack->attack_force*self->modeldata.multiple);    // New multiple variable
14737 		control_rumble(opp->playerindex, attack->attack_force*2);
14738 	}
14739 	// Don't animate or fall if hurt by self, since
14740 	// it means self fell to the ground already. :)
14741 	// Add throw score to the player
14742 	else if(other==self && self->damage_on_landing > 0) addscore(opp->playerindex, attack->attack_force);
14743 }
14744 
checkdamage(entity * other,s_attack * attack)14745 void checkdamage(entity* other, s_attack* attack)
14746 {
14747 	int force = attack->attack_force;
14748 	int type = attack->attack_type;
14749 	if(self->modeldata.guardpoints.maximum > 0 && self->modeldata.guardpoints.current <= 0) force = 0; //guardbreak does not deal damage.
14750 	if(!(self->damage_on_landing && self == other) && !other->projectile && type >= 0 && type<max_attack_types)
14751 	{
14752 		force = (int)(force * other->offense_factors[type]);
14753 		force = (int)(force * self->defense[type].factor);
14754 	}
14755 
14756 	self->health -= force; //Apply damage.
14757 
14758 	if (self->health > self->modeldata.health) self->health = self->modeldata.health; //Cap negative damage to max health.
14759 
14760 	if(attack->no_kill && self->health<=0) self->health = 1;
14761 
14762 	execute_takedamage_script(self, other, force, attack->attack_drop, type, attack->no_block, attack->guardcost, attack->jugglecost, attack->pause_add);                       //Execute the take damage script.
14763 
14764 	if (self->health <= 0)                                      //Health at 0?
14765 	{
14766 		if(!(self->a < PIT_DEPTH || self->lifespancountdown<0)) //Not a pit death or countdown?
14767 		{
14768 			if (self->invincible == 2)                          //Invincible type 2?
14769 			{
14770 				self->health = 1;                               //Stop at 1hp.
14771 			}
14772 			else if(self->invincible == 3)                      //Invincible type 3?
14773 			{
14774 				self->health = self->modeldata.health;          //Reset to max health.
14775 			}
14776 		}
14777 		execute_ondeath_script(self, other, force, attack->attack_drop, type, attack->no_block, attack->guardcost, attack->jugglecost, attack->pause_add);   //Execute ondeath script.
14778 	}
14779 }
14780 
checkgrab(entity * other,s_attack * attack)14781 int checkgrab(entity *other, s_attack* attack)
14782 {
14783 	//if(attack->no_pain) return  0; //no effect, let modders to deside, don't bother check it here
14784 	if(self!=other && attack->grab && cangrab(other, self))
14785 	{
14786 		if(adjust_grabposition(other, self, attack->grab_distance, attack->grab))
14787 		{
14788 			ents_link(other, self);
14789 			self->a = other->a;
14790 		}
14791 		else return 0;
14792 	}
14793 	return 1;
14794 }
14795 
arrow_takedamage(entity * other,s_attack * attack)14796 int arrow_takedamage(entity *other, s_attack* attack)
14797 {
14798 	self->modeldata.no_adjust_base = 0;
14799 	self->modeldata.subject_to_wall = self->modeldata.subject_to_platform = self->modeldata.subject_to_hole = self->modeldata.subject_to_gravity = 1;
14800 	if( common_takedamage(other, attack) && self->dead)
14801 	{
14802 			  return 1;
14803 	}
14804 	return 0;
14805 }
14806 
common_takedamage(entity * other,s_attack * attack)14807 int common_takedamage(entity *other, s_attack* attack)
14808 {
14809 	if(self->dead) return 0;
14810 	if(self->toexplode == 2) return 0;
14811 	// fake 'grab', if failed, return as the attack hit nothing
14812 	if(!checkgrab(other, attack)) return 0; // try to grab but failed, so return 0 means attack missed
14813 
14814 	// set pain_time so it wont get hit too often
14815 	// 2011/11/24 UT: move this to do_attack to merge with block code
14816 	//self->pain_time = time + (attack->pain_time?attack->pain_time:(GAME_SPEED / 5));
14817 	// set oppoent
14818 	if(self!=other) set_opponent(self, other);
14819 	// adjust type
14820 	if(attack->attack_type >= 0 && attack->attack_type<max_attack_types) self->damagetype = attack->attack_type;
14821 	else self->damagetype = ATK_NORMAL;
14822 	// pre-check drop
14823 	checkdamagedrop(attack);
14824 	// Drop Weapon due to being hit.
14825 	if(self->modeldata.weaploss[0] <= 0) dropweapon(1);
14826 	// check effects, e.g., frozen, blast, steal
14827 	if(!(self->modeldata.guardpoints.maximum > 0 && self->modeldata.guardpoints.current <= 0)) checkdamageeffects(attack);
14828 	// check flip direction
14829 	checkdamageflip(other, attack);
14830 	// mprate can also control the MP recovered per hit.
14831 	checkmpadd();
14832 	//damage score
14833 	checkhitscore(other, attack);
14834 	// check damage, cost hp.
14835 	checkdamage(other, attack);
14836 	// is it dead now?
14837 	checkdeath();
14838 
14839 	if(self->modeldata.type == TYPE_PLAYER) control_rumble(self->playerindex, attack->attack_force * 3);
14840 	if(self->a<=PIT_DEPTH && self->dead)
14841 	{
14842 		if(self->modeldata.type == TYPE_PLAYER) player_die();
14843 		else kill(self);
14844 		return 1;
14845 	}
14846 	// fall to the ground so dont fall again
14847 	if(self->damage_on_landing)
14848 	{
14849 		self->damage_on_landing = 0;
14850 		return 1;
14851 	}
14852 	// unlink due to being hit
14853 	if((self->opponent && self->opponent->grabbing != self)||
14854 	   self->dead || self->frozen || self->drop)
14855 	{
14856 		ent_unlink(self);
14857 	}
14858 	// Enemies can now use SPECIAL2 to escape cheap attack strings!
14859 	if(self->modeldata.escapehits)
14860 	{
14861 		if(self->drop) self->escapecount = 0;
14862 		else self->escapecount++;
14863 	}
14864 	// New pain, fall, and death animations. Also, the nopain flag.
14865 	if(self->drop || self->health <= 0)
14866 	{
14867 		self->takeaction = common_fall;
14868 		// Drop Weapon due to death.
14869 		if(self->modeldata.weaploss[0] <= 2 && self->health <= 0) dropweapon(1);
14870 		else if(self->modeldata.weaploss[0] <= 1) dropweapon(1);
14871 
14872 		if(self->health <= 0 && self->modeldata.falldie == 1)
14873 		{
14874 			self->xdir = self->zdir = self->tossv = 0;
14875 			set_death(self, self->damagetype, 0);
14876 		}
14877 		else
14878 		{
14879 			self->xdir = attack->dropv[1];
14880 			self->zdir = attack->dropv[2];
14881 			if(self->direction) self->xdir = -self->xdir;
14882 			toss(self, attack->dropv[0]);
14883 			self->damage_on_landing = attack->damage_on_landing;
14884 			self->knockdowncount = self->modeldata.knockdowncount; // reset the knockdowncount
14885 			self->knockdowntime = 0;
14886 
14887 			// Now if no fall/die animations exist, entity simply disapears
14888 			//set_fall(entity *iFall, int type, int reset, entity* other, int force, int drop)
14889 			if(!set_fall(self, self->damagetype, 1, other, attack->attack_force, attack->attack_drop, attack->no_block, attack->guardcost, attack->jugglecost, attack->pause_add))
14890 			{
14891 				if(self->modeldata.type == TYPE_PLAYER) player_die();
14892 				else kill(self);
14893 				return 1;
14894 			}
14895 		}
14896 		if(self->modeldata.type == TYPE_PLAYER) control_rumble(self->playerindex, attack->attack_force * 3);
14897 	}
14898 	else if(attack->grab && !attack->no_pain)
14899 	{
14900 		self->takeaction = common_pain;
14901 		other->takeaction = common_grabattack;
14902 		other->stalltime = time + GRAB_STALL;
14903 		self->releasetime = time + (GAME_SPEED/2);
14904 		set_pain(self, self->damagetype, 0);
14905 	}
14906 	// Don't change to pain animation if frozen
14907 	else if(!self->frozen && !self->modeldata.nopain && !attack->no_pain && !(self->defense[(short)attack->attack_type].pain && attack->attack_force < self->defense[(short)attack->attack_type].pain))
14908 	{
14909 		self->takeaction = common_pain;
14910 		set_pain(self, self->damagetype, 1);
14911 	}
14912 	return 1;
14913 }
14914 
14915 // A.I. try upper cut
common_try_upper(entity * target)14916 int common_try_upper(entity* target)
14917 {
14918 	if(!validanim(self,ANI_UPPER)) return 0;
14919 
14920 
14921 	if(!target) target = normal_find_target(ANI_UPPER,0);
14922 
14923 	// Target jumping? Try uppercut!
14924 	if(target && target->jumping )
14925 	{
14926 		self->takeaction = common_attack_proc;
14927 		set_attacking(self);
14928 		self->zdir = self->xdir = 0;
14929 		// Don't waste any time!
14930 		ent_set_anim(self, ANI_UPPER, 0);
14931 		return 1;
14932 	}
14933 	return 0;
14934 }
14935 
common_try_runattack(entity * target)14936 int common_try_runattack(entity* target)
14937 {
14938 	if(!self->running || !validanim(self,ANI_RUNATTACK)) return 0;
14939 
14940 
14941 	if(!target) target = normal_find_target(ANI_RUNATTACK,0);
14942 
14943 	if(target)
14944 	{
14945 		if(!target->animation->vulnerable[target->animpos] && (target->drop || target->attacking))
14946 			return 0;
14947 		self->takeaction = common_attack_proc;
14948 		self->zdir = self->xdir = 0;
14949 		set_attacking(self);
14950 		ent_set_anim(self, ANI_RUNATTACK, 0);
14951 		return 1;
14952 	}
14953 	return 0;
14954 }
14955 
common_try_block(entity * target)14956 int common_try_block(entity* target)
14957 {
14958 	if(self->modeldata.nopassiveblock==0 ||
14959 	   (rand32()&self->modeldata.blockodds) != 1 ||
14960 	   !validanim(self,ANI_BLOCK))
14961 	   return 0;
14962 
14963 	if(!target) target = block_find_target(ANI_BLOCK,0); // temporary fix, other wise ranges never work
14964 
14965 	// no passive block, so block by himself :)
14966 	if(target && target->attacking)
14967 	{
14968 		self->takeaction = common_block;
14969 		set_blocking(self);
14970 		self->zdir = self->xdir = 0;
14971 		ent_set_anim(self, ANI_BLOCK, 0);
14972 		return 1;
14973 	}
14974 	return 0;
14975 }
14976 
14977 // this logic could be used for multiple times, so make a function
14978 // pick a random attack or return the first attacks if testonly is set
14979 // when testonly is set, the function will not check special attacks (upper, jumpattack)
14980 // if target is NULL, ranges are not checked
pick_random_attack(entity * target,int testonly)14981 int pick_random_attack(entity* target, int testonly){
14982 	int found = 0, i, j;
14983 
14984 	for(i=0; i<max_attacks; i++) // TODO: recheck range for attacks chains
14985 	{
14986 		if(validanim(self,animattacks[i]) &&
14987 			(!target || check_range(self, target, animattacks[i])))
14988 		{
14989 			for(j=((5-i)>=0?(5-i):0)*3; j>=0; j--)
14990 				atkchoices[found++] = animattacks[i];
14991 		}
14992 	}
14993 	for(i=0; i<max_freespecials; i++)
14994 	{
14995 		if(validanim(self,animspecials[i]) &&
14996 		   (check_energy(1, animspecials[i]) ||
14997 			check_energy(0, animspecials[i])) &&
14998 		    (!target || check_range(self, target, animspecials[i])))
14999 		{
15000 			atkchoices[found++] = animspecials[i];
15001 		}
15002 	}
15003 	if( validanim(self,ANI_THROWATTACK) &&
15004 		self->weapent && self->weapent->modeldata.subtype == SUBTYPE_PROJECTILE &&
15005 		(!target || check_range(self, target, ANI_THROWATTACK) ))
15006 	{
15007 		atkchoices[found++] = ANI_THROWATTACK;
15008 	}
15009 
15010 	if(testonly){
15011 		if(found) return atkchoices[(rand32()&0xffff)%found];
15012 		return -1;
15013 	}
15014 
15015 	if( validanim(self,ANI_JUMPATTACK) &&
15016 		(!target || check_range(self, target, ANI_JUMPATTACK)) )
15017 	{
15018 		if(testonly) return ANI_JUMPATTACK;
15019 		atkchoices[found++] = ANI_JUMPATTACK;
15020 	}
15021 	if( validanim(self,ANI_UPPER) &&
15022 		(!target || check_range(self, target, ANI_UPPER)) )
15023 	{
15024 		if(testonly) return ANI_UPPER;
15025 		atkchoices[found++] = ANI_UPPER;
15026 	}
15027 
15028 	if(found){
15029 		return atkchoices[(rand32()&0xffff)%found];
15030 	}
15031 
15032 	return -1;
15033 }
15034 
15035 
15036 // code to lower the chance of attacks, may change while testing old mods
15037 // min - min attack chance
15038 // max - max attack chance
check_attack_chance(entity * target,float min,float max)15039 int check_attack_chance(entity* target, float min, float max){
15040 
15041 	float chance, chance1, chance2;//, aggfix;
15042 
15043 	if(self->modeldata.aiattack&AIATTACK1_ALWAYS) return 1;
15044 
15045 	chance1 = MIN(1.0f,(diff(self->x, self->destx)+diff(self->z, self->destz))/(videomodes.hRes+videomodes.vRes)*move_noatk_factor);
15046 	chance2 = MIN(1.0f, (count_ents(self->modeldata.type)-1)*group_noatk_factor);
15047 
15048 	chance = (1.0f-chance1)*(1.0f-chance2);
15049 
15050 	if(chance>max) chance = max;
15051 	else if(chance<min) chance = min;
15052 
15053 	chance *= (1.0-self->modeldata.attackthrottle);
15054 
15055 	if(self->x<screenx-10 || self->x>screenx+videomodes.hRes+10){
15056 		chance *= (1.0-offscreen_noatk_factor);
15057 	}
15058 
15059 	return (randf(1)<=chance);
15060 }
15061 
15062 //make a function, mostly for debug purpose
15063 //give it a chance to reset current noattack timer
recheck_nextattack(entity * target)15064 u32 recheck_nextattack(entity* target)
15065 {
15066 	if(target->blocking) self->nextattack = 0;
15067 	else if(target->attacking && self->nextattack>4) self->nextattack-=4;
15068 	else if(target->jumping && self->nextattack>16) self->nextattack-=16;
15069 
15070 	return self->nextattack;
15071 }
15072 
common_try_normalattack(entity * target)15073 int common_try_normalattack(entity* target)
15074 {
15075 	target = normal_find_target(-1, 0);
15076 
15077 	if(!target) return 0;
15078 
15079 	recheck_nextattack(target);
15080 
15081 	if(recheck_nextattack(target)>time) return 0;
15082 
15083 	if(!target->animation->vulnerable[target->animpos] && (target->drop || target->attacking || target->takeaction==common_rise))
15084 		return 0;
15085 
15086 	if(pick_random_attack(target, 1)>=0) {
15087 		if(self->combostep[0] && self->combotime>time) self->stalltime = time+1;
15088 		else
15089 		{
15090 			if(!check_attack_chance(target, 1.0f-min_noatk_chance, 1.0f-min_noatk_chance)) {
15091 				self->nextattack = time + randf(self->modeldata.attackthrottletime);
15092 				return 0;
15093 			} else
15094 				self->stalltime = time + (int)randf((float)MAX(1,GAME_SPEED*3/4 - self->modeldata.aggression));
15095 		}
15096 		self->takeaction = normal_prepare;
15097 		self->zdir = self->xdir = 0;
15098 		set_idle(self);
15099 		self->idling = 0; // not really idle, in fact it is thinking
15100 		self->attacking = -1; // pre-attack, for AI-block check
15101 		return 1;
15102 	}
15103 
15104 	return 0;
15105 }
15106 
common_try_jumpattack(entity * target)15107 int common_try_jumpattack(entity* target)
15108 {
15109 	entity* dust;
15110 	int rnum, ani = 0;
15111 	if((validanim(self,ANI_JUMPATTACK) || validanim(self,ANI_JUMPATTACK2)))
15112 	{
15113 		if(!validanim(self,ANI_JUMPATTACK)) rnum = 1;
15114 		else if(validanim(self,ANI_JUMPATTACK2) && (rand32()&1)) rnum = 1;
15115 		else rnum = 0;
15116 
15117 		if(rnum==0 &&
15118 			// do a jumpattack
15119 			(target || (target = normal_find_target(ANI_JUMPATTACK,0))) )
15120 		{
15121 			if(recheck_nextattack(target)>time) return 0;
15122 
15123 			if(!target->animation->vulnerable[target->animpos] && (target->drop || target->attacking))
15124 				rnum = -1;
15125 			else{
15126 				if(!check_attack_chance(target,0.05f,0.4f)) {
15127 					self->nextattack = time + randf(self->modeldata.attackthrottletime);
15128 					return 0;
15129 				}
15130 				//ent_set_anim(self, ANI_JUMPATTACK, 0);
15131 				ani = ANI_JUMPATTACK;
15132 				if(self->direction) self->xdir = (float)1.3;
15133 				else self->xdir = (float)-1.3;
15134 				self->zdir = 0;
15135 			}
15136 		}
15137 		else if(rnum==1 &&
15138 			// do a jumpattack2
15139 			(target || (target = normal_find_target(ANI_JUMPATTACK2,0))) )
15140 		{
15141 			if(recheck_nextattack(target)>time) return 0;
15142 
15143 			if(!target->animation->vulnerable[target->animpos] && (target->drop || target->attacking))
15144 				rnum = -1;
15145 			else{
15146 				if(!check_attack_chance(target,0.05f,0.5f)) {
15147 					self->nextattack = time + randf(self->modeldata.attackthrottletime);
15148 					return 0;
15149 				}
15150 				//ent_set_anim(self, ANI_JUMPATTACK2, 0);
15151 				ani = ANI_JUMPATTACK2;
15152 				self->xdir = self->zdir = 0;
15153 			}
15154 		} else {
15155 			rnum = -1;
15156 		}
15157 
15158 		if(rnum >= 0)
15159 		{
15160 
15161 			self->takeaction = common_jump;
15162 			set_attacking(self);
15163 			self->jumping = 1;
15164 			toss(self, self->modeldata.jumpheight);
15165 
15166 			if(self->modeldata.dust[2]>=0)
15167 			{
15168 				dust = spawn(self->x, self->z, self->a, self->direction, NULL, self->modeldata.dust[2], NULL);
15169 				if(dust){
15170 					dust->base = self->a;
15171 					dust->autokill = 2;
15172 					execute_onspawn_script(dust);
15173 				}
15174 			}
15175 
15176 			ent_set_anim(self, ani, 0);
15177 
15178 			return 1;
15179 		}
15180 	}
15181 	return 0;
15182 }
15183 
common_try_grab(entity * other)15184 int common_try_grab(entity* other)
15185 {
15186 	int trygrab(entity* t);
15187 	if( (rand()&7)==0 &&
15188 		(validanim(self,ANI_THROW) ||
15189 		 validanim(self,ANI_GRAB)) && self->idling &&
15190 		(other || (other = find_ent_here(self,self->x, self->z, self->modeldata.hostile, NULL)))&&
15191 		trygrab(other))
15192 	{
15193 		return 1;
15194 	}
15195 	return 0;
15196 }
15197 
15198 // Normal attack style
15199 // Used by root A.I., what to do if a target is found.
15200 // return 0 if no action is token
15201 // return 1 if an action is token
normal_attack()15202 int normal_attack()
15203 {
15204 	//int rnum;
15205 
15206 	//rnum = rand32()&7;
15207 	if( common_try_grab(NULL) ||
15208 		common_try_upper(NULL) ||
15209 		common_try_block(NULL) ||
15210 		common_try_runattack(NULL) ||
15211 	   //(rnum < 2 && common_try_freespecial(NULL)) ||
15212 		common_try_normalattack(NULL) ||
15213 		common_try_jumpattack(NULL) )
15214 	{
15215 		self->running = 0;
15216 		return 1;
15217 	}
15218 	return 0;// nothing to do? so go to next think step
15219 }
15220 
15221 // A.I. characters do a throw
common_throw()15222 void common_throw()
15223 {
15224 	if(self->animating) return; // just play the throw animation
15225 
15226 	// we have done the throw, return to A.I. root
15227 	self->takeaction = NULL;
15228 
15229 	set_idle(self);
15230 }
15231 
15232 // toss the grabbed one
dothrow()15233 void dothrow()
15234 {
15235 	entity* other;
15236 	self->xdir = self->zdir = 0;
15237 	other = self->link;
15238 	if(other == NULL) //change back to idle, or we will get stuck here
15239 	{
15240 		self->takeaction = NULL;// A.I. root again
15241 		set_idle(self);
15242 		return;
15243 	}
15244 
15245 	if(other->modeldata.throwheight) toss(other, other->modeldata.throwheight);
15246 	else toss(other, other->modeldata.jumpheight);
15247 
15248 	other->direction = self->direction;
15249 	other->projectile = 2;
15250 	other->xdir = (other->direction)?(-other->modeldata.throwdist):(other->modeldata.throwdist);
15251 
15252 	if(autoland == 1 && validanim(other,ANI_LAND)) other->damage_on_landing = -1;
15253 	else other->damage_on_landing = self->modeldata.throwdamage;
15254 
15255 	ent_unlink(other);
15256 
15257 	other->takeaction = common_fall;
15258 	self->takeaction = common_throw;
15259 	set_fall(other, ATK_NORMAL, 0, self, 0, 0, 0, 0, 0, 0);
15260 	ent_set_anim(self, ANI_THROW, 0);
15261 }
15262 
15263 
15264 // Waiting until throw frame reached
common_throw_wait()15265 void common_throw_wait()
15266 {
15267 	if(!self->link)
15268 	{
15269 		self->takeaction = NULL;// A.I. root again
15270 		set_idle(self);
15271 		return;
15272 	}
15273 
15274 	self->releasetime += THINK_SPEED; //extend release time
15275 
15276 	if(self->animpos != self->modeldata.throwframewait) return;
15277 
15278 	dothrow();
15279 }
15280 
15281 
common_prethrow()15282 void common_prethrow()
15283 {
15284 	self->running = 0;    // Quits running if grabbed by opponent
15285 
15286 	// Just check if we're still grabbed...
15287 	if(self->link) return;
15288 
15289 	self->takeaction = NULL;// A.I. root again
15290 
15291 	set_idle(self);
15292 }
15293 
15294 // warp to its parent entity, just like skeletons in Diablo 2
npc_warp()15295 void npc_warp()
15296 {
15297 	if(!self->parent) return;
15298 	self->z = self->parent->z;
15299 	self->x = self->parent->x;
15300 	self->a = self->parent->a;
15301 	self->xdir = self->zdir = 0;
15302 	self->base = self->parent->base;
15303 	self->tossv = 0;
15304 
15305 	if(validanim(self,ANI_RESPAWN)) {
15306 		self->takeaction = common_spawn;
15307 		ent_set_anim(self, ANI_RESPAWN, 0);
15308 	} else if(validanim(self,ANI_SPAWN)) {
15309 		self->takeaction = common_spawn;
15310 		ent_set_anim(self, ANI_SPAWN, 0);
15311 	}
15312 }
15313 
adjust_grabposition(entity * ent,entity * other,float dist,int grabin)15314 int adjust_grabposition(entity* ent, entity* other, float dist, int grabin)
15315 {
15316 	float x1, z1, x2, z2, x;
15317 
15318 	if(ent->a!=other->a) return 0;
15319 	if(ent->base!=other->base) return 0;
15320 
15321 	if(grabin==1)
15322 	{
15323 		x1 = ent->x;
15324 		z1 = z2 = ent->z;
15325 		x2 = ent->x + ((other->x>ent->x)?dist:-dist);
15326 	}
15327 	else
15328 	{
15329 		x = (ent->x + other->x)/2;
15330 		x1 = x + ((ent->x>=other->x)?(dist/2):(-dist/2));
15331 		x2 = x + ((other->x>ent->x)?(dist/2):(-dist/2));
15332 		z1 = z2 = (ent->z + other->z)/2;
15333 	}
15334 
15335 	if(0>=testmove(ent, ent->x, ent->z, x1, z1) || 0>=testmove(other, other->x, other->z, x2, z2))
15336 		return 0;
15337 
15338 	ent->x = x1; ent->z = z1;
15339 	other->x = x2; other->z = z2;
15340 	//other->a = ent->a;
15341 	//other->base = ent->base;
15342 	return 1;
15343 }
15344 
trygrab(entity * other)15345 int trygrab(entity* other)
15346 {
15347 	if( cangrab(self, other) &&	adjust_grabposition(self, other, self->modeldata.grabdistance, 0))
15348 	{
15349 		if(self->model->grabflip&1) self->direction = (self->x < other->x);
15350 
15351 		set_opponent(other, self);
15352 		ents_link(self, other);
15353 		other->attacking = 0;
15354 		self->idling = 0;
15355 		self->running = 0;
15356 
15357 		self->xdir = self->zdir =
15358 		other->xdir = other->zdir = 0;
15359 		if(validanim(self,ANI_GRAB))
15360 		{
15361 			if(self->model->grabflip&2) other->direction = !self->direction;
15362 			self->attacking = 0;
15363 			memset(self->combostep, 0, 5*sizeof(int));
15364 			other->stalltime = time + GRAB_STALL;
15365 			self->releasetime = time + (GAME_SPEED/2);
15366 			other->takeaction = common_grabbed;
15367 			self->takeaction = common_grab;
15368 			ent_set_anim(self, ANI_GRAB, 0);
15369 			set_pain(other, -1, 0); //set grabbed animation
15370 		}
15371 		// use original throw code if throwframewait not present, kbandressen 10/20/06
15372 		else if(self->modeldata.throwframewait == -1)
15373 			dothrow();
15374 		// otherwise enemy_throw_wait will be used, kbandressen 10/20/06
15375 		else
15376 		{
15377 			if(self->model->grabflip&2) other->direction = !self->direction;
15378 
15379 			other->takeaction = common_prethrow;
15380 			self->takeaction = common_throw_wait;
15381 			ent_set_anim(self, ANI_THROW, 0);
15382 			set_pain(other, -1, 0); // set grabbed animation
15383 		}
15384 		return 1;
15385 	}
15386 	return 0;
15387 }
15388 
15389 
common_trymove(float xdir,float zdir)15390 int common_trymove(float xdir, float zdir)
15391 {
15392 	entity *other = NULL;
15393 	int wall, heightvar;
15394 	float x, z, oxdir, ozdir;
15395 
15396 	if(!xdir && !zdir) return 0;
15397 
15398 	oxdir = xdir; ozdir = zdir;
15399 	/*
15400 	// entity is grabbed by other
15401 	if(self->link && self->link->grabbing==self && self->link->grabwalking)
15402 	{
15403 		return 1; // just return so we don't have to check twice
15404 	}*/
15405 
15406 	x = self->x + xdir;  z = self->z + zdir;
15407 	// -----------bounds checking---------------
15408 	// Subjec to Z and out of bounds? Return to level!
15409 	if (self->modeldata.subject_to_minz>0)
15410 	{
15411 		if(zdir && z < PLAYER_MIN_Z)
15412 		{
15413 			zdir = PLAYER_MIN_Z - self->z;
15414 			execute_onblockz_script(self);
15415 		}
15416 	}
15417 
15418 	if (self->modeldata.subject_to_maxz>0)
15419 	{
15420 		if(zdir && z > PLAYER_MAX_Z)
15421 		{
15422 			zdir = PLAYER_MAX_Z - self->z;
15423 			execute_onblockz_script(self);
15424 		}
15425 	}
15426 
15427 	// End of level is blocked?
15428 	if(level->exit_blocked)
15429 	{
15430 		if(x > level->width-30-(PLAYER_MAX_Z-z))
15431 		{
15432 			xdir = level->width-30-(PLAYER_MAX_Z-z) - self->x;
15433 		}
15434 	}
15435 	// screen checking
15436 	if(self->modeldata.subject_to_screen>0)
15437 	{
15438 		if(x < advancex+10)
15439 		{
15440 			xdir = advancex+10 - self->x;
15441 			execute_onblocks_script(self);  //Screen block event.
15442 		}
15443 		else if(x > advancex+(videomodes.hRes-10))
15444 		{
15445 			xdir = advancex+(videomodes.hRes-10) - self->x;
15446 			execute_onblocks_script(self);  //Screen block event.
15447 		}
15448 	}
15449 
15450 	if(!xdir && !zdir) return 0;
15451 	x = self->x + xdir;  z = self->z + zdir;
15452 
15453 	//-----------end of bounds checking-----------
15454 
15455 	//-------------hole checking ---------------------
15456 	// Don't walk into a hole or walk off platforms into holes
15457 	if( self->modeldata.type!=TYPE_PLAYER && self->idling &&
15458 		(!self->animation->seta||self->animation->seta[self->animpos]<0) &&
15459 		self->modeldata.subject_to_hole>0 && !inair(self) &&
15460 		!(self->modeldata.aimove&AIMOVE2_IGNOREHOLES))
15461 	{
15462 
15463 		if(zdir && checkhole(self->x, z) && checkwall(self->x, z)<0 && (((other = check_platform(self->x, z, self)) &&  self->base < other->a + other->animation->platform[other->animpos][7]) || other == NULL))
15464 		{
15465 			zdir = 0;
15466 		}
15467 		if(xdir && checkhole(x, self->z) && checkwall(x, self->z)<0 && (((other = check_platform(x, self->z, self)) &&  self->base < other->a + other->animation->platform[other->animpos][7]) || other == NULL))
15468 		{
15469 			xdir = 0;
15470 		}
15471 	}
15472 
15473 	if(!xdir && !zdir) return 0;
15474 	x = self->x + xdir;  z = self->z + zdir;
15475 	//-----------end of hole checking---------------
15476 
15477 	//--------------obstacle checking ------------------
15478 	if(self->modeldata.subject_to_obstacle>0 /*&& !inair(self)*/)
15479 	{
15480 		if((other = find_ent_here(self, x, self->z, (TYPE_OBSTACLE | TYPE_TRAP), NULL)) &&
15481 		   (xdir>0 ? other->x > self->x: other->x < self->x) &&
15482 		   (!other->animation->platform||!other->animation->platform[other->animpos][7]))
15483 			{
15484 				xdir    = 0;
15485 				execute_onblocko_script(self, other);
15486 			}
15487 		if((other = find_ent_here(self, self->x, z, (TYPE_OBSTACLE | TYPE_TRAP), NULL)) &&
15488 		   (zdir>0 ? other->z > self->z: other->z < self->z) &&
15489 		   (!other->animation->platform||!other->animation->platform[other->animpos][7]))
15490 			{
15491 				zdir    = 0;
15492 				execute_onblocko_script(self, other);
15493 			}
15494 	}
15495 
15496 	if(!xdir && !zdir) return 0;
15497 	x = self->x + xdir*2;  z = self->z + zdir*2;
15498 
15499 	//-----------end of obstacle checking--------------
15500 
15501 	// ---------------- platform checking----------------
15502 
15503 	if(self->animation->height) heightvar = self->animation->height;
15504 	else heightvar = self->modeldata.height;
15505 
15506 	// Check for obstacles with platform code and adjust base accordingly
15507 	if(self->modeldata.subject_to_platform>0 && (other = check_platform_between(x, z, self->a, self->a+heightvar, self)) )
15508 	{
15509 		if(xdir>0 ? other->x>self->x : other->x<self->x) {xdir = 0; }
15510 		if(zdir>0 ? other->z>self->z : other->z<self->z) {zdir = 0; }
15511 	}
15512 
15513 	if(!xdir && !zdir) return 0;
15514 	x = self->x + xdir;  z = self->z + zdir;
15515 
15516 	//-----------end of platform checking------------------
15517 
15518 	// ------------------ wall checking ---------------------
15519 	if(self->modeldata.subject_to_wall){
15520 
15521 		if((wall = checkwall(x, self->z))>=0 && level->walls[wall][7]>self->a)
15522 		{
15523 			if(xdir > 0.5){ xdir = 0.5; }
15524 			else if(xdir < -0.5){ xdir = -0.5; }
15525 			if((wall = checkwall(self->x + xdir, self->z))>=0 && level->walls[wall][7]>self->a){
15526 				xdir = 0;
15527 				execute_onblockw_script(self,1,(double)level->walls[wall][7]);
15528 			}
15529 		}
15530 		if((wall = checkwall(self->x, z))>=0 && level->walls[wall][7]>self->a)
15531 		{
15532 			if(zdir > 0.5){ zdir = 0.5; }
15533 			else if(zdir < -0.5){ zdir = -0.5; }
15534 			if((wall = checkwall(self->x, self->z + zdir))>=0 && level->walls[wall][7]>self->a){
15535 				zdir = 0;
15536 				execute_onblockw_script(self,2,(double)level->walls[wall][7]);
15537 			}
15538 		}
15539 	}
15540 
15541 
15542 	if(!xdir && !zdir) return 0;
15543 	x = self->x + xdir;  z = self->z + zdir;
15544 	//----------------end of wall checking--------------
15545 
15546 	//------------------ grab/throw checking------------------
15547 	if(self->modeldata.type==TYPE_PLAYER &&
15548 		(rand()&7)==0 &&
15549 		(validanim(self,ANI_THROW) ||
15550 		 validanim(self,ANI_GRAB)) && self->idling &&
15551 		(other = find_ent_here(self, self->x, self->z, self->modeldata.hostile, NULL)))
15552 	{
15553 		if(trygrab(other)) return 0;
15554 	}
15555 	// ---------------  end of grab/throw checking ------------------------
15556 
15557 	// do move and return
15558 	self->x += xdir;
15559 	self->z += zdir;
15560 
15561 	if(xdir)    execute_onmovex_script(self);   //X move event.
15562 	if(zdir)    execute_onmovez_script(self);   //Z move event.
15563 	return 2-(xdir==oxdir && zdir ==ozdir);     // return 2 for some checks
15564 }
15565 
15566 // enemies run off after attack
common_runoff()15567 void common_runoff()
15568 {
15569 	entity *target = normal_find_target(-1,0);
15570 
15571 	if(target == NULL) { //sealth checking
15572 		self->zdir = self->xdir = 0;
15573 		self->takeaction = NULL; // OK, back to A.I. root
15574 		set_idle(self);
15575 		return;
15576 	}
15577 
15578 	if(!self->modeldata.noflip) self->direction = (self->x < target->x);
15579 	if(self->direction) self->xdir = -self->modeldata.speed/2;
15580 	else self->xdir = self->modeldata.speed/2;
15581 
15582 	self->zdir = 0;
15583 
15584 	if(time > self->stalltime) self->takeaction = NULL; // OK, back to A.I. root
15585 
15586 	adjust_walk_animation(target);
15587 }
15588 
15589 
common_stuck_underneath()15590 void common_stuck_underneath()
15591 {
15592 	if(!check_platform_between(self->x, self->z, self->a, self->a+self->modeldata.height, self) )
15593 	{
15594 		self->takeaction = NULL;
15595 		set_idle(self);
15596 		return;
15597 	}
15598 	if(player[self->playerindex].keys & FLAG_MOVELEFT)
15599 	{
15600 		self->direction = 0;
15601 	}
15602 	else if(player[self->playerindex].keys & FLAG_MOVERIGHT)
15603 	{
15604 		self->direction = 1;
15605 	}
15606 	if(player[self->playerindex].playkeys & FLAG_ATTACK && validanim(self,ANI_DUCKATTACK))
15607 	{
15608 		player[self->playerindex].playkeys -= FLAG_ATTACK;
15609 		self->takeaction = common_attack_proc;
15610 		set_attacking(self);
15611 		self->xdir = self->zdir = 0;
15612 		self->combostep[0] = 0;
15613 		self->running = 0;
15614 		ent_set_anim(self, ANI_DUCKATTACK, 0);
15615 		return;
15616 	}
15617 	if((player[self->playerindex].keys & FLAG_MOVEDOWN) && (player[self->playerindex].playkeys & FLAG_JUMP) && validanim(self,ANI_SLIDE))
15618 	{
15619 		player[self->playerindex].playkeys -= FLAG_JUMP;
15620 		self->takeaction = common_attack_proc;
15621 		set_attacking(self);
15622 		self->xdir = self->zdir = 0;
15623 		self->combostep[0] = 0;
15624 		self->running = 0;
15625 		ent_set_anim(self, ANI_SLIDE, 0);
15626 		return;
15627 	}
15628 }
15629 
15630 
15631 // finish attacking, do something
common_attack_finish()15632 void common_attack_finish()
15633 {
15634 	entity *target;
15635 	int stall;
15636 
15637 	self->xdir = self->zdir = 0;
15638 
15639 	if(self->modeldata.type == TYPE_PLAYER)
15640 	{
15641 		self->takeaction = NULL;
15642 		set_idle(self);
15643 		return;
15644 	}
15645 
15646 	target = self->opponent;
15647 
15648 	if(target && !self->modeldata.nomove && diff(self->x, target->x)<80 && (rand32()&3))
15649 	{
15650 		self->takeaction = NULL;//common_runoff;
15651 		self->destx = self->x>target->x?MIN(self->x+40, target->x+80):MAX(self->x-40,target->x-80);
15652 		self->destz = self->z;
15653 		self->xdir = self->x>target->x?self->modeldata.speed:-self->modeldata.speed;
15654 		self->zdir = 0;
15655 		adjust_walk_animation(target);
15656 		self->idling = 1;
15657 	}
15658 	else
15659 	{
15660 		self->takeaction = NULL;
15661 		set_idle(self);
15662 	}
15663 
15664 	stall = GAME_SPEED - self->modeldata.aggression;
15665 	if (stall<GAME_SPEED/2)
15666 	{
15667 		stall = GAME_SPEED/2;
15668 	}
15669 	self->stalltime = time + MAX(0,stall);
15670 }
15671 
15672 
15673 //while playing attack animation
common_attack_proc()15674 void common_attack_proc()
15675 {
15676 
15677 	if(self->animating || diff(self->a, self->base)>=4) return;
15678 
15679 	if(self->tocost)
15680 	{    // Enemy was hit with a special so go ahead and subtract life
15681 		if(check_energy(1, self->animnum))
15682 		{
15683 			self->mp -= self->animation->energycost.cost;
15684 		}
15685 		else self->health -= self->animation->energycost.cost;
15686 		self->tocost = 0;    // Life is subtracted, so go ahead and reset the flag
15687 	}
15688 
15689 	if(self == smartbomber)
15690 	{    // Player is done with the special animation, so unfreeze and execute a smart bomb
15691 		smart_bomb(self, self->modeldata.smartbomb);
15692 		smartbomber = NULL;
15693 	}
15694 	if(self->reactive == 1)
15695 	{
15696 		subtract_shot();
15697 		self->reactive=0;
15698 	}
15699 	self->attacking = 0;
15700 	// end of attack proc
15701 	common_attack_finish();
15702 }
15703 
15704 
15705 // dispatch A.I. attack
common_attack()15706 int common_attack()
15707 {
15708 	int aiattack ;
15709 
15710 	//if(stalker==self) return 0;
15711 
15712 	if(time/THINK_SPEED%4==0) return 0;
15713 
15714 	if(self->modeldata.aiattack==-1) return 0;
15715 
15716 	aiattack = self->modeldata.aiattack & MASK_AIATTACK1;
15717 
15718 	switch(aiattack)
15719 	{
15720 	case AIATTACK1_LONG:
15721 	case AIATTACK1_MELEE:
15722 	case AIATTACK1_NOATTACK:
15723 		return 0;
15724 	default:                    // this is the only available attack style by now
15725 		return inair(self)?0:normal_attack();
15726 	}
15727 }
15728 
15729 //maybe used many times, so make a function
15730 // A.I. characters will check if there's a wall infront, and jump onto it if possible
15731 // return 1 if jump
common_try_jump()15732 int common_try_jump()
15733 {
15734 	float xdir, zdir;
15735 	int wall, j=0;
15736 	float rmin, rmax;
15737 
15738 	if(validanim(self,ANI_JUMP)) //Can jump?
15739 	{
15740 		//Check to see if there is a wall within jumping distance and within a jumping height
15741 		xdir = 0; wall = -1;
15742 		rmin = (float)self->modeldata.animation[ANI_JUMP]->range.xmin;
15743 		rmax = (float)self->modeldata.animation[ANI_JUMP]->range.xmax;
15744 		if(self->direction) xdir = self->x + rmin;
15745 		else xdir = self->x - rmin;
15746 		//check z jump
15747 		if(self->modeldata.jumpmovez) zdir = self->z + self->zdir;
15748 		else zdir = self->z;
15749 
15750 		if( (wall = checkwall_below(xdir, zdir, 999999)) >= 0 &&
15751 			level->walls[wall][7] <= self->a + rmax &&
15752 			!inair(self) && self->a < level->walls[wall][7]  )
15753 		{
15754 			j=1;
15755 		}
15756 		else if(checkhole(self->x + (self->direction?2:-2), zdir) &&
15757 				checkwall(self->x + (self->direction?2:-2), zdir)<0 &&
15758 				check_platform (self->x + (self->direction?2:-2), zdir, self)==NULL &&
15759 				!checkhole(self->x + (self->direction?rmax:-rmax), zdir))
15760 		{
15761 			j=1;
15762 		}
15763 	}
15764 
15765 	/*
15766 	Damon V. Caskey
15767 	03292010
15768 	AI can will check its RUNJUMP range if JUMP can't reach. Code is pretty redundant,
15769 	can probably be moved to a function later.
15770 	*/
15771 	if(!j && validanim(self, ANI_RUNJUMP))														//Jump check failed and can run jump?
15772 	{
15773 		//Check for wall in range of RUNJUMP.
15774 		xdir = 0; wall = -1;
15775 		rmin = (float)self->modeldata.animation[ANI_RUNJUMP]->range.xmin;
15776 		rmax = (float)self->modeldata.animation[ANI_RUNJUMP]->range.xmax;
15777 		if(self->direction) xdir = self->x + rmin;
15778 		else xdir = self->x - rmin;
15779 		//check z jump
15780 		if(self->modeldata.jumpmovez) zdir = self->z + self->zdir;
15781 		else zdir = self->z;
15782 
15783 		if( (wall = checkwall_below(xdir, zdir, 999999)) >= 0 &&
15784 			level->walls[wall][7] <= self->a + rmax &&
15785 			!inair(self) && self->a < level->walls[wall][7]  )
15786 		{
15787 			j=2;																				//Set to perform runjump.
15788 		}
15789 		//Check for pit in range of RUNJUMP.
15790 		else if(checkhole(self->x + (self->direction?2:-2), zdir) &&
15791 				checkwall(self->x + (self->direction?2:-2), zdir)<0 &&
15792 				check_platform (self->x + (self->direction?2:-2), zdir, self)==NULL &&
15793 				!checkhole(self->x + (self->direction?rmax:-rmax), zdir))
15794 		{
15795 			j=2;																				//Set to perform runjump.
15796 		}
15797 	}
15798 
15799 	if(j)
15800 	{
15801 		if(self->running || j==2)
15802 		{
15803 			if(validanim(self,ANI_RUNJUMP))														//Running or only within range of RUNJUMP?
15804 				tryjump(self->modeldata.runjumpheight, self->modeldata.jumpspeed*self->modeldata.runjumpdist, (self->modeldata.jumpmovez)?self->zdir:0, ANI_RUNJUMP);
15805 			else if(validanim(self,ANI_FORWARDJUMP))
15806 				tryjump(self->modeldata.runjumpheight, self->modeldata.jumpspeed*self->modeldata.runjumpdist, (self->modeldata.jumpmovez)?self->zdir:0, ANI_FORWARDJUMP);
15807 			else
15808 				tryjump(self->modeldata.runjumpheight, self->modeldata.jumpspeed*self->modeldata.runjumpdist, (self->modeldata.jumpmovez)?self->zdir:0, ANI_JUMP);
15809 		}
15810 		else
15811 		{
15812 			if(validanim(self,ANI_FORWARDJUMP))
15813 				tryjump(self->modeldata.jumpheight, self->modeldata.jumpspeed, (self->modeldata.jumpmovez)?self->zdir:0, ANI_FORWARDJUMP);
15814 			else
15815 				tryjump(self->modeldata.jumpheight, self->modeldata.jumpspeed, (self->modeldata.jumpmovez)?self->zdir:0, ANI_JUMP);
15816 		}
15817 
15818 		return 1;
15819 	}
15820 	return 0;
15821 }
15822 
adjust_walk_animation(entity * other)15823 void adjust_walk_animation(entity* other)
15824 {
15825 	if(self->running)
15826 	{
15827 		ent_set_anim(self, ANI_RUN, 0);
15828 		return;
15829 	}
15830 
15831 	//reset the walk animation
15832 	if( ((!other && self->zdir<0)||(other && self->z>other->z)) && validanim(self,ANI_UP))
15833 		common_up_anim(self); //ent_set_anim(self, ANI_UP, 0);
15834 	else if(((!other && self->zdir>0)||(other && other->z > self->z)) && validanim(self,ANI_DOWN))
15835 		common_down_anim(self); //ent_set_anim(self, ANI_DOWN, 0);
15836 	else if((self->direction ? self->xdir<0 : self->xdir>0) && validanim(self,ANI_BACKWALK))
15837 		common_backwalk_anim(self); //ent_set_anim(self, ANI_BACKWALK, 0);
15838 	else common_walk_anim(self); //ent_set_anim(self, ANI_WALK, 0);
15839 
15840 	if((self->direction ? self->xdir<0 : self->xdir>0) && self->animnum!=ANI_BACKWALK)
15841 		self->animating = -1;
15842 	else self->animating = 1;
15843 }
15844 
15845 
15846 // ai character try to move towards the item
15847 // TODO, check path or entity might get stuck under a wall
common_try_pick(entity * other)15848 int common_try_pick(entity* other)
15849 {
15850 	// if there's an item to pick up, move towards it.
15851 	float maxspeed = self->modeldata.speed*1.5;
15852 	float dx = diff(self->x, other->x);
15853 	float dz = diff(self->z, other->z);
15854 
15855 	if(other == NULL || self->modeldata.nomove) return 0;
15856 
15857 	if(!dz && !dx) {
15858 		self->xdir = self->zdir = 0;
15859 		self->destz = self->z;
15860 		self->destx = self->x;
15861 	}
15862 	else {
15863 		self->xdir = maxspeed * dx / (dx+dz);
15864 		self->zdir = maxspeed * dz / (dx+dz);
15865 		self->destx = other->x;
15866 		self->destz = other->z;
15867 	}
15868 	if(self->x > other->x) self->xdir = -self->xdir;
15869 	if(self->z > other->z) self->zdir = -self->zdir;
15870 
15871 	self->running = 0;
15872 
15873 	adjust_walk_animation(other);
15874 
15875 	return 1;
15876 }
15877 
15878 #define astarw 640
15879 #define astarh 360
15880 #define starts (astarw*astarh)
15881 
15882 // not so completed pathfinding logic based on a*
15883 // it should be fairly slow due to the complicacy of terrain checking
15884 // and it doesn't always work since walking from wall to wall
15885 // requires jump.
astar(entity * ent,float destx,float destz,float step,point2d ** wp)15886 int astar(entity* ent, float destx, float destz, float step, point2d** wp){
15887 	int (*came_from)[astarw][astarh][2] = malloc(sizeof(*came_from));
15888 	unsigned char (*closed)[astarw][astarh] = malloc(sizeof(*closed));
15889 	int (*openset)[starts][2] = malloc(sizeof(*openset));
15890 	float (*gscore)[astarw][astarh] = malloc(sizeof(*gscore));
15891 	float (*hscore)[astarw][astarh] = malloc(sizeof(*hscore));
15892 	float (*fscore)[astarw][astarh] = malloc(sizeof(*fscore));
15893 	int opensize = 0;
15894 	int result=0, mi=0;
15895 	float tg, minf;
15896 	int x, z, i, j, tx, tz, better;
15897 	static int vx[8] = {0, 1, 1, 1, 0, -1, -1, -1}, vz[8] = {-1, -1, 0, 1, 1, 1, 0, -1};
15898 	static float score[8] = {1.0, 1.4, 1.0, 1.4, 1.0, 1.4, 1.0, 1.4};
15899 
15900 	int sx = astarw/2, sz = astarh/2;
15901 	int dx = sx + (destx-ent->x)/step, dz = sz + (destz-ent->z)/step;
15902 
15903 	*wp = NULL;
15904 	if(dx<0 || dx>=astarw || dz<0 || dz>=astarh){
15905 		goto pfclearup;
15906 	}
15907 	memset(closed, 0, sizeof(*closed));
15908     (*openset)[opensize][0] = sx;
15909 	(*openset)[opensize][1] = sz;
15910 	opensize++;
15911     memset(came_from, 0, sizeof(*came_from));
15912 
15913 	(*gscore)[sx][sz] = 0;
15914 	(*hscore)[sx][sz] = diff(dx, sx) + diff(dz, sz);
15915 	(*fscore)[sx][sz] = (*gscore)[sx][sz] + (*hscore)[sx][sz];
15916 	(*came_from)[sx][sz][0] = -1;
15917 
15918 	while(opensize>0){
15919 		minf = 9999999;
15920 		for(j=0; j<opensize; j++){
15921 			x = (*openset)[j][0];
15922 			z = (*openset)[j][1];
15923 			if((*fscore)[x][z]<minf){
15924 				minf = (*fscore)[x][z];
15925 				mi = j;
15926 			}
15927 		}
15928 
15929 		x = (*openset)[mi][0];z = (*openset)[mi][1];
15930         if(x==dx && z==dz) {
15931 			 do{
15932 				tx = (*came_from)[x][z][0];
15933 				tz = (*came_from)[x][z][1];
15934 				result++;
15935 				x = tx; z = tz;
15936 			 }while(x>=0);
15937 			 *wp = malloc(sizeof(point2d)*result);
15938 			 tx = (*came_from)[dx][dz][0];
15939 			 tz = (*came_from)[dx][dz][1];
15940 			 j = 0;
15941 			 while(tx>=0){
15942 				(*wp)[j].x = (tx-sx)*step + ent->x;
15943 				(*wp)[j].z = (tz-sz)*step + ent->z;
15944 				x = (*came_from)[tx][tz][0];
15945 				z = (*came_from)[tx][tz][1];
15946 				tx = x; tz = z;
15947 				j++;
15948 			 }
15949 			 goto pfclearup;
15950 		}
15951 
15952 		(*openset)[mi][0] = (*openset)[opensize-1][0];
15953 		(*openset)[mi][1] = (*openset)[opensize-1][1];
15954 
15955         opensize--;
15956         (*closed)[x][z] = 1;
15957 
15958 		for(i=0; i<8; i++){
15959 			tx = x + vx[i]; tz = z + vz[i];
15960 
15961 			if(tx<0 || tx>=astarw || tz<0 || tz>=astarh) continue;
15962 			if((*closed)[tx][tz]) continue;
15963 
15964 			if(!testmove(ent, (x-sx)*step+ent->x, (z-sz)*step+ent->z,  (tx-sx)*step+ent->x, (tz-sz)*step+ent->z)){
15965 				//(*closed)[tx][tz] = 1; // don't add that to close list just in case the entity can jump
15966 				continue;
15967 			}
15968 
15969             tg = (*gscore)[x][z] + score[i];
15970 
15971 			for(j=0; j<opensize; j++){
15972 				if((*openset)[j][0]==tx && (*openset)[j][1]==tz){
15973 					break;
15974 				}
15975 			}
15976 
15977             if(j==opensize){
15978 				(*openset)[opensize][0] = tx;
15979 				(*openset)[opensize][1] = tz;
15980                 opensize++;
15981                 better = 1;
15982             }else if (tg < (*gscore)[tx][tz])
15983                 better = 1;
15984             else
15985                 better = 0;
15986 
15987             if(better){
15988                 (*came_from)[tx][tz][0] = x;
15989 				(*came_from)[tx][tz][1] = z;
15990                 (*gscore)[tx][tz] = tg;
15991                 (*hscore)[tx][tz] = diff(tx, dx) + diff(tz, dz);
15992                 (*fscore)[tx][tz] = (*gscore)[tx][tz] + (*hscore)[tx][tz];
15993 			}
15994 		}
15995 	}
15996 
15997 pfclearup:
15998 	if(came_from) free(came_from); came_from = NULL;
15999 	if(closed) free(closed); closed = NULL;
16000 	if(openset) free(openset); openset = NULL;
16001 	if(gscore) free(gscore); gscore = NULL;
16002 	if(hscore) free(hscore); hscore = NULL;
16003 	if(fscore) free(fscore); fscore = NULL;
16004 
16005 	return result;
16006 }
16007 
16008 
16009 // use this after a wall checking meets
16010 // wall sliding code
16011 // whichside:
16012 //      0
16013 //  1       3
16014 //      2
adjustdirection(float coords[],float offx,float offz,float ox,float oz,float xdir,float zdir,float * cxdir,float * czdir)16015 int adjustdirection(float coords[], float offx, float offz, float ox, float oz, float xdir, float zdir, float *cxdir, float *czdir)
16016 {
16017 	float x[4], z[4];
16018 	int whichside, i;
16019 	float a;
16020 
16021 	for(i=0; i<4; i++){
16022 		x[i] = coords[2+i] + coords[0] + offx;
16023 	}
16024 	z[1] = z[3] = coords[1] + offz;
16025 	z[0] = z[2] = z[1] - coords[6];
16026 
16027 	if(oz<=z[0]) whichside = 0;
16028 	else if(oz>=z[1]) whichside = 2;
16029 	else if(ox<x[2]) whichside = 1;
16030 	else whichside = 3;
16031 
16032 	if(whichside==0 || whichside==2){
16033 		*cxdir = xdir;
16034 		*czdir = 0;
16035 	}else{
16036 		if((x[0]==x[1] && whichside==1) || (x[2]==x[3] && whichside==3)) {
16037 			*cxdir = 0;
16038 			*czdir = zdir;
16039 		}else{
16040 			if(whichside==1)
16041 				a = (z[1]-z[0])/(x[1]-x[0]);
16042 			else
16043 				a = (z[3]-z[2])/(x[3]-x[2]);
16044 
16045 			*cxdir = xdir + zdir/a;
16046 			*czdir = a * xdir + zdir;
16047 
16048 			a = (ABS(xdir) + ABS(zdir)) / (ABS(*cxdir) + ABS(*czdir)) ;
16049 			*cxdir *= a;
16050 			*czdir *= a;
16051 		}
16052 	}
16053 	//printf("%f, %f, %f, %f, %d\n", xdir, zdir, *cxdir, *czdir, whichside);
16054 	return whichside;
16055 }
16056 
16057 // adjust walk speed for entity assuming it walks straight forward
16058 // x, z - current position
16059 // tx, tz - target position
16060 // speed - max speed
16061 // xdir, zdir - return values
adjustspeed(float speed,float x,float z,float tx,float tz,float * xdir,float * zdir)16062 void adjustspeed(float speed, float x, float z, float tx, float tz, float* xdir, float* zdir){
16063 	float xd, zd;
16064 	float dx = diff(tx, x);
16065 	float dz = diff(tz,z)*2;
16066 
16067 	if(dx>dz) {
16068 		xd = speed;
16069 		zd = xd/dx*dz;
16070 	}else if(dz>dx){
16071 		zd = speed;
16072 		xd = zd/dz*dx;
16073 	}else if(dx){
16074 		xd = zd = speed;
16075 	}else{
16076 		xd = zd = 0;
16077 	}
16078 
16079 	if(tx<x) xd = -xd;
16080 	if(tz<z) zd = -zd;
16081 
16082 	zd /= 2;
16083 
16084 	*xdir = xd;
16085 	*zdir = zd;
16086 
16087 }
16088 
checkpathblocked()16089 int checkpathblocked()
16090 {
16091 	float x, z, r;
16092 	int aitype, wpc;
16093 	entity * target;
16094 	point2d* wp;
16095 	if(self->modeldata.nomove) return 0;
16096 	if(self->stalltime>=time)
16097 	{
16098 		aitype = self->modeldata.aimove;
16099 		if(self->modeldata.subtype==SUBTYPE_CHASE) aitype |= AIMOVE1_CHASE;
16100 
16101 		//be moo tolerable to PLAYER_MAX_Z and PLAYER_MIN_Z
16102 		if((self->modeldata.subject_to_maxz && self->zdir>0 && !self->xdir && self->zdir+self->z>PLAYER_MAX_Z) ||
16103 		   (self->modeldata.subject_to_minz && self->zdir<0 && !self->xdir && self->zdir+self->z<PLAYER_MIN_Z) )
16104 		{
16105 			self->zdir = -self->zdir;
16106 			self->pathblocked = 0;
16107 			self->destz = self->zdir>0?(PLAYER_MIN_Z+videomodes.vRes/10):(PLAYER_MAX_Z-videomodes.vRes/10);
16108 			adjust_walk_animation(NULL);
16109 			return 1;
16110 		}
16111 
16112 		if(self->pathblocked>40 || (self->pathblocked>20 && (aitype & (AIMOVE1_CHASEX|AIMOVE1_CHASEZ|AIMOVE1_CHASE))))
16113 		{
16114 			if(self->modeldata.pathfindstep>0){
16115 				target = normal_find_target(-1,0);
16116 
16117 				if(target){
16118 					//printf("pathfind: (%f %f)-(%f %f) %d steps\n", self->x, self->z, self->destx, self->destz, pathfind(self, self->destx, self->destz));
16119 					if((wpc=astar(self, target->x, target->z, self->modeldata.pathfindstep, &wp))>0){
16120 						//printf("wp %d\n", wp);
16121 						self->numwaypoints = wpc;
16122 						if(self->waypoints){
16123 							free(self->waypoints);
16124 						}
16125 						self->waypoints = wp;
16126 						self->destx = self->waypoints[self->numwaypoints-1].x;
16127 						self->destz = self->waypoints[self->numwaypoints-1].z;
16128 						self->numwaypoints--;
16129 						self->pathblocked = 0;
16130 						return 1;
16131 					}
16132 				}
16133 			}
16134 
16135 			x = self->xdir;
16136 			z = self->zdir;
16137 			if(x>0) x = self->modeldata.speed;
16138 			else if(x<0) x = -self->modeldata.speed;
16139 			if(z>0) z = self->modeldata.speed/2;
16140 			else if(z<0) z = -self->modeldata.speed/2;
16141 			r = randf(1);
16142 			if(r>0.6f){
16143 				self->zdir = x;
16144 				self->xdir = -z;
16145 			} else if(r>0.2f) {
16146 				self->zdir = -x;
16147 				self->xdir = z;
16148 			}else{
16149 				self->zdir = (1.0f - randf(2))*self->modeldata.speed/2;
16150 				self->xdir = (1.0f - randf(2))*self->modeldata.speed;
16151 			}
16152 			self->running = 0; // TODO: re-adjust walk speed
16153 			self->stalltime = time + GAME_SPEED/2;
16154 			adjust_walk_animation(NULL);
16155 			self->pathblocked = 0;
16156 
16157 			if(self->zdir>0) self->destz = self->z + 40;
16158 			else if(self->zdir<0) self->destz = self->z - 40;
16159 			else self->destz = self->z;
16160 			if(self->xdir>0) self->destx = self->x + 40;
16161 			else if(self->xdir<0) self->destx = self->x - 40;
16162 			else self->destx = self->x;
16163 
16164 			return 1;
16165 
16166 		}
16167 	}
16168 	return 0;
16169 }
16170 
16171 
16172 // this is the most aggressive aimove pattern
16173 // the entity will try get in and attack at anytime
16174 // though the range depends on what attack you setup
common_try_chase(entity * target,int dox,int doz)16175 int common_try_chase(entity* target, int dox, int doz)
16176 {
16177 	// start chasing the target
16178 	float dx, dz, range;
16179 	int randomatk;
16180 
16181 	self->running = 0;
16182 
16183 	//adjustspeed(self->modeldata.speed, self->x, self->z, self->x + self->xdir, self->z + self->zdir, &self->xdir, &self->zdir);
16184 
16185 	if(target == NULL || self->modeldata.nomove) return 0;
16186 
16187 	randomatk = pick_random_attack(NULL, 0);
16188 
16189 	if(randomatk>=0){
16190 		range = (self->modeldata.animation[randomatk]->range.xmin + self->modeldata.animation[randomatk]->range.xmax)/2;
16191 		//printf("range picked: ani %d, range %f\n", randomatk, range);
16192 		if(range<0) range = self->modeldata.grabdistance;
16193 		else if(range>videomodes.hRes/4) range = videomodes.hRes/4;
16194 	} else range = self->modeldata.grabdistance;
16195 
16196 	if(dox){
16197 		if(self->x>target->x) self->destx = target->x + range - 1;
16198 		else self->destx = target->x - range + 1;
16199 		dx = diff(self->x, self->destx);
16200 
16201 		if(dx>150 && validanim(self, ANI_RUN)){
16202 			self->xdir = self->modeldata.runspeed;
16203 			self->running = 1;
16204 		}
16205 		else self->xdir = self->modeldata.speed;
16206 		if(self->destx<self->x) self->xdir = -self->xdir;
16207 	}
16208 
16209 	if(doz){
16210 		self->destz = target->z ;
16211 		dz = diff(self->z, self->destz);
16212 
16213 		if(dz>100 && self->modeldata.runupdown && validanim(self, ANI_RUN)){
16214 			self->zdir = self->modeldata.runspeed/2;
16215 			self->running = 1;
16216 		}
16217 		else self->zdir = self->modeldata.speed/2;
16218 		if(self->destz<self->z) self->zdir = -self->zdir;
16219 	}
16220 
16221 	return 1;
16222 }
16223 
16224 //may be used many times, so make a function
16225 // minion follow his owner
common_try_follow(entity * target,int dox,int doz)16226 int common_try_follow(entity* target, int dox, int doz)
16227 {
16228 	// start chasing the target
16229 	float dx, dz, distance;
16230 	int mx, mz;
16231 	int facing;
16232 
16233 	//target = self->parent;
16234 	if(target == NULL || self->modeldata.nomove) return 0;
16235 	distance = (float)((validanim(self,ANI_IDLE))? self->modeldata.animation[ANI_IDLE]->range.xmin: 100);
16236 
16237 	if(distance<=0) distance = 100.0;
16238 
16239 	facing = (self->direction?self->x<target->x:self->x>target->x);
16240 
16241 	dx = diff(self->x, target->x);
16242 	dz = diff(self->z, target->z);
16243 
16244 	if(dox && dx<distance) {
16245 		self->xdir = 0;
16246 		mx = 0;
16247 	}else mx = 1;
16248 
16249 	if(doz && dz<distance/2){
16250 		self->zdir = 0;
16251 		mz = 0;
16252 	}else mz = 1;
16253 
16254 	if(dox && mx){
16255 		if(facing && dx>200 && validanim(self, ANI_RUN)){
16256 			self->xdir = self->modeldata.runspeed;
16257 			self->running = 1;
16258 		}else {
16259 			self->xdir = self->modeldata.speed;
16260 			self->running = 0;
16261 		}
16262 		if(self->x>target->x) self->xdir = -self->xdir;
16263 		self->destx = target->x;
16264 	}
16265 
16266 	if(doz && mz){
16267 		if(facing && dx>200 && self->modeldata.runupdown && validanim(self, ANI_RUN)){
16268 			self->zdir = self->modeldata.runspeed/2;
16269 			self->running = 1;
16270 		}else{
16271 			self->zdir = self->modeldata.speed/2;
16272 			self->running = 0; // not right, to be modified
16273 		}
16274 		if(self->z>target->z) self->zdir = -self->zdir;
16275 		self->destz = target->z;
16276 	}
16277 
16278 
16279 	return 1;
16280 }
16281 
16282 // try to avoid the target
16283 // used by 'avoid avoidz avoidx
16284 // Basic logic: the entity walk within a min distance and a max distance from the target
common_try_avoid(entity * target,int dox,int doz)16285 int common_try_avoid(entity* target, int dox, int doz)
16286 {
16287 	float dx, dz;
16288 	float maxdz, mindz, maxdx, mindx;
16289 	int randomatk;
16290 
16291 	if(target == NULL || self->modeldata.nomove) return 0;
16292 
16293 	dx = diff(self->x, target->x);
16294 	dz = diff(self->z, target->z);
16295 
16296 	randomatk = pick_random_attack(NULL, 0);
16297 
16298 	if((rand32()&15)<8 && randomatk>=0){
16299 		maxdx = self->modeldata.animation[randomatk]->range.xmax-self->modeldata.speed;
16300 		if(maxdx<videomodes.hRes/5) maxdx = videomodes.hRes / 5;
16301 		mindx = maxdx - 10;
16302 		maxdz = self->modeldata.animation[randomatk]->range.zmax-self->modeldata.speed;
16303 		if(maxdz<videomodes.vRes/5) maxdz = videomodes.vRes / 5;
16304 		mindz = maxdz - 10;
16305 	}else {
16306 		mindx = videomodes.hRes / 3;
16307 		maxdx = videomodes.hRes / 2;
16308 		mindz = videomodes.vRes / 3;
16309 		maxdz = videomodes.vRes / 2;
16310 	}
16311 
16312 	if(dox){
16313 		if(self->x < screenx) {
16314 			self->xdir = self->modeldata.speed;
16315 			self->destx = screenx + videomodes.hRes/12.0;
16316 		}else if(self->x > screenx + videomodes.hRes) {
16317 			self->xdir = -self->modeldata.speed;
16318 			self->destx = screenx + videomodes.hRes*11.0/12.0;
16319 		}else if(dx < mindx){
16320 			self->xdir = (self->x < target->x)? (-self->modeldata.speed):self->modeldata.speed;
16321 			self->destx = (self->x < target->x)? (target->x-maxdx): (target->x + maxdx);
16322 		}else if (dx > maxdx){
16323 			self->xdir = (self->x < target->x)? self->modeldata.speed:(-self->modeldata.speed);
16324 			self->destx = (self->x < target->x)? (target->x-mindx): (target->x + mindx);
16325 		}else {
16326 			self->xdir = 0;
16327 			self->destx = self->x;
16328 		}
16329 	}
16330 
16331 	if(doz){
16332 		if(self->z < screeny) {
16333 			self->zdir = self->modeldata.speed/2;
16334 			self->destz = screeny +  videomodes.vRes/12.0;
16335 		}else if(self->z > screeny + videomodes.vRes) {
16336 			self->zdir = -self->modeldata.speed/2;
16337 			self->destz = screeny +  videomodes.vRes*11.0/12.0;
16338 		}else if(dz < mindz){
16339 			self->zdir = (self->z < target->z)? (-self->modeldata.speed/2):(self->modeldata.speed/2);
16340 			self->destz = (self->z < target->z)? (target->z-maxdz): (target->z + maxdz);
16341 		}else if(dz > maxdz){
16342 			self->zdir = (self->z < target->z)? (self->modeldata.speed/2):(-self->modeldata.speed/2);
16343 			self->destz = (self->z < target->z)? (target->z-mindz): (target->z + mindz);
16344 		}else {
16345 			self->zdir = 0;
16346 			self->destz = self->z;
16347 		}
16348 	}
16349 
16350 	return 1;
16351 }
16352 
16353 //  wander completely and ignore the target
16354 // this ai pattern only works when you use aimove wander,
16355 // if you mix wander with other patterns like chase or avoid
16356 // this pattern is not triggered
common_try_wandercompletely(int dox,int doz)16357 int common_try_wandercompletely(int dox, int doz)
16358 {
16359 	int rnum;
16360 
16361 	if(self->modeldata.nomove) return 0;
16362 
16363 	if(dox){
16364 		rnum = rand32()&15;
16365 		if(rnum < 4) self->xdir = -self->modeldata.speed;
16366 		else if(rnum> 11) self->xdir = self->modeldata.speed;
16367 		else self->xdir = 0;
16368 		if( self->x<screenx-10){
16369 			self->xdir = self->modeldata.speed;
16370 		}else if(self->x>screenx+videomodes.hRes+10){
16371 			self->xdir = -self->modeldata.speed;
16372 		}
16373 
16374 		if(self->xdir>0) self->destx = self->x + videomodes.hRes/5;
16375 		else if(self->xdir<0) self->destx = self->x - videomodes.hRes/5;
16376 		else self->destx = self->x;
16377 
16378 	}
16379 	if(doz){
16380 		rnum = rand32()&15;
16381 		if(rnum < 4) self->zdir = -self->modeldata.speed/2;
16382 		else if(rnum > 11) self->zdir = self->modeldata.speed/2;
16383 		else self->zdir = 0;
16384 		if(self->z<screeny-10){
16385 			self->zdir = self->modeldata.speed/2;
16386 		}else if(self->z>screeny+videomodes.vRes+10){
16387 			self->zdir = -self->modeldata.speed/2;
16388 		}
16389 
16390 		if(self->zdir>0) self->destz = self->z + videomodes.vRes/5;
16391 		else if(self->zdir<0) self->destz = self->z - videomodes.vRes/5;
16392 		else self->destz = self->z;
16393 
16394 	}
16395 
16396 	return 1;
16397 
16398 }
16399 /*
16400 int assume_safe_distance(entity* target, int ani, int* minx, int* maxx, int* minz, int* maxz)
16401 {
16402 	int f, set = 0;
16403 	short tminx, tmaxx, tminz, tmaxz;
16404 	s_anim* ta;
16405 	short* coords;
16406 	if(validanim(target, ani)){
16407 		ta = target->modeldata.animation[ani];
16408 		*minx = *minz = 9999;
16409 		*maxx = *maxz = -9999;
16410 		if(ta->attacks){
16411 			for(f=0; f<ta->numframes; f++){
16412 				if(!ta->attacks[f]) continue;
16413 				coords = ta->attacks[f]->attack_coords;
16414 				if(target->direction) {
16415 					tminx = coords[0];
16416 					tmaxx = coords[2];
16417 				}else{
16418 					tminx = -coords[2];
16419 					tmaxx = -coords[0];
16420 				}
16421 				tminz = -coords[4];
16422 				tmaxz = coords[4];
16423 				if(tminx<*minx)
16424 					*minx = tminx;
16425 				if(tminz<*minz)
16426 					*minz = tminz;
16427 				if(tmaxx>*maxx)
16428 					*maxx = tmaxx;
16429 				if(tmaxz>*maxz)
16430 					*maxz = tmaxz;
16431 
16432 				set = 1;
16433 			}
16434 
16435 			if(set && self->animation->bbox_coords && self->animation->bbox_coords[self->animpos]){
16436 				coords = self->animation->bbox_coords[self->animpos];
16437 				*minx -= coords[2] - coords[0];
16438 				*minz -= coords[4];
16439 				*maxx += coords[2] - coords[0];
16440 				*maxz += coords[4];
16441 			}
16442 
16443 			return set;
16444 		}
16445 	}
16446 
16447 	return 0;
16448 
16449 }
16450 */
16451 // for normal and default ai patttern
16452 // the entity is not actually wandering
16453 // they just go around the target and get close
16454 // occasionally to attack
common_try_wander(entity * target,int dox,int doz)16455 int common_try_wander(entity* target, int dox, int doz)
16456 {
16457 	int walk = 0, behind, grabd, mod;
16458 
16459 	float diffx, diffz, //distance from target
16460 		returndx, returndz, //how far should keep from target
16461 		borderdx, borderdz, //how far should keep offscreen
16462 		mindx, mindz;// don't walk into the target
16463 	int rnum = rand32()&15, t, randomatk;
16464 
16465 	if(!target || self->modeldata.nomove) return 0;
16466 
16467 	diffx = diff(self->x, target->x);
16468 	diffz = diff(self->z, target->z);
16469 	behind = ((self->x<target->x)==target->direction);
16470 	grabd = self->modeldata.grabdistance;
16471 	//when entity is behind the target, it has a greater chance to go after the target
16472 	if(behind&&diffx<grabd*4&&diffz<grabd){ //right behind, go for it
16473 		t = 13;
16474 	}else if(behind){ // only behind, half chance
16475 		t = 7;
16476 	}else { // otherwise, 1/8 chance
16477 		t = 2;
16478 	}
16479 
16480 	if(behind && target->attacking) t+=5;
16481 
16482 	// could use this to replace the completely wander ai
16483 	if(dox!=doz) t = 0;
16484 
16485 	if(rnum<t){ //chase target
16486 		returndx = videomodes.hRes/4;
16487 		returndz = videomodes.vRes/8;
16488 	}else{ // only chase when too far away
16489 		returndx = videomodes.hRes*0.6;
16490 		returndz = videomodes.vRes*0.4;
16491 	}
16492 	if(rnum>7){
16493 		borderdx = videomodes.hRes/8;
16494 		borderdz = videomodes.vRes/8;
16495 	}else{
16496 		borderdx = borderdz = 0;
16497 	}
16498 
16499 	randomatk = pick_random_attack(NULL, 0);
16500 
16501 	if(randomatk>=0){
16502 		mindx = self->modeldata.animation[randomatk]->range.xmax - (self->modeldata.animation[randomatk]->range.xmax-self->modeldata.animation[randomatk]->range.xmin)/4 -1;
16503 	} else	mindx = (!behind&&target->attacking)? grabd*3:grabd*1.2;
16504 	mindz = grabd/4;
16505 
16506 	mod = ((int)(time/(videomodes.hRes/self->modeldata.speed)) + self->sortid/100 + self->health/3 + self->pathblocked + self->modeldata.aggression/10) % 4;
16507 
16508 	if(dox){
16509 		if(self->x<screenx-borderdx){
16510 			self->xdir = self->modeldata.speed;
16511 			self->destx = screenx + videomodes.hRes/8.0;
16512 			walk = 1;
16513 		}else if (self->x>screenx+videomodes.hRes+borderdx){
16514 			self->xdir = -self->modeldata.speed;
16515 			self->destx = screenx + videomodes.hRes*7.0/8.0;
16516 			walk = 1;
16517 		}else if(diffx>returndx){
16518 			self->xdir = (self->x>target->x)?-self->modeldata.speed:self->modeldata.speed;
16519 			self->destx = (self->x>target->x)?(target->x + mindx):(target->x - mindx);
16520 			walk = 1;
16521 		}else{
16522 			switch(mod){
16523 			case 0:
16524 				self->destx = target->x + grabd;
16525 				break;
16526 			case 2:
16527 				self->destx = target->x - grabd;
16528 				break;
16529 			case 1:
16530 				self->destx = target->x + videomodes.hRes*0.4 + (self->health/3%20);
16531 				break;
16532 			case 3:
16533 				self->destx = target->x - videomodes.hRes*0.4 - (self->health/3%20);;
16534 				break;
16535 			}
16536 			self->xdir = self->x>self->destx?-self->modeldata.speed:self->modeldata.speed;
16537 			walk = 1;
16538 			//printf("mod x %d\n", mod);
16539 		}
16540 	}
16541 
16542 	if(doz)
16543 	{
16544 		if(self->z<screeny-borderdz){
16545 			self->zdir = self->modeldata.speed/2;
16546 			self->destz = screeny + videomodes.vRes/12.0;
16547 			walk |= 1;
16548 		}else if (self->z>screeny+videomodes.vRes+borderdz){
16549 			self->zdir = -self->modeldata.speed/2;
16550 			self->destz = screeny + videomodes.vRes*11.0/12.0;
16551 			walk |= 1;
16552 		}else if(diffz>returndz){
16553 			self->zdir = (self->z>target->z)?-self->modeldata.speed/2:self->modeldata.speed/2;
16554 			self->destz = (self->z>target->z)?(target->z + mindz):(target->z - mindz);
16555 			walk |= 1;
16556 		} else{
16557 			switch(mod){
16558 			case 1:
16559 				self->destz = target->z + grabd/2;
16560 				break;
16561 			case 3:
16562 				self->destz = target->z - grabd/2;
16563 				break;
16564 			case 2:
16565 				self->destz = target->z + MIN((PLAYER_MAX_Z-PLAYER_MIN_Z), videomodes.vRes)*0.25+(self->health/3%5);
16566 				break;
16567 			case 0:
16568 				self->destz = target->z - MIN((PLAYER_MAX_Z-PLAYER_MIN_Z), videomodes.vRes)*0.25-(self->health/3%5);
16569 				break;
16570 			}
16571 			self->zdir = self->z>self->destz?-self->modeldata.speed/2:self->modeldata.speed/2;
16572 			walk |= 1;
16573 			//printf("mod z %d\n", mod);
16574 		}
16575 	}
16576 
16577 	return walk;
16578 }
16579 
16580 //A.I chracter pickup an item
common_pickupitem(entity * other)16581 void common_pickupitem(entity* other){
16582 	int pickup = 0;
16583 	//weapons
16584 	if(self->weapent == NULL && isSubtypeWeapon(other) && validanim(self,ANI_GET))
16585 	{
16586 		self->takeaction = common_get;
16587 		dropweapon(0);  //don't bother dropping the previous one though, scine it won't pickup another
16588 		self->weapent = other;
16589 		set_weapon(self, other->modeldata.weapnum, 0);
16590 		set_getting(self);
16591 		self->xdir=self->zdir=0;//stop moving
16592 		if(self->modeldata.animal)  // UTunnels: well, ride, not get. :)
16593 		{
16594 			self->direction = other->direction;
16595 			self->x = other->x;
16596 			self->z = other->z;
16597 		}
16598 		other->nextanim = other->nextthink = time + GAME_SPEED*999999;
16599 		ent_set_anim(self, ANI_GET, 0);
16600 		pickup = 1;
16601 	}
16602 	// projectiles
16603 	else if(self->weapent == NULL && isSubtypeProjectile(other) && validanim(self,ANI_GET))
16604 	{
16605 		self->takeaction = common_get;
16606 		dropweapon(0);
16607 		self->weapent = other;
16608 		set_getting(self);
16609 		self->xdir=self->zdir=0;//stop moving
16610 		other->nextanim = other->nextthink = time + GAME_SPEED*999999;
16611 		ent_set_anim(self, ANI_GET, 0);
16612 		pickup = 1;
16613 	}
16614 	// other items
16615 	else if(! isSubtypeWeapon(other) && ! isSubtypeProjectile(other) )
16616 	{
16617 		if(validanim(self,ANI_GET) && !isSubtypeTouch(other))
16618 		{
16619 			self->takeaction = common_get;
16620 			set_getting(self);
16621 			self->xdir=self->zdir=0;//stop moving
16622 			ent_set_anim(self, ANI_GET, 0);
16623 		}
16624 		if(other->health){
16625 			self->health += other->health;
16626 			if(self->health > self->modeldata.health) self->health = self->modeldata.health;
16627 			other->health = 0;
16628 			//if(SAMPLE_GET >= 0) sound_play_sample(SAMPLE_GET, 0, savedata.effectvol,savedata.effectvol, 100);
16629 		}
16630 		// else if, TODO: other effects
16631 		// kill that item
16632 		other->takeaction = suicide;
16633 		other->nextthink = time + GAME_SPEED * 3;
16634 		pickup = 1;
16635 	}
16636 	// hide it
16637 	if(pickup)
16638 	{
16639 		execute_didhit_script(other, self, 0, 0, other->modeldata.subtype, 0, 0, 0, 0, 0); //Execute didhit script as if item "hit" collecter to allow easy item scripting.
16640 		other->z = 100000;
16641 	}
16642 }
16643 
16644 // for old bikers
biker_move()16645 int biker_move()
16646 {
16647 
16648 	if((self->direction)?(self->x > advancex+(videomodes.hRes+200)):(self->x < advancex-200))
16649 	{
16650 		self->direction = !self->direction;
16651 		self->attack_id = 0;
16652 		self->z = (float)(PLAYER_MIN_Z + randf((float)(PLAYER_MAX_Z-PLAYER_MIN_Z)));
16653 		if(SAMPLE_BIKE >= 0) sound_play_sample(SAMPLE_BIKE, 0, savedata.effectvol,savedata.effectvol, 100);
16654 		if(self->modeldata.speed) self->xdir = (self->direction)?(self->modeldata.speed):(-self->modeldata.speed);
16655 		else self->xdir = (self->direction)?((float)1.7 + randf((float)0.6)):(-((float)1.7 + randf((float)0.6)));
16656 	}
16657 
16658 	self->nextthink = time + THINK_SPEED / 2;
16659 	return 1;
16660 }
16661 
16662 // for common arrow types
arrow_move()16663 int arrow_move(){
16664 	int wall;
16665 	float dx;
16666 	float dz;
16667 	float maxspeed;
16668 	entity* target = NULL;
16669 
16670 	// new subtype chase
16671 	if(self->modeldata.subtype == SUBTYPE_CHASE)
16672 	{
16673 		target = homing_find_target(self->modeldata.hostile);
16674 
16675 		if(target)
16676 		{
16677 			if(!self->modeldata.noflip) self->direction = (target->x > self->x);
16678 			// start chasing the target
16679 			dx = diff(self->x, target->x);
16680 			dz = diff(self->z, target->z);
16681 			maxspeed = self->modeldata.speed * 1.5;
16682 
16683 			if(!dz && !dx) self->xdir = self->zdir = 0;
16684 			else
16685 			{
16686 				self->xdir = maxspeed * dx / (dx+dz);
16687 				self->zdir = maxspeed * dz / (dx+dz);
16688 			}
16689 			if(self->direction!=1) self->xdir = -self->xdir;
16690 			if(self->z > target->z) self->zdir = -self->zdir;
16691 		}
16692 		else
16693 		{
16694 			if(!self->xdir && !self->zdir)
16695 			{
16696 				if(self->direction == 0) self->xdir = -self->modeldata.speed;
16697 				else if(self->direction == 1) self->xdir = self->modeldata.speed;
16698 			}
16699 		}
16700 		if(!self->modeldata.nomove)
16701 		{
16702 			if(target && self->z > target->z && validanim(self,ANI_UP)) common_up_anim(self); //ent_set_anim(self, ANI_UP, 0);
16703 			else if(target && target->z > self->z && validanim(self,ANI_DOWN)) common_down_anim(self); //ent_set_anim(self, ANI_DOWN, 0);
16704 			else if(validanim(self,ANI_WALK)) common_walk_anim(self); //ent_set_anim(self, ANI_WALK, 0);
16705 			else
16706 			{
16707 				ent_set_anim(self, ANI_IDLE, 0);
16708 			}
16709 		}
16710 	}
16711 	else
16712 	{
16713 		// Now projectiles can have custom speeds
16714 		if(self->direction == 0) self->xdir = -self->modeldata.speed;
16715 		else if(self->direction == 1) self->xdir = self->modeldata.speed;
16716 	}
16717 
16718 	if(level)
16719 	{
16720 		if((level->exit_blocked && self->x > level->width-30-(PLAYER_MAX_Z-self->z)) ||
16721 			(self->modeldata.subject_to_wall && (wall = checkwall(self->x, self->z)) >= 0 && self->a < level->walls[wall][7]))
16722 		{
16723 			// Added so projectiles bounce off blocked exits
16724 			if(validanim(self,ANI_FALL))
16725 			{
16726 				self->takeaction = common_fall;
16727 				self->attacking = 0;
16728 				self->health = 0;
16729 				self->projectile = 0;
16730 				if(self->direction == 0) self->xdir = (float)-1.2;
16731 				else if(self->direction == 1) self->xdir = (float)1.2;
16732 				self->damage_on_landing = 0;
16733 				toss(self, 2.5 + randf(1));
16734 				self->modeldata.no_adjust_base = 0;
16735 				self->modeldata.subject_to_wall = self->modeldata.subject_to_platform = self->modeldata.subject_to_hole = self->modeldata.subject_to_gravity = 1;
16736 				set_fall(self, ATK_NORMAL, 0, self, 100000, 0, 0, 0, 0, 0);
16737 			}
16738 		}
16739 	}
16740 	self->autokill |= self->ptype;
16741 	self->nextthink = time + THINK_SPEED / 2;
16742 	return 1;
16743 }
16744 
16745 // for common bomb types
bomb_move()16746 int bomb_move()
16747 {
16748 	if(inair(self) && self->toexplode == 1) {
16749 		if(self->direction == 0) self->xdir = -self->modeldata.speed;
16750 		else if(self->direction == 1) self->xdir = self->modeldata.speed;
16751 		self->nextthink = time + THINK_SPEED / 2;
16752 	}else if(self->takeaction != bomb_explode){
16753 
16754 		self->takeaction = bomb_explode;
16755 		self->tossv = 0;    // Stop moving up/down
16756 		self->modeldata.no_adjust_base = 1;    // Stop moving up/down
16757 		self->base = self->a;
16758 		self->xdir = self->zdir = 0;
16759 
16760 		if(self->modeldata.diesound >= 0) sound_play_sample(self->modeldata.diesound, 0, savedata.effectvol,savedata.effectvol, 100);
16761 
16762 		if(self->toexplode == 2 && validanim(self,ANI_ATTACK2))
16763 		{
16764 			ent_set_anim(self, ANI_ATTACK2, 0);    // If bomb never reaces the ground, play this
16765 		}
16766 		else
16767 		{
16768 			if (validanim(self,ANI_ATTACK1)) ent_set_anim(self, ANI_ATTACK1, 0);
16769 		}
16770 		// hit something, just make it an explosion animation.
16771 		self->modeldata.subject_to_wall = 0;
16772 		self->modeldata.subject_to_platform = 1;
16773 		self->modeldata.subject_to_hole = 0;
16774 	}
16775 	return 1;
16776 }
16777 
star_move()16778 int star_move(){
16779 	int wall;
16780 
16781 	if(self->x<advancex-80 || self->x>advancex+(videomodes.hRes+80) || (self->base<=0 && !self->modeldata.falldie)){
16782 		kill(self);
16783 		return 0;
16784 	}
16785 
16786 	self->base -= 2;
16787 	self->a = self->base;
16788 
16789 	if(validanim(self,ANI_FALL))    // Added so projectiles bounce off blocked exits
16790 	{
16791 		if((level->exit_blocked && self->x > level->width-30-(PLAYER_MAX_Z-self->z)) ||
16792 			((wall = checkwall(self->x, self->z)) >= 0 && self->a < level->walls[wall][7]))
16793 		{
16794 			self->takeaction = common_fall;
16795 			self->attacking = 0;
16796 			self->health = 0;
16797 			self->projectile = 0;
16798 			self->xdir = (self->direction)?(-1.2):1.2;
16799 			self->damage_on_landing = 0;
16800 			toss(self, 2.5 + randf(1));
16801 			set_fall(self, ATK_NORMAL, 0, self, 100000, 0, 0, 0, 0, 0);
16802 		}
16803 	}
16804 
16805 	if(self->landed_on_platform || self->base <= 0)
16806 	{
16807 		self->takeaction = common_lie;
16808 		self->health = 0;
16809 		if(self->modeldata.nodieblink == 2) self->animating = 0;
16810 	}
16811 
16812 	self->nextthink = time + THINK_SPEED / 2;
16813 	return 1;
16814 }
16815 
16816 
16817 //dispatch move patterns
16818 //root function for aimove
common_move()16819 int common_move()
16820 {
16821 	int aimove, makestop = 0, reachx, reachz;
16822 	int air = inair(self);
16823 	entity* other = NULL; //item
16824 	entity* target = NULL;//hostile target
16825 	entity* owner = NULL;
16826 	entity* ent = NULL;
16827 	int predir, stall;
16828 	int patx[5], pxc, px, patz[5], pzc, pz, fz; //move pattern in z and x
16829 
16830 	if(self->modeldata.aimove==-1) return 0; // invalid value
16831 
16832 	// get move pattern
16833 	aimove = self->modeldata.aimove & MASK_AIMOVE1;
16834 
16835 //if(stricmp(self->name, "os")==0) printf("%d\n", aimove);
16836 	// old and outdated patterns, but MUST be kept anyway
16837 	if(aimove&AIMOVE1_BIKER)
16838 	{// for biker subtype
16839 		return biker_move();
16840 	}
16841 	else if(aimove&AIMOVE1_ARROW)
16842 	{// for common straight-flying arrow
16843 		return arrow_move();
16844 	}
16845 	else if(aimove&AIMOVE1_STAR)
16846 	{// for a star, disappear when hit ground
16847 		return star_move();
16848 	}
16849 	else if(aimove&AIMOVE1_BOMB)
16850 	{// for a bomb, travel in a arc
16851 		return bomb_move();
16852 	}
16853 	else if(aimove&AIMOVE1_NOMOVE)
16854 	{// no move, just return
16855 		return 0;
16856 	}else{
16857 		// all above are special move patterns, real AI goes here:
16858 
16859 		 // skip if the entity is in air,
16860 		 // removing this and entity might be spawned walking in air
16861 		if(air) return 0;
16862 
16863 		// store this for turning checking
16864 		predir = self->direction;
16865 
16866 		// find all possible entities for target
16867 		// bad for optimization, but makes better sense
16868 		target = normal_find_target(-1,0); // confirm the target again
16869 		other = ((time/GAME_SPEED+self->health/3+self->sortid)%15<10)?normal_find_item():NULL;    // find an item
16870 		owner = self->parent;
16871 
16872 		// temporary solution to turn off running if xdir is not set
16873 		// unless one day vertical running logic is written
16874 		if(!self->xdir)
16875 				self->running = 0;
16876 
16877 		// change direction unless the ai pattern ignores target or model has noflip
16878 		if(!self->modeldata.noflip && !self->running && aimove!=AIMOVE1_WANDER){
16879 			if(other)   //try to pick up an item, if possible
16880 				self->direction = (self->x < other->x);
16881 			else if(target)
16882 				self->direction = (self->x < target->x);
16883 			else if(owner)
16884 				self->direction = (self->x < owner->x);
16885 		}else if(aimove==AIMOVE1_WANDER){
16886 			if(self->xdir) self->direction = (self->xdir>0);
16887 		}
16888 
16889 		//turn back if we have a turn animation
16890 		// TODO, make a function for ai script
16891 		if(self->direction != predir && validanim(self,ANI_TURN)){
16892 			self->takeaction = common_turn;
16893 			self->direction = !self->direction;
16894 			self->xdir = self->zdir = 0;
16895 			ent_set_anim(self, ANI_TURN, 0);
16896 			return 1;
16897 		}
16898 
16899 		//pick up the item if possible
16900 		if(other && diff(other->x,self->x)<(self->modeldata.grabdistance*0.83333)
16901 			&& diff(other->z,self->z)<(self->modeldata.grabdistance/3) &&
16902 			other->animation->vulnerable[other->animpos])//won't pickup an item that is not previous one
16903 		{
16904 			if(diff(self->base, other->a)<0.1){
16905 				common_pickupitem(other);
16906 				return 1;
16907 			}
16908 		}
16909 
16910 		if(self->modeldata.nomove) {
16911 			self->idling = 1;
16912 			return 1;
16913 		}
16914 
16915 		if(common_try_jump()) {
16916 			self->numwaypoints = 0;
16917 			return 1;  //need to jump? so quit
16918 		}
16919 
16920 		if(checkpathblocked()) return 1; // handle path blocked logic
16921 
16922 		// judge next move if stalltime is expired
16923 		// skip if waypoints presents (passive move)
16924 		if(self->stalltime < time && !self->waypoints){
16925 			if(other){
16926 				// try walking to the item
16927 				common_try_pick(other);
16928 				ent = other;
16929 			}else{
16930 				if(target && (self->modeldata.subtype == SUBTYPE_CHASE ||
16931 				(self->modeldata.type == TYPE_NPC && self->parent)))
16932 					// try chase a target
16933 					aimove |= AIMOVE1_CHASE;
16934 
16935 				if(aimove & AIMOVE1_CHASE) aimove |= AIMOVE1_CHASEX|AIMOVE1_CHASEZ;
16936 				if(aimove & AIMOVE1_AVOID) aimove |= AIMOVE1_AVOIDX|AIMOVE1_AVOIDZ;
16937 
16938 				if(other!=ent) self->xdir = self->zdir = 0;
16939 
16940 				if(!aimove && target){
16941 					common_try_wander(target, 1, 1);
16942 					ent = target;
16943 				} else if (target){
16944 					ent = target;
16945 					pxc = pzc = 0;
16946 
16947 					if(aimove&AIMOVE1_WANDER) {
16948 						patx[pxc++] = AIMOVE1_WANDER;
16949 						patx[pxc++] = AIMOVE1_WANDER;
16950 						patz[pzc++] = AIMOVE1_WANDER;
16951 						patz[pzc++] = AIMOVE1_WANDER;
16952 					}
16953 					if(aimove&AIMOVE1_CHASEX) {
16954 						patx[pxc++] = AIMOVE1_CHASEX;
16955 					}
16956 					if(aimove&AIMOVE1_AVOIDX) {
16957 						patx[pxc++] = AIMOVE1_AVOIDX;
16958 					}
16959 					if(aimove&AIMOVE1_CHASEZ) {
16960 						patz[pzc++] = AIMOVE1_CHASEZ;
16961 					}
16962 					if(aimove&AIMOVE1_AVOIDZ) {
16963 						patz[pzc++] = AIMOVE1_AVOIDZ;
16964 					}
16965 					if(!pxc) {
16966 						patx[pxc++] = AIMOVE1_WANDER;
16967 					}
16968 					if(!pzc) {
16969 						patz[pzc++] = AIMOVE1_WANDER;
16970 					}
16971 					px = patx[(rand32()&0xff)%pxc];
16972 					pz = patz[(rand32()&0xff)%pzc];
16973 
16974 					fz = 0;
16975 
16976 					aimove = (self->modeldata.aimove & MASK_AIMOVE1);
16977 
16978 					//valid types: avoidx, aviodz, chasex, chasez, wander
16979 					if(px==AIMOVE1_WANDER){
16980 						if (pz==AIMOVE1_WANDER && aimove==AIMOVE1_WANDER) {
16981 							common_try_wandercompletely(1, 1);
16982 							fz = 1;
16983 						}else common_try_wander(target, 1, 0);
16984 
16985 					}else if(px==AIMOVE1_CHASEX){
16986 						common_try_chase(target, 1, (pz==AIMOVE1_CHASEZ));
16987 						fz = (pz==AIMOVE1_CHASEZ);
16988 					}else if (px==AIMOVE1_AVOIDX){
16989 						common_try_avoid(target, 1, (pz==AIMOVE1_AVOIDZ));
16990 						fz = (pz==AIMOVE1_AVOIDZ);
16991 					}
16992 					if(!fz){
16993 						if(pz==AIMOVE1_WANDER)
16994 							common_try_wander(target, 0, 1);
16995 						else if(pz==AIMOVE1_CHASEZ)
16996 							common_try_chase(target, 0, 1);
16997 						else if (pz==AIMOVE1_AVOIDZ)
16998 							common_try_avoid(target, 0, 1);
16999 					}
17000 
17001 				}else if(!common_try_follow(owner, 1, 1) && !(self->modeldata.aimove&AIMOVE2_NOTARGETIDLE) ){
17002 					common_try_wandercompletely(1, 1);
17003 					ent = NULL;
17004 				}else{
17005 					ent = owner;
17006 				}
17007 			}
17008 			//end of if
17009 
17010 		}//if(self->stalltime < time )
17011 		else
17012 		{
17013 			ent = other;
17014 			if(!ent) ent = target;
17015 			if(!ent) ent = owner;
17016 		}
17017 		if(self->numwaypoints==0 && self->waypoints){
17018 			free(self->waypoints);
17019 			self->waypoints = NULL;
17020 		}
17021 
17022 		//fix 2d level panic, or should this be moved to the very beginning?
17023 		if(self->modeldata.subject_to_minz>0 && self->destz<PLAYER_MIN_Z) self->destz = PLAYER_MIN_Z;
17024 		if(self->modeldata.subject_to_maxz>0 && self->destz>PLAYER_MAX_Z) self->destz = PLAYER_MAX_Z;
17025 
17026 		// don't run in passive move mode. The path could be complex and running may look bad.
17027 		if(self->waypoints) self->running = 0;
17028 
17029 		if(self->direction==(self->destx<self->x)) self->running = 0;
17030 
17031 		// make the entity walks in a straight path instead of flickering here and there
17032 		// acceleration can be added easily based on this logic, if necessary
17033 		adjustspeed(self->running?self->modeldata.runspeed:self->modeldata.speed, self->x, self->z, self->destx, self->destz, &self->xdir, &self->zdir);
17034 
17035 		// fix running animation, if the model doesn't allow running updown then set zdir to 0
17036 		if(self->running && !self->modeldata.runupdown) {
17037 			self->zdir = 0;
17038 			self->destz = self->z;
17039 		}
17040 
17041 		// check destination point to make a stop or pop a waypoint from the stack
17042 		reachx = (diff(self->x, self->destx)<MAX(1,ABS(self->xdir)));
17043 		reachz = (diff(self->z, self->destz)<MAX(1,ABS(self->zdir)));
17044 
17045 		// check destination point to make a stop or pop a waypoint from the stack
17046 		if(reachx&&reachz){
17047 			if(self->waypoints && self->numwaypoints){
17048 				self->destx = self->waypoints[self->numwaypoints-1].x;
17049 				self->destz = self->waypoints[self->numwaypoints-1].z;
17050 				self->numwaypoints--;
17051 			}else if(self->xdir || self->zdir) makestop = 1;
17052 		}
17053 
17054 		if(!self->waypoints || !self->numwaypoints){
17055 			if(reachx) {self->xdir=0; self->destx=self->x;}
17056 			if(reachz) {self->zdir=0; self->destz=self->z;}
17057 		}
17058 
17059 		// stoped so play idle, preventinng funny stepping bug, but may cause flickering
17060 		if(!self->xdir && !self->zdir && !self->waypoints){
17061 			set_idle(self);
17062 			if(makestop){
17063 				stall = (GAME_SPEED - self->modeldata.aggression)/2;
17064 				if(stall<GAME_SPEED/5) stall = GAME_SPEED/5;
17065 				self->stalltime = time + MAX(0,stall);
17066 			}
17067 		}else{
17068 			// readjust walk animation
17069 			adjust_walk_animation(ent);
17070 			// give proper stalltime if destination point is not reached
17071 			// if the destination point is not reachable,
17072 			// it should be already handled in checkpathblocked
17073 			if(time>self->stalltime){
17074 				if(ABS(self->xdir)>ABS(self->zdir)) stall = diff(self->destx, self->x)/ABS(self->xdir)*2;
17075 				else if(self->zdir) stall = diff(self->destz, self->z)/ABS(self->zdir)*2;
17076 				else stall = GAME_SPEED/2;
17077 				self->stalltime = time + MAX(0,stall);
17078 			}
17079 		}
17080 
17081 		//target is moving?  readjust destination sooner
17082 		if(aimove!=AIMOVE1_WANDER && !self->waypoints && ent && (self->xdir || self->zdir) && (ent->xdir || ent->zdir)){
17083 			 if(self->running && self->stalltime>time + GAME_SPEED/2)
17084 				self->stalltime = time + GAME_SPEED/2;
17085 			 else if(!self->running && self->stalltime>time + GAME_SPEED/5)
17086 				self->stalltime = time + GAME_SPEED/5;
17087 		}
17088 
17089 		return 1;
17090 
17091 	}
17092 
17093 	return 1;
17094 }
17095 
17096 
decide_stalker()17097 void decide_stalker(){
17098 	entity* ent, *furthest = NULL;
17099 	int i;
17100 	int l = 0, r=0;
17101 	float maxz= 0.0f, z;
17102 
17103 	if(stalker && stalking) return;
17104 
17105 	firstplayer = NULL;
17106 
17107 	for(i=0; i<4; i++){
17108 		if(player[i].ent){
17109 			firstplayer = player[i].ent;
17110 			break;
17111 		}
17112 	}
17113 
17114 	if(!firstplayer) return;
17115 
17116 	for(i=0; i<ent_max; i++){
17117 		ent = ent_list[i];
17118 
17119 		if(ent->exists && !ent->dead && ent->modeldata.type == TYPE_ENEMY ){
17120 			if(ent->x>firstplayer->x) r++;
17121 			else l++;
17122 
17123 			if((z=diff(ent->z, firstplayer->z))>=maxz &&
17124 				(ent->modeldata.aimove==0 || (ent->modeldata.aimove&AIMOVE1_CHASE))){ // 2 mostly used type
17125 				maxz = z;
17126 				furthest = ent;
17127 			}
17128 		}
17129 	}
17130 
17131 	if((l>1 && !r) || (r>1 && !l)){
17132 		stalker = furthest;
17133 		//printf("** stalker decided: %s @ time %d\n", stalker->name, time);
17134 	}
17135 }
17136 
17137 
plan()17138 void plan(){
17139 	decide_stalker();
17140 }
17141 
checkstalker()17142 void checkstalker(){
17143 	float maxspeed;
17144 	int running;
17145 
17146 	if(self!=stalker) return;
17147 
17148 	if(!firstplayer) {
17149 		stalker = NULL;
17150 		return;
17151 	}
17152 
17153 	if(stalking){
17154 		if(self->stalltime<=time){
17155 			//printf("** stalk time expired: %s @ time %d\n", stalker->name, time);
17156 			stalker = NULL;
17157 		}
17158 		return;
17159 	}
17160 
17161 	running = validanim(self,ANI_RUN);
17162 
17163 	maxspeed = running?self->modeldata.runspeed:self->modeldata.speed;
17164 
17165 	self->xdir = maxspeed;
17166 	self->zdir = 0;
17167 
17168 	if(self->x>firstplayer->x) self->xdir = -self->xdir;
17169 
17170 	self->running = running;
17171 
17172 
17173 	self->stalltime = time + (diff(self->x, firstplayer->x) + 150)/maxspeed*THINK_SPEED;
17174 
17175 	adjust_walk_animation(firstplayer);
17176 
17177 	stalking = 1;
17178 	//printf("**start stalking: %s @ time %d till @%d\n", stalker->name, time, self->stalltime);
17179 }
17180 
checkplanned()17181 int checkplanned(){
17182 	return 0;
17183 }
17184 
17185 
ai_check_warp()17186 int ai_check_warp(){
17187 	if(self->link) return 0;
17188 
17189 	if(self->modeldata.subtype == SUBTYPE_FOLLOW && self->parent &&
17190 		(diff(self->z, self->parent->z) > self->modeldata.animation[ANI_IDLE]->range.xmax ||
17191 		diff(self->x, self->parent->x) > self->modeldata.animation[ANI_IDLE]->range.xmax) )
17192 	{
17193 		self->takeaction = npc_warp;
17194 		return 1;
17195 	}
17196 	return 0;
17197 }
17198 
ai_check_lie()17199 int ai_check_lie(){
17200 	if(self->drop && self->a==self->base && !self->tossv && validanim(self,ANI_RISEATTACK) && ((rand32()%(self->stalltime-time+1)) < 3) && (self->health >0 && time > self->staydown.riseattack_stall))
17201 	{
17202 		common_try_riseattack();
17203 		return 1;
17204 	}
17205 	return 0;
17206 }
17207 
ai_check_grabbed()17208 int ai_check_grabbed(){
17209 	if(self->link && !self->grabbing && !self->inpain && self->takeaction!=common_prethrow && !inair(self) &&
17210 	   time >= self->stalltime && validanim(self,ANI_SPECIAL))
17211 	{
17212 		check_special();
17213 		return 1;
17214 	}
17215 	return 0;
17216 }
17217 
ai_check_grab()17218 int ai_check_grab(){
17219 	if(self->grabbing && !self->attacking)
17220 	{
17221 		common_grab_check();
17222 		return 1;
17223 	}
17224 	return 0;
17225 }
ai_check_escape()17226 int ai_check_escape(){
17227 	if((self->escapecount > self->modeldata.escapehits) && !inair(self) && validanim(self,ANI_SPECIAL2))
17228 	{
17229 		// Counter the player!
17230 		check_costmove(ANI_SPECIAL2, 0, 0);
17231 		return 1;
17232 	}
17233 	return 0;
17234 }
17235 
ai_check_busy()17236 int ai_check_busy(){
17237 	return self->link || !self->idling;
17238 }
17239 
17240 
17241 // A.I root
common_think()17242 void common_think()
17243 {
17244 
17245 	if(self->dead) return;
17246 
17247 	//if(checkplanned()) return;
17248 
17249 	// too far away , do a warp
17250 	if(ai_check_warp()) return;
17251 
17252 	// rise? try rise attack
17253 	if(ai_check_lie()) return;
17254 
17255 	// Escape?
17256 	if(ai_check_grabbed()) return;
17257 
17258 	//grabbing something
17259 	if(ai_check_grab()) return;
17260 
17261 	// Enemies can now escape non-knockdown spammage (What a weird phrase)!
17262 	if(ai_check_escape()) return;
17263 
17264 	// busy right now?
17265 	if(ai_check_busy()) return;
17266 
17267 	// idle, so try to attack or judge next move
17268 	// dont move if fall into a hole or off a wall
17269    if(common_attack()) return;
17270    common_move();
17271 }
17272 
17273 //////////////////////////////////////////////////////////////////////////
17274 
suicide()17275 void suicide()
17276 {
17277 	if(time < self->stalltime) return;
17278 	level_completed |= self->boss;
17279 	kill(self);
17280 }
17281 
17282 
17283 
17284 // Re-enter playfield
17285 // Used by player_fall and player_takedamage
player_die()17286 void player_die()
17287 {
17288 	int playerindex = self->playerindex;
17289 	if(!livescheat) --player[playerindex].lives;
17290 
17291 	if(firstplayer==self) firstplayer = NULL;
17292 
17293 	execute_pdie_script(playerindex);
17294 
17295 	if(nomaxrushreset[4] >= 1) nomaxrushreset[playerindex] = player[playerindex].ent->rush[1];
17296 	player[playerindex].ent = NULL;
17297 	player[playerindex].spawnhealth = self->modeldata.health;
17298 	player[playerindex].spawnmp = self->modeldata.mp;
17299 
17300 
17301 	if(self->modeldata.nodieblink != 3) kill(self);
17302 	else
17303 	{
17304 		self->think = NULL;
17305 		self->takeaction = NULL;
17306 		self->modeldata.type = TYPE_NONE;
17307 	}
17308 
17309 	if(player[playerindex].lives <= 0)
17310 	{
17311 		if(!player[0].ent && !player[1].ent && !player[2].ent && !player[3].ent)
17312 		{
17313 			timeleft = 10 * COUNTER_SPEED;
17314 			if((!noshare && credits < 1) || (noshare && player[0].credits < 1 && player[1].credits < 1 && player[2].credits <1 && player[3].credits <1)) timeleft = COUNTER_SPEED/2;
17315 		}
17316 		if(self->modeldata.weaploss[0]<=3) player[playerindex].weapnum = level->setweap;
17317 		if(nomaxrushreset[4] != 2) nomaxrushreset[playerindex] = 0;
17318 		return;
17319 	}
17320 	else
17321 	{
17322 		spawnplayer(playerindex);
17323 		execute_respawn_script(playerindex);
17324 		if(!nodropen)
17325 		{
17326 			control_rumble(playerindex, 125);
17327 			drop_all_enemies();
17328 		}
17329 	}
17330 
17331 	if(!level->noreset) timeleft = level->settime * COUNTER_SPEED;    // Feb 24, 2005 - This line moved here to set custom time
17332 
17333 }
17334 
17335 
17336 
player_trymove(float xdir,float zdir)17337 int player_trymove(float xdir, float zdir)
17338 {
17339 	return common_trymove(xdir, zdir);
17340 }
17341 
check_energy(int which,int ani)17342 int check_energy(int which, int ani)
17343 {
17344 	int iCost[3];																//0 = energycost.cost (amount of HP or MP needed), 1 = Cost type (MP, HP, both), 2 = Disable flag.
17345 	int iType;																	//Entity type.
17346 
17347 	if(self->modeldata.animation[ani])											//Does animation exist?
17348 	{
17349 		iCost[2]	= self->modeldata.animation[ani]->energycost.disable;		//Get disable flag.
17350 		iType		= self->modeldata.type;										//Get entity type.
17351 
17352 		/* DC 05082010: It is now possible to individualy disable specials. In
17353 		many cases (weapons in particular) this can	help cut down the need for
17354 		superflous models when differing abilities are desired for players,
17355 
17356 		enemies, or npcs. */
17357 		if(!(iCost[2]==iType													//Disabled by type?
17358 			|| (iCost[2]==-1)													//Disabled for all?
17359 			|| (iCost[2]==-2 && (iType == TYPE_ENEMY || iType == TYPE_NPC))		//Disabled for all AI?
17360 			|| (iCost[2]==-3 && (iType == TYPE_PLAYER || iType == TYPE_NPC))	//Disabled for players & NPCs?
17361 			|| (iCost[2]==-4 && (iType == TYPE_PLAYER || iType == TYPE_ENEMY))))//Disabled for all AI?
17362 		{
17363 			iCost[0] = self->modeldata.animation[ani]->energycost.cost;			//Get energy cost amount
17364 			iCost[1] = self->modeldata.animation[ani]->energycost.mponly;		//Get energy cost type.
17365 
17366 			if(!self->seal || self->seal >= iCost[0])							//No seal or seal is less/same as energy cost?
17367 			{
17368 				if(validanim(self,ani) &&										//Validate the animation one more time.
17369 						((which &&												//Check magic validity
17370 						(iCost[1] != 2) &&										//2 = From health bar only, 0 from both
17371 						(self->mp >= iCost[0])) ||
17372 						(!which &&												//Checks health validity
17373 						(iCost[1] != 1) &&										//1 = From magic bar only, 0 from both
17374 						(self->health > iCost[0]))))
17375 				{
17376 					return 1;
17377 				}
17378 				else
17379 				{
17380 					//DC 01232009
17381 					//Tried putting the CANT animation here to keep code compacted, but won't work. I'll come back to this.
17382 					//if (validanim(self,ani)){
17383 					//    ent_set_anim(self, ANI_CANT, 0);
17384 					//    self->takeaction = common_attack_proc;
17385 					//    player[self->playerindex].playkeys = 0;
17386 					//}
17387 					return 0;
17388 				}
17389 			}
17390 		}
17391 	}
17392 	return 0;
17393 }
17394 
17395 
check_special()17396 int check_special()
17397 {
17398 	entity* e;
17399 	if((!level->nospecial || level->nospecial == 3) &&
17400 	   !self->cantfire &&
17401 	   (check_energy(0, ANI_SPECIAL) ||
17402 		check_energy(1, ANI_SPECIAL)))
17403 	{
17404 		self->takeaction = common_attack_proc;
17405 		set_attacking(self);
17406 		memset(self->combostep, 0, sizeof(int)*5);
17407 
17408 		e = self->link;
17409 		if(e){
17410 			e->takeaction = NULL;
17411 			ent_unlink(self);
17412 			set_idle(e);
17413 		}
17414 
17415 		if(self->modeldata.smartbomb && !self->modeldata.dofreeze)
17416 		{
17417 			smart_bomb(self, self->modeldata.smartbomb); // do smartbomb immediately if it doesn't freeze screen
17418 		}
17419 
17420 		self->running = 0;    // If special is executed while running, ceases to run
17421 		self->xdir = self->zdir = 0;
17422 		ent_set_anim(self, ANI_SPECIAL, 0);
17423 
17424 		if(self->modeldata.dofreeze) smartbomber = self;    // Freezes the animations of all enemies/players while special is executed
17425 
17426 		if(!nocost && !healthcheat)
17427 		{
17428 			if(check_energy(1, ANI_SPECIAL)) self->mp -= self->modeldata.animation[ANI_SPECIAL]->energycost.cost;
17429 			else self->health -= self->modeldata.animation[ANI_SPECIAL]->energycost.cost;
17430 		}
17431 
17432 		return 1;
17433 	}
17434 	return 0;
17435 }
17436 
17437 
17438 // Check keys for special move. Used several times, so I func'd it.
17439 // 1-10-05 changed self->health>6 to self->health > self->modeldata.animation[ANI_SPECIAL]->energycost.cost
player_check_special()17440 int player_check_special()
17441 {
17442 	u32 thekey = 0;
17443 	if((!ajspecial || (ajspecial && !validanim(self,ANI_BLOCK))) &&
17444 		(player[self->playerindex].playkeys & FLAG_SPECIAL))
17445 	{
17446 		thekey = FLAG_SPECIAL;
17447 	}
17448 	else if(ajspecial && ((player[self->playerindex].playkeys & FLAG_JUMP) &&
17449 		(player[self->playerindex].keys & FLAG_ATTACK)))
17450 	{
17451 		thekey = FLAG_JUMP;
17452 	}
17453 	else return 0;
17454 
17455 	if(check_special())
17456 	{
17457 		self->stalltime = 0;
17458 		player[self->playerindex].playkeys -= thekey;
17459 		return 1;
17460 	}else{
17461 		return 0;
17462 	}
17463 }
17464 
17465 
common_land()17466 void common_land()
17467 {
17468 	self->xdir = self->zdir = 0;
17469 	if(self->animating) return;
17470 
17471 	self->takeaction = NULL;
17472 	set_idle(self);
17473 }
17474 
17475 
17476 //animal run when you lost it 3 times by tails
runanimal()17477 void runanimal()
17478 {
17479 	common_walk_anim(self);
17480 	//ent_set_anim(self, ANI_WALK, 0);
17481 
17482 	if(self->x < advancex - 80 || self->x > advancex + (videomodes.hRes+80)){
17483 		kill(self);
17484 		return;
17485 	}
17486 
17487 	if(self->direction) self->x += self->modeldata.speed;
17488 	else self->x -= self->modeldata.speed;
17489 }
17490 
17491 
player_blink()17492 void player_blink()
17493 {
17494 	self->blink = 1;
17495 	if(time >= self->stalltime) player_die();
17496 }
17497 
17498 
common_grabattack()17499 void common_grabattack()
17500 {
17501 	if(self->animating) return;
17502 
17503 	self->attacking = 0;
17504 
17505 	if(!(self->combostep[0] || self->combostep[1] ||
17506 		 self->combostep[2] || self->combostep[3] ||
17507 		 self->combostep[4]))
17508 	{
17509 		ent_unlink(self);
17510 	}
17511 
17512 	if(self->link)
17513 	{
17514 		self->takeaction = common_grab;
17515 		self->link->takeaction = common_grabbed;
17516 		self->attacking = 0;
17517 		ent_set_anim(self, ANI_GRAB, 0);
17518 		set_pain(self->link, -1, 0);
17519 		update_frame(self, self->animation->numframes-1);
17520 		update_frame(self->link, self->link->animation->numframes-1);
17521 	}
17522 	else
17523 	{
17524 		self->takeaction = NULL;
17525 		memset(self->combostep, 0, sizeof(int)*5);
17526 		set_idle(self);
17527 	}
17528 }
17529 
17530 // The vault.
common_vault()17531 void common_vault()
17532 {
17533 	if(!self->link)
17534 	{
17535 		self->takeaction = NULL;
17536 		set_idle(self);
17537 		return;
17538 	}
17539 	if(!self->animating)
17540 	{
17541 		self->takeaction = common_grab;
17542 		self->link->takeaction = common_grabbed;
17543 		self->attacking = 0;
17544 		self->direction = !self->direction;
17545 		self->a = self->base = self->link->base;
17546 
17547 		if(self->direction) self->x = self->link->x - self->modeldata.grabdistance;
17548 		else self->x = self->link->x + self->modeldata.grabdistance;
17549 
17550 		ent_set_anim(self, ANI_GRAB, 0);
17551 		set_pain(self->link, -1, 0);
17552 		update_frame(self, self->animation->numframes-1);
17553 		update_frame(self->link, self->link->animation->numframes-1);
17554 		return;
17555 	}
17556 }
17557 
17558 // Function that causes the player to continue to move up or down until the animation has finished playing
common_dodge()17559 void common_dodge()    // New function so players can dodge with up up or down down
17560 {
17561 	if(self->animating)    // Continues to move as long as the player is animating
17562 	{
17563 		return;
17564 	}
17565 	else    // Once done animating, returns to thinking
17566 	{
17567 		self->takeaction = NULL;
17568 		self->xdir = self->zdir = 0;
17569 		set_idle(self);
17570 	}
17571 }
17572 
17573 
common_prejump()17574 void common_prejump()
17575 {
17576 	if(self->animating) return;
17577 	dojump(self->jumpv, self->jumpx, self->jumpz, self->jumpid);
17578 }
17579 
tryjump(float jumpv,float jumpx,float jumpz,int jumpid)17580 void tryjump(float jumpv, float jumpx, float jumpz, int jumpid)
17581 {
17582 	self->jumpv = jumpv;              self->jumpx = jumpx;
17583 	self->jumpz = jumpz;              self->jumpid = jumpid;
17584 	if(validanim(self,ANI_JUMPDELAY))
17585 	{
17586 		self->takeaction = common_prejump;
17587 		self->xdir = self->zdir = 0;
17588 
17589 		self->idling = 0;
17590 		ent_set_anim(self, ANI_JUMPDELAY, 0);
17591 	}
17592 	else
17593 	{
17594 		dojump(jumpv, jumpx, jumpz, jumpid);
17595 	}
17596 }
17597 
17598 
dojump(float jumpv,float jumpx,float jumpz,int jumpid)17599 void dojump(float jumpv, float jumpx, float jumpz, int jumpid)
17600 {
17601 	entity* dust;
17602 
17603 	self->takeaction = common_jump;
17604 
17605 	if(SAMPLE_JUMP >= 0) sound_play_sample(SAMPLE_JUMP, 0, savedata.effectvol,savedata.effectvol, 100);
17606 
17607 	//Spawn jumpstart dust.
17608 	if(self->modeldata.dust[2]>=0)
17609 	{
17610 		dust = spawn(self->x, self->z, self->a, self->direction, NULL, self->modeldata.dust[2], NULL);
17611 		if(dust){
17612 			dust->base = self->a;
17613 			dust->autokill = 2;
17614 			execute_onspawn_script(dust);
17615 		}
17616 	}
17617 
17618 	set_jumping(self);
17619 
17620 	toss(self, jumpv);
17621 
17622 	if(self->direction == 0)
17623 		self->xdir = -jumpx;
17624 	else self->xdir = jumpx;
17625 
17626 	self->zdir = jumpz;
17627 	ent_set_anim(self, jumpid, 0);
17628 }
17629 
17630 // Function created to combine the action taken if either picking up an item, or running into an item that is a
17631 // SUBTYPE_TOUCH, executing the appropriate action based on which type of item is picked up
didfind_item(entity * other)17632 void didfind_item(entity *other)
17633 {    // Function that takes care of items when picked up
17634 	set_opponent(self, other);
17635 
17636 	//for reload weapons that are guns(no knife) we use this items reload for ours shot at max and shootnum in items for get a amount of shoots by tails
17637 	if(other->modeldata.reload)
17638 	{
17639 		if(self->weapent && self->weapent->modeldata.typeshot)
17640 		{
17641 			self->weapent->modeldata.shootnum += other->modeldata.reload;
17642 			if(self->weapent->modeldata.shootnum > self->weapent->modeldata.shootnum) self->weapent->modeldata.shootnum = self->weapent->modeldata.shootnum;
17643 			if(SAMPLE_GET >= 0) sound_play_sample(SAMPLE_GET, 0, savedata.effectvol,savedata.effectvol, 100);
17644 		}
17645 		else
17646 		{
17647 			addscore(self->playerindex, other->modeldata.score);
17648 			if(SAMPLE_GET2 >= 0) sound_play_sample(SAMPLE_GET2, 0, savedata.effectvol,savedata.effectvol, 100);
17649 		}
17650 	}
17651 	//end of weapons items section
17652 	else if(other->modeldata.score)
17653 	{
17654 		addscore(self->playerindex, other->modeldata.score);
17655 		if(SAMPLE_GET2 >= 0) sound_play_sample(SAMPLE_GET2, 0, savedata.effectvol,savedata.effectvol, 100);
17656 	}
17657 	else if(other->health)
17658 	{
17659 		self->health += other->health;
17660 
17661 		if(self->health > self->modeldata.health) self->health = self->modeldata.health;
17662 
17663 		other->health = 0;
17664 
17665 		if(SAMPLE_GET >= 0) sound_play_sample(SAMPLE_GET, 0, savedata.effectvol,savedata.effectvol, 100);
17666 	}
17667 	else if(other->modeldata.mp)
17668 	{
17669 		self->mp += other->modeldata.mp;
17670 
17671 		if(self->mp > self->modeldata.mp) self->mp = self->modeldata.mp;
17672 
17673 		other->mp = 0;
17674 		sound_play_sample(SAMPLE_GET, 0, savedata.effectvol,savedata.effectvol, 100);
17675 	}
17676 	else if(stricmp(other->modeldata.name, "Time")==0)
17677 	{
17678 		timeleft = level->settime * COUNTER_SPEED;    // Feb 24, 2005 - This line moved here to set custom time
17679 
17680 		if(SAMPLE_GET2 >= 0) sound_play_sample(SAMPLE_GET2, 0, savedata.effectvol,savedata.effectvol, 100);
17681 	}
17682 	else if(other->modeldata.makeinv)
17683 	{    // Mar 2, 2005 - New item makes player invincible
17684 		self->invincible = 1;
17685 		self->invinctime = time + ABS(other->modeldata.makeinv);
17686 		self->blink = (other->modeldata.makeinv>0);
17687 
17688 		if(SAMPLE_GET2 >= 0) sound_play_sample(SAMPLE_GET2, 0, savedata.effectvol,savedata.effectvol, 100);
17689 	}
17690 	else if(other->modeldata.smartbomb)
17691 	{    // Damages everything on the screen
17692 		smart_bomb(self, other->modeldata.smartbomb);
17693 
17694 		if(SAMPLE_GET2 >= 0) sound_play_sample(SAMPLE_GET2, 0, savedata.effectvol,savedata.effectvol, 100);
17695 	}
17696 	else if(other->modeldata.subtype == SUBTYPE_WEAPON)
17697 	{
17698 		dropweapon(0);
17699 		self->weapent = other;
17700 		set_weapon(self, other->modeldata.weapnum, 0);
17701 
17702 		if(self->modeldata.animal)  // UTunnels: well, ride, not get. :)
17703 		{
17704 			self->direction = other->direction;
17705 			self->x = other->x;
17706 			self->z = other->z;
17707 		}
17708 
17709 		if(!other->modeldata.typeshot && self->modeldata.typeshot) other->modeldata.typeshot = 1;
17710 
17711 		if(SAMPLE_GET >= 0) sound_play_sample(SAMPLE_GET, 0, savedata.effectvol,savedata.effectvol, 100);
17712 	}
17713 	else if(other->modeldata.subtype == SUBTYPE_PROJECTILE)
17714 	{
17715 		dropweapon(0);
17716 		self->weapent = other;
17717 
17718 		if(SAMPLE_GET >= 0) sound_play_sample(SAMPLE_GET, 0, savedata.effectvol,savedata.effectvol, 100);
17719 	}
17720 	else if(other->modeldata.credit)
17721 	{
17722 		if(!noshare) credits++;
17723 		else player[self->playerindex].credits++;
17724 
17725 		if(SAMPLE_1UP >= 0) sound_play_sample(SAMPLE_1UP, 0, savedata.effectvol,savedata.effectvol, 100);
17726 	}
17727 	else
17728 	{
17729 		// Must be a 1up then.
17730 		player[self->playerindex].lives++;
17731 
17732 		if(SAMPLE_1UP >= 0) sound_play_sample(SAMPLE_1UP, 0, savedata.effectvol,savedata.effectvol, 100);
17733 	}
17734 
17735 	if(other->modeldata.subtype != SUBTYPE_WEAPON && other->modeldata.subtype != SUBTYPE_PROJECTILE)
17736 	{
17737 		other->takeaction = suicide;
17738 		if(!other->modeldata.instantitemdeath)
17739 			 other->nextthink = time + GAME_SPEED * 3;
17740 	} else {
17741 		other->nextthink = other->nextanim = time + GAME_SPEED*999999;
17742 	}
17743 	other->z = 100000;
17744 }
17745 
player_fall_check()17746 void player_fall_check()
17747 {
17748 	if(autoland != 2 && (player[self->playerindex].keys & (FLAG_MOVEUP|FLAG_JUMP)) == (FLAG_MOVEUP|FLAG_JUMP))
17749 	{
17750 		self->damage_on_landing=-2; // mark it, so we will play land animation when hit the ground
17751 	}
17752 }
17753 
player_grab_check()17754 void player_grab_check()
17755 {
17756 	entity * other = self->link;
17757 
17758 	if(other == NULL || (self->modeldata.grabfinish && self->animating && !self->grabwalking)) return;
17759 
17760 	if(self->base != other->base)
17761 	{       // Change this from ->a to ->base
17762 		self->takeaction = NULL;
17763 		ent_unlink(self);
17764 		set_idle(self);
17765 		return;
17766 	}
17767 
17768 	if(player_check_special()) return;
17769 
17770 	if(!nolost && self->modeldata.weaploss[0] <= 0) dropweapon(1);
17771 
17772 	// grabturn code
17773 	if(self->animation == self->modeldata.animation[ANI_GRABTURN])
17774 	{
17775 		// still turning? don't bother with anything else
17776 		if(self->animating) return;
17777 
17778 		// done turning? switch directions and return to grab animation
17779 		else
17780 		{
17781 			if(self->direction)
17782 			{
17783 				self->direction = 0;
17784 				other->direction = 1;
17785 			}
17786 			else
17787 			{
17788 				self->direction = 1;
17789 				other->direction = 0;
17790 			}
17791 			other->x = self->x + (((self->direction * 2) - 1) * self->modeldata.grabdistance);
17792 			ent_set_anim(self, ANI_GRAB, 0);
17793 			set_pain(other, -1, 0);
17794 			update_frame(self, self->animation->numframes-1);
17795 			update_frame(other, other->animation->numframes-1);
17796 		}
17797 	}
17798 
17799 	self->attacking = 0; //for checking
17800 	self->grabwalking = 0;
17801 	if(self->direction ?
17802 		(player[self->playerindex].keys & FLAG_MOVELEFT) :
17803 		(player[self->playerindex].keys & FLAG_MOVERIGHT))
17804 	{
17805 		// initiating grabturn
17806 		if(self->modeldata.grabturn)
17807 		{
17808 				// start animation if it exists...
17809 				if(validanim(self,ANI_GRABTURN))
17810 				{
17811 					ent_set_anim(self, ANI_GRABTURN, 0);
17812 					if(validanim(other,ANI_GRABBEDTURN)) ent_set_anim(other, ANI_GRABBEDTURN, 0);
17813 					else if(validanim(other,ANI_GRABBED)) ent_set_anim(other, ANI_GRABBED, 0);
17814 					else ent_set_anim(other, ANI_PAIN, 0);
17815 					other->xdir = other->zdir = self->xdir = self->zdir = 0;
17816 					other->x = self->x;
17817 					return;
17818 				}
17819 
17820 				// otherwise, just turn around
17821 				else
17822 				{
17823 					if(self->direction)
17824 					{
17825 						self->direction = 0;
17826 						other->direction = 1;
17827 					}
17828 					else
17829 					{
17830 						self->direction = 1;
17831 						other->direction = 0;
17832 					}
17833 					ent_set_anim(self, ANI_GRAB, 0);
17834 					set_pain(other, -1, 0);
17835 					update_frame(self, self->animation->numframes-1);
17836 					update_frame(other, other->animation->numframes-1);
17837 					other->x = self->x + (((self->direction * 2) - 1) * self->modeldata.grabdistance);
17838 				}
17839 		}
17840 		else if(!validanim(self,ANI_GRABWALK) && time > self->releasetime)
17841 		{
17842 			// Release
17843 			self->takeaction = NULL;
17844 			ent_unlink(self);
17845 			set_idle(self);
17846 			return;
17847 		}
17848 	}
17849 	else self->releasetime = time + (GAME_SPEED/2);
17850 
17851 	if((player[self->playerindex].playkeys & FLAG_ATTACK) &&
17852 		(self->direction ?
17853 		 (player[self->playerindex].keys & FLAG_MOVELEFT) :
17854 		 (player[self->playerindex].keys & FLAG_MOVERIGHT)))
17855 	{
17856 		player[self->playerindex].playkeys -= FLAG_ATTACK;
17857 		if(validanim(self,ANI_GRABBACKWARD))
17858 			 dograbattack(4);
17859 		else if(validanim(self,ANI_THROW))
17860 		{
17861 			 if(self->modeldata.throwframewait >= 0)
17862 				  doprethrow();
17863 			 else
17864 				  dothrow();
17865 		}
17866 		else
17867 			 dograbattack(0);
17868 	}
17869 	// grab forward
17870 	else if((player[self->playerindex].playkeys & FLAG_ATTACK) &&
17871 		validanim(self,ANI_GRABFORWARD) &&
17872 		(!self->direction ?
17873 		 (player[self->playerindex].keys & FLAG_MOVELEFT) :
17874 		 (player[self->playerindex].keys & FLAG_MOVERIGHT)))
17875 	{
17876 		player[self->playerindex].playkeys -= FLAG_ATTACK;
17877 		dograbattack(1);
17878 	}
17879 	// grab up
17880 	else if((player[self->playerindex].playkeys & FLAG_ATTACK) &&
17881 		validanim(self, ANI_GRABUP) && (player[self->playerindex].keys & FLAG_MOVEUP))
17882 	{
17883 		player[self->playerindex].playkeys -= FLAG_ATTACK;
17884 		dograbattack(2);
17885 	}
17886 	// grab down
17887 	else if((player[self->playerindex].playkeys & FLAG_ATTACK) &&
17888 		validanim(self,ANI_GRABDOWN) && (player[self->playerindex].keys & FLAG_MOVEDOWN))
17889 	{
17890 		player[self->playerindex].playkeys -= FLAG_ATTACK;
17891 		dograbattack(3);
17892 	}
17893 	// normal grab attack
17894 	else if((player[self->playerindex].playkeys & FLAG_ATTACK) && validanim(self,ANI_GRABATTACK))
17895 	{
17896 		player[self->playerindex].playkeys -= FLAG_ATTACK;
17897 		dograbattack(0);
17898 	}
17899 	// Vaulting.
17900 	else if((player[self->playerindex].playkeys & FLAG_JUMP) && validanim(self,ANI_VAULT))
17901 	{
17902 		player[self->playerindex].playkeys -= FLAG_JUMP;
17903 		dovault();
17904 	}
17905 	// grab attack finisher
17906 	else if(player[self->playerindex].playkeys & (FLAG_JUMP|FLAG_ATTACK))
17907 	{
17908 		player[self->playerindex].playkeys &= ~(FLAG_JUMP|FLAG_ATTACK);
17909 
17910 		// Perform final blow
17911 		if(validanim(self,ANI_GRABATTACK2) || validanim(self,ANI_ATTACK3))
17912 			dograbattack(-1);
17913 		else
17914 		{
17915 			self->attacking = 1;
17916 			memset(self->combostep, 0, sizeof(int)*5);
17917 			self->takeaction = common_grabattack;
17918 			tryjump(self->modeldata.jumpheight, self->modeldata.jumpspeed, 0, ANI_JUMP);
17919 		}
17920 	}
17921 
17922 	// grab walk code
17923 	else if(validanim(self,ANI_GRABWALK)  // check if grabwalk animation exists
17924 
17925 		 // if entity is still animating anything besides a grabwalk variant, don't let them move
17926 		 && (!self->animating || self->animation == self->modeldata.animation[ANI_GRABWALK]
17927 		 || self->animation == self->modeldata.animation[ANI_GRABWALKUP]
17928 		 || self->animation == self->modeldata.animation[ANI_GRABWALKDOWN]
17929 		 || self->animation == self->modeldata.animation[ANI_GRABBACKWALK])){
17930 
17931 		 // z axis movement
17932 		if(PLAYER_MIN_Z != PLAYER_MAX_Z)
17933 		{
17934 			if(player[self->playerindex].keys & FLAG_MOVEUP)
17935 			{
17936 				if(self->modeldata.grabwalkspeed) self->zdir = -self->modeldata.grabwalkspeed/2;
17937 				else self->zdir = -self->modeldata.speed/2;
17938 			}
17939 			else if(player[self->playerindex].keys & FLAG_MOVEDOWN)
17940 			{
17941 				if(self->modeldata.grabwalkspeed) self->zdir = self->modeldata.grabwalkspeed/2;
17942 				else self->zdir = self->modeldata.speed/2;
17943 			}
17944 			else if(!(player[self->playerindex].keys & (FLAG_MOVEUP|FLAG_MOVEDOWN)))
17945 				self->zdir = 0;
17946 		}
17947 
17948 		// x axis movement
17949 		if(player[self->playerindex].keys & FLAG_MOVELEFT)
17950 		{
17951 			if(self->modeldata.grabwalkspeed) self->xdir = -self->modeldata.grabwalkspeed;
17952 			else self->xdir = -self->modeldata.speed;
17953 		}
17954 
17955 		else if(player[self->playerindex].keys & FLAG_MOVERIGHT)
17956 		{
17957 			if(self->modeldata.grabwalkspeed) self->xdir = self->modeldata.grabwalkspeed;
17958 			else self->xdir = self->modeldata.speed;
17959 		}
17960 		else if(!((player[self->playerindex].keys & FLAG_MOVELEFT) || (player[self->playerindex].keys & FLAG_MOVERIGHT)) )
17961 			self->xdir = 0;
17962 
17963 		// setting the animations based on the velocity set above
17964 		if(self->xdir || self->zdir){
17965 			if(((self->xdir > 0 && !self->direction) || (self->xdir < 0 && self->direction)) && validanim(self,ANI_GRABBACKWALK))
17966 				ent_set_anim(self, ANI_GRABBACKWALK, 0);
17967 			else if(self->zdir < 0 && validanim(self,ANI_GRABWALKUP)) ent_set_anim(self, ANI_GRABWALKUP, 0);
17968 			else if(self->zdir > 0 && validanim(self,ANI_GRABWALKDOWN)) ent_set_anim(self, ANI_GRABWALKDOWN, 0);
17969 			else ent_set_anim(self, ANI_GRABWALK, 0);
17970 			if(self->animation == self->modeldata.animation[ANI_GRABWALKUP] && validanim(other,ANI_GRABBEDWALKUP))
17971 				ent_set_anim(other, ANI_GRABBEDWALKUP, 0);
17972 			else if(self->animation == self->modeldata.animation[ANI_GRABWALKDOWN] && validanim(other,ANI_GRABBEDWALKDOWN))
17973 				ent_set_anim(other, ANI_GRABBEDWALKDOWN, 0);
17974 			else if(self->animation == self->modeldata.animation[ANI_GRABBACKWALK] && validanim(other,ANI_GRABBEDBACKWALK))
17975 				ent_set_anim(other, ANI_GRABBEDBACKWALK, 0);
17976 			else if(validanim(other,ANI_GRABBEDWALK)) ent_set_anim(other, ANI_GRABBEDWALK, 0);
17977 			else if (validanim(other,ANI_GRABBED)) ent_set_anim(other, ANI_GRABBED, 0);
17978 			else ent_set_anim(other, ANI_PAIN, 0);
17979 		}
17980 		else{
17981 			ent_set_anim(self, ANI_GRAB, 0);
17982 			if (validanim(other,ANI_GRABBED)) ent_set_anim(other, ANI_GRABBED, 0);
17983 			else ent_set_anim(other, ANI_PAIN, 0);
17984 		}
17985 		// use check_link_move to set velocity, don't change it here
17986 		other->zdir = other->xdir = 0;
17987 		self->grabwalking = 1;
17988 	}
17989 
17990 	if(self->attacking)  self->releasetime = time + (GAME_SPEED/2); // reset releasetime when do attacks
17991 }
17992 
17993 
player_jump_check()17994 void player_jump_check()
17995 {
17996 	int candospecial = 0;
17997 	if(!noaircancel || !self->animating || self->animnum == self->jumpid)
17998 	{
17999 		//air special, copied and changed from Fugue's code
18000 		if((!level->nospecial || level->nospecial == 3) && player[self->playerindex].playkeys & FLAG_SPECIAL){
18001 
18002 			if(validanim(self,ANI_JUMPSPECIAL))
18003 			{
18004 				if(check_energy(1, ANI_JUMPSPECIAL))
18005 				{
18006 					if(!healthcheat) self->mp -= self->modeldata.animation[ANI_JUMPSPECIAL]->energycost.cost;
18007 					candospecial = 1;
18008 				}
18009 				else if(check_energy(0, ANI_JUMPSPECIAL))
18010 				{
18011 					if(!healthcheat) self->health -= self->modeldata.animation[ANI_JUMPSPECIAL]->energycost.cost;
18012 					candospecial = 1;
18013 				}
18014 				else if(validanim(self,ANI_JUMPCANT))
18015 				{
18016 					ent_set_anim(self, ANI_JUMPCANT, 0);
18017 					self->tossv = 0;
18018 				}
18019 
18020 				if(candospecial)
18021 				{
18022 					player[self->playerindex].playkeys -= FLAG_SPECIAL;
18023 					ent_set_anim(self, ANI_JUMPSPECIAL, 0);
18024 					self->attacking = 1;
18025 					self->xdir = self->zdir = 0;                         // Kill movement when the special starts
18026 					self->tossv = 0;
18027 				}
18028 			}
18029 		}//end of jumpspecial
18030 
18031 		//jumpattacks, up down forward normal....we don't check energy cost
18032 		else if(player[self->playerindex].playkeys & FLAG_ATTACK){
18033 			player[self->playerindex].playkeys -= FLAG_ATTACK;
18034 			self->attacking = 1;
18035 
18036 			if((player[self->playerindex].keys & FLAG_MOVEDOWN) && validanim(self,ANI_JUMPATTACK2)) ent_set_anim(self, ANI_JUMPATTACK2, 0);
18037 			else if((player[self->playerindex].keys & FLAG_MOVEUP) && validanim(self,ANI_JUMPATTACK3)) ent_set_anim(self, ANI_JUMPATTACK3, 0);
18038 			else if(self->running && validanim(self,ANI_RUNJUMPATTACK)) ent_set_anim(self, ANI_RUNJUMPATTACK, 0);    // Added so an extra strong jump attack can be executed
18039 			else if(self->xdir != 0 && validanim(self,ANI_JUMPFORWARD)) ent_set_anim(self, ANI_JUMPFORWARD, 0);    // If moving and set, do this attack
18040 			else if(validanim(self,ANI_JUMPATTACK)) ent_set_anim(self, ANI_JUMPATTACK, 0);
18041 		}//end of jumpattack
18042 	}
18043 	if(self->modeldata.jumpmovex&1) //flip?
18044 	{
18045 	   if((player[self->playerindex].keys & FLAG_MOVELEFT)) self->direction = 0;
18046 	   else if((player[self->playerindex].keys & FLAG_MOVERIGHT)) self->direction = 1;
18047 	}
18048 	if(self->modeldata.jumpmovex&2) //move?
18049 	{
18050 	   if(((player[self->playerindex].keys & FLAG_MOVELEFT)&&self->xdir>0) ||
18051 		  ((player[self->playerindex].keys & FLAG_MOVERIGHT)&&self->xdir<0))	self->xdir = -self->xdir;
18052 	}
18053 	if(self->modeldata.jumpmovex&4) //Move x if vertical jump?
18054 	{
18055 		if(((player[self->playerindex].keys & FLAG_MOVELEFT)&&self->xdir>0) ||
18056 		  ((player[self->playerindex].keys & FLAG_MOVERIGHT)&&self->xdir<0))	self->xdir = -self->xdir;
18057 
18058 		if((player[self->playerindex].keys & FLAG_MOVELEFT) && (!self->xdir))
18059 		{
18060 			self->xdir -= self->modeldata.speed;
18061 		}
18062 		else if((player[self->playerindex].keys & FLAG_MOVERIGHT) && (!self->xdir))
18063 		{
18064 			self->xdir = self->modeldata.speed;
18065 		}
18066 	}
18067 	if(self->modeldata.jumpmovez&2) //z move?
18068 	{
18069 	   if(((player[self->playerindex].keys & FLAG_MOVEUP)&&self->zdir>0) ||
18070 		  ((player[self->playerindex].keys & FLAG_MOVEDOWN)&&self->zdir<0)) self->zdir = -self->zdir;
18071 	}
18072 	if(self->modeldata.jumpmovez&4) //Move z if vertical jump?
18073 	{
18074 		if((player[self->playerindex].keys & FLAG_MOVELEFT)) self->direction = 0;
18075 	   else if((player[self->playerindex].keys & FLAG_MOVERIGHT)) self->direction = 1;
18076 
18077 		if(((player[self->playerindex].keys & FLAG_MOVEUP)&&self->zdir>0) ||
18078 		  ((player[self->playerindex].keys & FLAG_MOVEDOWN)&&self->zdir<0)) self->zdir = -self->zdir;
18079 
18080 		if((player[self->playerindex].keys & FLAG_MOVEUP) && (!self->zdir))
18081 		{
18082 			self->zdir -= (0.5 * self->modeldata.speed);
18083 		}
18084 		else if((player[self->playerindex].keys & FLAG_MOVEDOWN) && (!self->zdir))
18085 		{
18086 			self->zdir = (0.5 * self->modeldata.speed);
18087 		}
18088 	}
18089 
18090 }
18091 
player_pain_check()18092 void player_pain_check()
18093 {
18094 	if(player_check_special())  self->inpain = 0;
18095 }
18096 
18097 // check riseattack input up+attack
player_lie_check()18098 void player_lie_check()
18099 {
18100 	if(validanim(self,ANI_RISEATTACK) &&
18101 	   (player[self->playerindex].playkeys & FLAG_ATTACK) &&
18102 	   (player[self->playerindex].keys & FLAG_MOVEUP) &&
18103 	   (self->health > 0 && time > self->staydown.riseattack_stall))
18104 	{
18105 		player[self->playerindex].playkeys -= FLAG_ATTACK;
18106 		if((player[self->playerindex].keys & FLAG_MOVELEFT))
18107 		{
18108 			self->direction = 0;
18109 		}
18110 		if((player[self->playerindex].keys & FLAG_MOVERIGHT))
18111 		{
18112 			self->direction = 1;
18113 		}
18114 		self->stalltime = 0;
18115 		set_riseattack(self, self->damagetype, 0);
18116 	}
18117 }
18118 
player_charge_check()18119 void player_charge_check()
18120 {
18121 	if(!((player[self->playerindex].keys&FLAG_JUMP)&&
18122 		 (player[self->playerindex].keys&FLAG_SPECIAL)))
18123 	{
18124 		self->takeaction = NULL;
18125 		self->charging = 0;
18126 		set_idle(self);
18127 	}
18128 }
18129 
18130 
18131 // make a function so enemies can use
18132 // UT: jumphack is a temporary fix for jump cancel
check_costmove(int s,int fs,int jumphack)18133 int check_costmove(int s, int fs, int jumphack)
18134 {
18135 	if(((fs == 1 && level->nospecial < 2) || (fs == 0 && level->nospecial == 0) || (fs == 0 && level->nospecial == 3)) &&
18136 	   (check_energy(0, s) ||
18137 		check_energy(1, s))  )
18138 	{
18139 		if(!jumphack) self->takeaction = common_attack_proc;
18140 		if(!nocost && !healthcheat)
18141 		{
18142 			if(check_energy(1, s)) self->mp -= self->modeldata.animation[s]->energycost.cost;
18143 			else self->health -= self->modeldata.animation[s]->energycost.cost;
18144 		}
18145 
18146 		self->xdir = self->zdir = 0;
18147 		set_attacking(self);
18148 		self->inpain = 0;
18149 		memset(self->combostep, 0, sizeof(int)*5);
18150 		ent_unlink(self);
18151 		ent_set_anim(self, s, 0);
18152 		return 1;
18153 	}
18154 	return 0;
18155 }
18156 
match_combo(int a[],s_player * p,int l)18157 int match_combo(int a[], s_player* p, int l){
18158 	int j, step;
18159 	for(j=0; j<l; j++){
18160 		step = p->combostep-1-j;
18161 		step = (step + MAX_SPECIAL_INPUTS)%MAX_SPECIAL_INPUTS;
18162 		if(!(a[l-1-j]&p->combokey[step]))
18163 			return 0;
18164 	}
18165 	return 1;
18166 }
18167 
18168 
check_combo()18169 int check_combo(){
18170 	int i, maxstep = -1, valid = -1;
18171 	s_com *com;
18172 	s_player* p;
18173 
18174 	p = player+self->playerindex;
18175 
18176 	for(i = 0; i < self->modeldata.specials_loaded; i++)
18177 	{
18178 		com = self->modeldata.special + i;
18179 
18180 		if(self->animation->cancel&&
18181 			(self->animnum!=com->cancel||
18182 			com->startframe>self->animpos||
18183 			com->endframe<self->animpos||
18184 			self->animation->animhits<com->hits))
18185 			continue;
18186 		else if(!self->animation->cancel &&
18187 			(com->cancel||!self->idling||diff(self->a,self->base)>1) )
18188 			continue;
18189 
18190 		if( com->steps > maxstep && // find the longest possible combo
18191 			validanim(self,com->anim) &&
18192 		   (check_energy(1, com->anim) || check_energy(0, com->anim)) &&
18193 			match_combo(com->input, p, com->steps))
18194 		{
18195 			valid = com->anim;
18196 			maxstep = com->steps;
18197 		}
18198 	}//end of for
18199 
18200 	if(valid>=0 && check_costmove(valid, 1, self->jumping)){
18201 		return 1;
18202 	}
18203 
18204 	return 0;
18205 }
18206 
player_preinput()18207 int player_preinput()
18208 {
18209 	if(player[self->playerindex].playkeys){
18210 		if(check_combo()){
18211 			player[self->playerindex].playkeys &= ~FLAG_CONTROLKEYS;
18212 			return 1;
18213 		}
18214 	}
18215 	return 0;
18216  }
18217 
player_think()18218 void player_think()
18219 {
18220 	int action = 0;		// 1=walking, 2=up, 3=down, 4=running
18221 	int bkwalk = 0;   //backwalk
18222 	int runx,runz,movex,movez;
18223 	int t, t2;
18224 	entity *other = NULL;
18225 	float altdiff ;
18226 	int notinair;
18227 
18228 	static int ll[] = {FLAG_MOVELEFT, FLAG_MOVELEFT};
18229 	static int rr[] = {FLAG_MOVERIGHT, FLAG_MOVERIGHT};
18230 	static int uu[] = {FLAG_MOVEUP, FLAG_MOVEUP};
18231 	static int dd[] = {FLAG_MOVEDOWN, FLAG_MOVEDOWN};
18232 	static int ba[] = {FLAG_BACKWARD, FLAG_ATTACK};
18233 
18234 	int oldrunning = self->running;
18235 	int pli = self->playerindex;
18236 	s_player* pl= player+pli;
18237 
18238 
18239 	if(pl->ent != self || self->dead) return;
18240 
18241 	// check endlevel item
18242 	if((other = find_ent_here(self, self->x, self->z, TYPE_ENDLEVEL, NULL)) && diff(self->a, other->a)<=0.1)
18243 	{
18244 		if(!reached[0] && !reached[1] && !reached[2] && !reached[3]) addscore(pli, other->modeldata.score);
18245 		reached[pli] = 1;
18246 
18247 		if (!other->modeldata.subtype ||(other->modeldata.subtype == SUBTYPE_BOTH &&
18248 			(reached[0]+reached[1]+reached[2]+reached[3]) >= (count_ents(TYPE_PLAYER))))
18249 		{
18250 			level_completed = 1;
18251 
18252 			if(other->modeldata.branch) strncpy( branch_name, other->modeldata.branch, MAX_NAME_LEN); //now, you can branch to another level
18253 			return;
18254 		}
18255 	}
18256 
18257 	if(time > self->rushtime)
18258 	{
18259 		self->rush[0] = 0;
18260 		self->rushtime = 0;
18261 	}
18262 
18263 	if(player_preinput()){
18264 		goto endthinkcheck;
18265 	}
18266 
18267 	if(self->charging)
18268 	{
18269 		player_charge_check();
18270 		goto endthinkcheck;
18271 	}
18272 
18273 	if(self->inpain || (self->link && !self->grabbing))
18274 	{
18275 		player_pain_check();
18276 		goto endthinkcheck;
18277 	}
18278 
18279 	// falling? check for landing
18280 	if(self->projectile == 2)
18281 	{
18282 		player_fall_check();
18283 		goto endthinkcheck;
18284 	}
18285 
18286 	// grab section, dont move if still animating
18287 	if(self->grabbing && !self->attacking && self->takeaction!=common_throw_wait)
18288 	{
18289 		player_grab_check();
18290 		goto endthinkcheck;
18291 	}
18292 
18293 	// jump section
18294 	if(self->jumping)
18295 	{
18296 		player_jump_check();
18297 		goto endthinkcheck;
18298 	}
18299 
18300 	if(self->drop && self->a==self->base && !self->tossv)
18301 	{
18302 		player_lie_check();
18303 		goto endthinkcheck;
18304 	}
18305 
18306 
18307 	// cant do anything if busy
18308 	if(!self->idling && !(self->animation->idle && self->animation->idle[self->animpos]))
18309 		goto endthinkcheck;
18310 
18311 	// Check if entity is under a platform
18312 	if(self->modeldata.subject_to_platform>0 && validanim(self,ANI_DUCK) && check_platform_between(self->x/*+self->direction*2-1*/, self->z, self->a, self->a+self->modeldata.height, self) && (check_platform_between(self->x/*+self->direction*2-1*/, self->z, self->a, self->a+self->animation->height, self) || !self->animation->height) )
18313 	{
18314 		self->takeaction = common_stuck_underneath;
18315 		ent_set_anim(self, ANI_DUCK, 0);
18316 		goto endthinkcheck;
18317 	}
18318 
18319 	altdiff = diff(self->a, self->base);
18320 	notinair = (self->landed_on_platform?altdiff<5:altdiff<2);
18321 
18322 	if(pl->playkeys & FLAG_MOVEUP)
18323 	{
18324 		t = (notinair&&match_combo(uu, pl, 2));
18325 		if(t && (self->modeldata.runupdown&2) && validanim(self,ANI_RUN)){
18326 			pl->playkeys &= ~FLAG_MOVEUP;
18327 			pl->combostep = (pl->combostep-1+MAX_SPECIAL_INPUTS)%MAX_SPECIAL_INPUTS;
18328 			self->running = 1;    // Player begins to run
18329 		}
18330 		else if(t && validanim(self,ANI_ATTACKUP))
18331 		{    // New u u combo attack
18332 			pl->playkeys -= FLAG_MOVEUP;
18333 			self->takeaction = common_attack_proc;
18334 			set_attacking(self);
18335 			self->combostep[0] = 0;
18336 			self->xdir = self->zdir = 0;
18337 			ent_set_anim(self, ANI_ATTACKUP, 0);
18338 			pl->combostep = (pl->combostep-1+MAX_SPECIAL_INPUTS)%MAX_SPECIAL_INPUTS; // this workaround deals default freespecial2
18339 			goto endthinkcheck;
18340 		}
18341 		else if(t && validanim(self,ANI_DODGE))
18342 		{    // New dodge move like on SOR3
18343 			pl->playkeys -= FLAG_MOVEUP;
18344 			self->takeaction = common_dodge;
18345 			self->combostep[0] = 0;
18346 			self->idling = 0;
18347 			self->zdir = -self->modeldata.speed * 1.75; self->xdir = 0;// OK you can use jumpframe to modify this anyway
18348 			ent_set_anim(self, ANI_DODGE, 0);
18349 			pl->combostep = (pl->combostep-1+MAX_SPECIAL_INPUTS)%MAX_SPECIAL_INPUTS;
18350 			goto endthinkcheck;;
18351 		}
18352 	}
18353 
18354 	if(pl->playkeys & FLAG_MOVEDOWN)
18355 	{
18356 		t = (notinair&&match_combo(dd, pl, 2));
18357 		if(t && (self->modeldata.runupdown&2) && validanim(self,ANI_RUN)){
18358 			pl->playkeys &= ~FLAG_MOVEDOWN;
18359 			pl->combostep = (pl->combostep-1+MAX_SPECIAL_INPUTS)%MAX_SPECIAL_INPUTS;
18360 			self->running = 1;    // Player begins to run
18361 		}
18362 		else if(t && validanim(self,ANI_ATTACKDOWN))
18363 		{    // New d d combo attack
18364 			pl->playkeys -= FLAG_MOVEDOWN;
18365 			self->takeaction = common_attack_proc;
18366 			set_attacking(self);
18367 			self->xdir = self->zdir = 0;
18368 			self->combostep[0] = 0;
18369 			ent_set_anim(self, ANI_ATTACKDOWN, 0);
18370 			pl->combostep = (pl->combostep-1+MAX_SPECIAL_INPUTS)%MAX_SPECIAL_INPUTS;
18371 			goto endthinkcheck;
18372 		}
18373 		else if(t && validanim(self,ANI_DODGE))
18374 		{    // New dodge move like on SOR3
18375 			pl->playkeys -= FLAG_MOVEDOWN;
18376 			self->takeaction = common_dodge;
18377 			self->combostep[0] = 0;
18378 			self->idling = 0;
18379 			self->zdir = self->modeldata.speed * 1.75; self->xdir = 0;
18380 			ent_set_anim(self, ANI_DODGE, 0);
18381 			pl->combostep = (pl->combostep-1+MAX_SPECIAL_INPUTS)%MAX_SPECIAL_INPUTS;
18382 			goto endthinkcheck;
18383 		}
18384 	}
18385 
18386 	if((pl->playkeys & (FLAG_MOVELEFT|FLAG_MOVERIGHT)))
18387 	{
18388 		t = (notinair&&((self->direction&&match_combo(rr, pl, 2))||(!self->direction&&match_combo(ll, pl, 2))));
18389 
18390 		if(t && validanim(self,ANI_RUN)){
18391 			pl->playkeys &= ~(FLAG_MOVELEFT|FLAG_MOVERIGHT); // usually left + right is not acceptable, so it is OK to null both
18392 			pl->combostep = (pl->combostep-1+MAX_SPECIAL_INPUTS)%MAX_SPECIAL_INPUTS;
18393 			self->running = 1;    // Player begins to run
18394 		}else if(t && validanim(self,ANI_ATTACKFORWARD)){
18395 			pl->playkeys &= ~(FLAG_MOVELEFT|FLAG_MOVERIGHT);
18396 			self->takeaction = common_attack_proc;
18397 			set_attacking(self);
18398 			self->xdir = self->zdir = 0;
18399 			self->combostep[0] = 0;
18400 			ent_set_anim(self, ANI_ATTACKFORWARD, 0);
18401 			pl->combostep = (pl->combostep-1+MAX_SPECIAL_INPUTS)%MAX_SPECIAL_INPUTS;
18402 			goto endthinkcheck;
18403 		}
18404 	}
18405 
18406 	if(!ajspecial && (pl->playkeys & FLAG_JUMP) && validanim(self,ANI_ATTACKBOTH))
18407 	{
18408 		if((pl->keys & FLAG_ATTACK) && notinair)
18409 		{
18410 			pl->playkeys -= FLAG_JUMP;
18411 			self->takeaction = common_attack_proc;
18412 			set_attacking(self);
18413 			self->xdir = self->zdir = 0;
18414 			self->combostep[0] = 0;
18415 			self->stalltime = 0;    // If attack is pressed, holding down attack to execute attack3 is no longer valid
18416 			ent_set_anim(self, ANI_ATTACKBOTH, 0);
18417 			goto endthinkcheck;
18418 		}
18419 	}
18420 
18421 	if((pl->playkeys & FLAG_JUMP) &&  validanim(self,ANI_CHARGE))
18422 	{
18423 		if((pl->keys & FLAG_SPECIAL) && notinair)
18424 		{
18425 			pl->playkeys -= FLAG_JUMP;
18426 			self->takeaction = common_charge;
18427 			self->combostep[0] = 0;
18428 			self->xdir = self->zdir = 0;
18429 			self->stalltime = 0;
18430 			set_charging(self);
18431 			ent_set_anim(self, ANI_CHARGE, 0);
18432 			goto endthinkcheck;
18433 		}
18434 	}
18435 
18436 	if(pl->playkeys & FLAG_SPECIAL )    //    The special button can now be used for freespecials
18437 	{
18438 		if( validanim(self,ANI_SPECIAL2) && notinair &&
18439 			(!self->direction ?
18440 			(pl->keys & FLAG_MOVELEFT) :
18441 			 (pl->keys & FLAG_MOVERIGHT))  )
18442 		{
18443 			if(check_costmove(ANI_SPECIAL2, 0, 0))
18444 			{
18445 				pl->playkeys -= FLAG_SPECIAL;
18446 				goto endthinkcheck;
18447 			}
18448 		}
18449 
18450 		if(validanim(self,ANI_BLOCK) && !self->modeldata.holdblock && notinair)    // New block code for players
18451 		{
18452 			pl->playkeys -= FLAG_SPECIAL;
18453 			self->takeaction = common_block;
18454 			self->xdir = self->zdir = 0;
18455 			set_blocking(self);
18456 			self->combostep[0] = 0;
18457 			ent_set_anim(self, ANI_BLOCK, 0);
18458 			goto endthinkcheck;
18459 		}
18460 	}
18461 
18462 	if(notinair && player_check_special()) goto endthinkcheck;    // So you don't perform specials falling off the edge
18463 
18464 	if((pl->releasekeys & FLAG_ATTACK))
18465 	{
18466 		if(self->stalltime  && notinair &&
18467 	      ((validanim(self,ANI_CHARGEATTACK) && self->stalltime+(GAME_SPEED*self->modeldata.animation[ANI_CHARGEATTACK]->chargetime) < time) ||
18468 		   (!validanim(self,ANI_CHARGEATTACK) && self->stalltime+(GAME_SPEED*self->modeldata.animation[animattacks[self->modeldata.atchain[self->modeldata.chainlength-1]-1]]->chargetime) < time)))
18469 		{
18470 			self->takeaction = common_attack_proc;
18471 			set_attacking(self);
18472 			self->xdir = self->zdir = 0;
18473 
18474 			self->stalltime = 0;
18475 			self->combostep[0] = 0;
18476 
18477 			if(SAMPLE_PUNCH >= 0) sound_play_sample(SAMPLE_PUNCH, 0, savedata.effectvol,savedata.effectvol, 100);
18478 
18479 			if(validanim(self,ANI_CHARGEATTACK)) ent_set_anim(self, ANI_CHARGEATTACK, 0);
18480 			else ent_set_anim(self, animattacks[self->modeldata.atchain[self->modeldata.chainlength-1]-1], 0);
18481 			goto endthinkcheck;
18482 		}
18483 		self->stalltime = 0;
18484 	}
18485 
18486 	if((pl->playkeys & FLAG_ATTACK)  && notinair)
18487 	{
18488 		pl->playkeys -= FLAG_ATTACK;
18489 		self->stalltime = 0;    // Disable the attack3 stalltime
18490 
18491 		if(pl->keys & FLAG_MOVEDOWN && validanim(self, ANI_DUCKATTACK) && PLAYER_MIN_Z == PLAYER_MAX_Z)
18492 		{
18493 			self->takeaction = common_attack_proc;
18494 			set_attacking(self);
18495 			self->xdir = self->zdir = 0;
18496 			self->combostep[0] = 0;
18497 			ent_set_anim(self, ANI_DUCKATTACK, 0);
18498 			goto endthinkcheck;
18499 		}
18500 
18501 		if(self->running && validanim(self,ANI_RUNATTACK))    // New run attack code section
18502 		{
18503 			self->takeaction = common_attack_proc;
18504 			set_attacking(self);
18505 			self->xdir = self->zdir = 0;
18506 			self->combostep[0] = 0;
18507 			self->running = 0;
18508 			ent_set_anim(self, ANI_RUNATTACK, 0);
18509 			goto endthinkcheck;
18510 		}
18511 
18512 		if(validanim(self,ANI_ATTACKBACKWARD) && match_combo(ba, pl,2))
18513 		{
18514 			t = (pl->combostep-1+MAX_SPECIAL_INPUTS)%MAX_SPECIAL_INPUTS;
18515 			t2 = (pl->combostep-2+MAX_SPECIAL_INPUTS)%MAX_SPECIAL_INPUTS;
18516 			if(pl->inputtime[t]-pl->inputtime[t2]<GAME_SPEED/10){
18517 				self->takeaction = common_attack_proc;
18518 				set_attacking(self);
18519 				self->xdir = self->zdir = 0;
18520 				if(!self->direction&&(pl->combokey[t2]&FLAG_MOVELEFT)) self->direction = 1;
18521 				else if(self->direction&&(pl->combokey[t2]&FLAG_MOVERIGHT)) self->direction = 0;
18522 				self->combostep[0] = 0;
18523 				ent_set_anim(self, ANI_ATTACKBACKWARD, 0);
18524 				goto endthinkcheck;
18525 			}
18526 		}
18527 
18528 		if( validanim(self,ANI_GET) && (other = find_ent_here(self, self->x, self->z, TYPE_ITEM, player_test_pickable)) )
18529 		{
18530 			self->xdir = self->zdir = 0;
18531 			set_getting(self);
18532 			self->takeaction = common_get;
18533 			ent_set_anim(self, ANI_GET, 0);
18534 			execute_didhit_script(other, self, 0, 0, other->modeldata.subtype, 0, 0, 0, 0, 0); //Execute didhit script as if item "hit" collecter to allow easy item scripting.
18535 			didfind_item(other);
18536 			goto endthinkcheck;
18537 		}
18538 
18539 		// Use stalltime to charge end-move
18540 		self->stalltime = time;
18541 		self->xdir = self->zdir = 0;
18542 
18543 		if(!validanim(self,ANI_ATTACK1) && validanim(self,ANI_JUMP))
18544 		{
18545 			// This is for Mighty
18546 			self->combostep[0] = 0;
18547 			tryjump(self->modeldata.jumpheight, self->modeldata.jumpspeed, 0, ANI_JUMP);
18548 			goto endthinkcheck;
18549 		}
18550 		if( self->weapent &&
18551 			self->weapent->modeldata.subtype == SUBTYPE_PROJECTILE &&
18552 			validanim(self,ANI_THROWATTACK)  )
18553 		{
18554 			self->takeaction = common_attack_proc;
18555 			set_attacking(self);
18556 			ent_set_anim(self, ANI_THROWATTACK, 0);
18557 		}
18558 		else if(perform_atchain())
18559 		{
18560 			if(SAMPLE_PUNCH >= 0 && self->attacking) sound_play_sample(SAMPLE_PUNCH, 0, savedata.effectvol,savedata.effectvol, 100);
18561 		}
18562 
18563 		goto endthinkcheck;
18564 	}
18565 	// 7-1-2005 spawn projectile end
18566 
18567 	// Mighty hass no attack animations, he just jumps.
18568 	if(pl->playkeys & FLAG_JUMP  && notinair)
18569 	{    // Added !inair(self) so players can't jump when falling into holes
18570 		pl->playkeys -= FLAG_JUMP;
18571 
18572 		if(self->running)
18573 		{
18574 			//Slide
18575 			if((pl->keys & FLAG_MOVEDOWN) && validanim(self,ANI_RUNSLIDE))
18576 			{
18577 				self->takeaction = common_attack_proc;
18578 				set_attacking(self);
18579 				self->xdir = self->zdir = 0;
18580 				self->combostep[0] = 0;
18581 				self->running = 0;
18582 				ent_set_anim(self, ANI_RUNSLIDE, 0);
18583 				goto endthinkcheck;
18584 			}
18585 
18586 			if(validanim(self,ANI_RUNJUMP))
18587 				tryjump(self->modeldata.runjumpheight, self->modeldata.jumpspeed*self->modeldata.runjumpdist, (self->modeldata.jumpmovez)?self->zdir:0, ANI_RUNJUMP);
18588 			else if(validanim(self,ANI_FORWARDJUMP))
18589 				tryjump(self->modeldata.runjumpheight, self->modeldata.jumpspeed*self->modeldata.runjumpdist, (self->modeldata.jumpmovez)?self->zdir:0, ANI_FORWARDJUMP);
18590 			else if(validanim(self,ANI_JUMP))
18591 				tryjump(self->modeldata.runjumpheight, self->modeldata.jumpspeed*self->modeldata.runjumpdist, (self->modeldata.jumpmovez)?self->zdir:0, ANI_JUMP);
18592 		}
18593 		else
18594 		{
18595 			//Slide
18596 			if((pl->keys & FLAG_MOVEDOWN) && validanim(self,ANI_SLIDE))
18597 			{
18598 				self->takeaction = common_attack_proc;
18599 				set_attacking(self);
18600 				self->xdir = self->zdir = 0;
18601 				self->combostep[0] = 0;
18602 				self->running = 0;
18603 				ent_set_anim(self, ANI_SLIDE, 0);
18604 				goto endthinkcheck;
18605 			}
18606 
18607 			if(!(pl->keys & (FLAG_MOVELEFT|FLAG_MOVERIGHT)) && validanim(self,ANI_JUMP))
18608 			{
18609 				tryjump(self->modeldata.jumpheight, 0, (self->modeldata.jumpmovez)?self->zdir:0, ANI_JUMP);
18610 				goto endthinkcheck;
18611 			}
18612 			else if((pl->keys & FLAG_MOVELEFT)) self->direction = 0;
18613 			else if((pl->keys & FLAG_MOVERIGHT)) self->direction = 1;
18614 
18615 			if(validanim(self,ANI_FORWARDJUMP))
18616 				tryjump(self->modeldata.jumpheight, self->modeldata.jumpspeed, (self->modeldata.jumpmovez)?self->zdir:0, ANI_FORWARDJUMP);
18617 			else if(validanim(self,ANI_JUMP)) tryjump(self->modeldata.jumpheight, self->modeldata.jumpspeed, (self->modeldata.jumpmovez)?self->zdir:0, ANI_JUMP);
18618 		}
18619 		return;
18620 	}
18621 
18622 	if(validanim(self,ANI_BLOCK) && self->modeldata.holdblock &&
18623 	   pl->keys & FLAG_SPECIAL && notinair)
18624 	{
18625 		if(!self->blocking )
18626 		{
18627 			self->blocking = 1;
18628 			self->xdir = self->zdir = 0;
18629 			ent_set_anim(self, ANI_BLOCK, 0);
18630 		}
18631 		goto endthinkcheck;
18632 	}
18633 	else
18634 	{
18635 		self->blocking = 0;
18636 	}
18637 
18638 	//dang long run checking logic
18639 	if(self->running){
18640 		runx=runz=movex=movez=0;
18641 		if(pl->keys & FLAG_MOVEUP) movez--;
18642 		if(pl->keys & FLAG_MOVEDOWN) movez++;
18643 		if(pl->keys & FLAG_MOVELEFT) movex--;
18644 		if(pl->keys & FLAG_MOVERIGHT) movex++;
18645 		if(oldrunning){
18646 			if(self->zdir<0) runz--;
18647 			else if(self->zdir>0) runz++;
18648 			if(self->xdir<0) runx--;
18649 			else if(self->xdir>0) runx++;
18650 		}
18651 		if(!self->modeldata.runupdown){
18652 			if(movez || !movex)
18653 				self->running=0;
18654 		}else if(self->modeldata.runupdown&4){
18655 			if(!movex && !movez) self->running=0;
18656 			else if(movex && !movez && runx==-movex)
18657 				self->running=0;
18658 			else if(movez && !movex && runz==-movez)
18659 				self->running=0;
18660 			else if(movex && movez && diff(movex,runx)+diff(movez,runz)>2)
18661 				self->running=0;
18662 		}else if(self->modeldata.runupdown){
18663 			if(!movex || movex==-runx)
18664 				self->running=0;
18665 		}
18666 
18667 	}
18668 
18669 	if(PLAYER_MIN_Z != PLAYER_MAX_Z)
18670 	{    // More of a platform feel
18671 		if(pl->keys & FLAG_MOVEUP)
18672 		{
18673 			//if(!self->modeldata.runupdown ) self->running = 0;    // Quits running if player presses up (or the up animation exists
18674 
18675 			if(validanim(self,ANI_UP) && !self->running)
18676 			{
18677 				action = 2;
18678 				self->zdir = -self->modeldata.speed/2;    // Used for up animation
18679 			}
18680 			else if(self->running)
18681 			{
18682 				action = 4;
18683 				 self->zdir = -self->modeldata.runspeed/2;    // Moves up at a faster rate running
18684 			}
18685 			else
18686 			{
18687 				action = 1;
18688 				self->zdir = -self->modeldata.speed/2;
18689 			}
18690 		}
18691 		else if(pl->keys & FLAG_MOVEDOWN)
18692 		{
18693 			//if(!self->modeldata.runupdown ) self->running = 0;    // Quits running if player presses down (or the down animation exists
18694 
18695 			if(validanim(self,ANI_DOWN) && !self->running )
18696 			{
18697 				action = 3;
18698 				self->zdir = self->modeldata.speed/2;    // Used for down animation
18699 			}
18700 			else if(self->running)
18701 			{
18702 				action = 4;
18703 				self->zdir = self->modeldata.runspeed/2;    // Moves down at a faster rate running
18704 			}
18705 			else
18706 			{
18707 				action = 1;
18708 				self->zdir = self->modeldata.speed/2;
18709 			}
18710 		}
18711 		else if(!(pl->keys & (FLAG_MOVEUP|FLAG_MOVEDOWN)))
18712 			self->zdir = 0;
18713 	}
18714 	else if(validanim(self,ANI_DUCK) && pl->keys & FLAG_MOVEDOWN  && notinair)
18715 	{
18716 		ent_set_anim(self, ANI_DUCK, 0);
18717 		self->xdir = self->zdir = 0;
18718 		goto endthinkcheck;
18719 	}
18720 
18721 	if(pl->keys & FLAG_MOVELEFT)
18722 	{
18723 		if(self->direction)
18724 		{
18725 			//self->running = 0;    // Quits running if player changes direction
18726 			if(self->modeldata.turndelay && !self->turntime)
18727 				self->turntime = time + self->modeldata.turndelay;
18728 			else if(self->turntime && time >= self->turntime)
18729 			{
18730 				self->turntime = 0;
18731 				if(validanim(self,ANI_TURN))
18732 				{
18733 					self->takeaction = common_turn;
18734 					set_turning(self);
18735 					self->xdir=self->zdir=0;
18736 					ent_set_anim(self, ANI_TURN, 0);
18737 					goto endthinkcheck;
18738 				}
18739 				self->direction = 0;
18740 			}
18741 			else if(!self->modeldata.turndelay && validanim(self,ANI_TURN))
18742 			{
18743 				self->takeaction = common_turn;
18744 				set_turning(self);
18745 				self->xdir=self->zdir=0;
18746 				ent_set_anim(self, ANI_TURN, 0);
18747 				goto endthinkcheck;
18748 			}
18749 			else if(!self->turntime) self->direction = 0;
18750 		}
18751 		else  self->turntime = 0;
18752 
18753 		if(self->running)
18754 		{
18755 			action = 4;
18756 			self->xdir = -self->modeldata.runspeed;    // If running, player moves at a faster rate
18757 		}
18758 		else if(action!=2 && action != 3)
18759 		{
18760 			action = 1;
18761 			self->xdir = -self->modeldata.speed;
18762 		}
18763 		else
18764 		{
18765 			self->xdir = -self->modeldata.speed;
18766 		}
18767 	}
18768 	else if(pl->keys & FLAG_MOVERIGHT)
18769 	{
18770 		if(!self->direction)
18771 		{
18772 			//self->running = 0;    // Quits running if player changes direction
18773 			if(self->modeldata.turndelay && !self->turntime)
18774 				self->turntime = time + self->modeldata.turndelay;
18775 			else if(self->turntime && time >= self->turntime)
18776 			{
18777 				self->turntime = 0;
18778 				if(validanim(self,ANI_TURN))
18779 				{
18780 					self->takeaction = common_turn;
18781 					set_turning(self);
18782 					self->xdir=self->zdir=0;
18783 					ent_set_anim(self, ANI_TURN, 0);
18784 					goto endthinkcheck;
18785 				}
18786 				self->direction = 1;
18787 			}
18788 			else if(!self->modeldata.turndelay && validanim(self,ANI_TURN))
18789 			{
18790 				self->takeaction = common_turn;
18791 				set_turning(self);
18792 				self->xdir=self->zdir=0;
18793 				ent_set_anim(self, ANI_TURN, 0);
18794 				goto endthinkcheck;
18795 			}
18796 			else if(!self->turntime) self->direction = 1;
18797 		}
18798 		else  self->turntime = 0;
18799 
18800 		if(self->running)
18801 		{
18802 			action = 4;
18803 			self->xdir = self->modeldata.runspeed;    // If running, player moves at a faster rate
18804 		}
18805 		else if(action!=2 && action != 3)
18806 		{
18807 			action = 1;
18808 			self->xdir = self->modeldata.speed;
18809 		}
18810 		else
18811 		{
18812 			self->xdir = self->modeldata.speed;
18813 		}
18814 	}
18815 	else if(!((pl->keys & FLAG_MOVELEFT) ||
18816 		(pl->keys & FLAG_MOVERIGHT)) )
18817 	{
18818 		//self->running = 0;    // Player let go of left/right and so quits running
18819 		self->xdir = 0;
18820 		self->turntime = 0;
18821 	}
18822 
18823 	if((other = find_ent_here(self, self->x, self->z, TYPE_ITEM, player_test_touch))  )
18824 	{
18825 		didfind_item(other);    // Added function to clean code up a bit
18826 	}
18827 
18828 	if(action)
18829 	{
18830 		self->takeaction = NULL;
18831 		self->idling = 1;
18832 	}
18833 	switch(action)
18834 	{
18835 		case 1:
18836 		// back walk feature
18837 			if(level && validanim(self,ANI_BACKWALK))
18838 			{
18839 			if(self->modeldata.facing == 1 || level->facing == 1)  bkwalk = !self->direction;
18840 			else if(self->modeldata.facing == 2 || level->facing == 2) bkwalk = self->direction;
18841 			else if((self->modeldata.facing == 3 || level->facing == 3) && (level->scrolldir & SCROLL_LEFT) && !self->direction ) bkwalk = 1;
18842 			else if((self->modeldata.facing == 3 || level->facing == 3) && (level->scrolldir & SCROLL_RIGHT) && self->direction) bkwalk = 1;
18843 			else if(self->turntime && self->modeldata.turndelay) bkwalk = 1;
18844 			if(bkwalk) common_backwalk_anim(self); //ent_set_anim(self, ANI_BACKWALK, 0);
18845 			else common_walk_anim(self); //ent_set_anim(self, ANI_WALK, 0);    // If neither up nor down exist, set to walk
18846 		}
18847 		else common_walk_anim(self); //ent_set_anim(self, ANI_WALK, 0);    // If neither up nor down exist, set to walk
18848 			break;
18849 		case 2:
18850 			common_up_anim(self); //ent_set_anim(self, ANI_UP, 0);    // Set to up animation if exists
18851 			break;
18852 		case 3:
18853 		    common_down_anim(self); //ent_set_anim(self, ANI_DOWN, 0);    // Set to down animation if exists
18854 			break;
18855 		case 4:
18856 			ent_set_anim(self, ANI_RUN, 0);    // Set to run animation if exists
18857 			break;
18858 		default:
18859 			if(self->idling)
18860 			{
18861 				common_idle_anim(self);
18862 			}
18863 			break;
18864 	}
18865 
18866 
18867 endthinkcheck:
18868 	//insert check here
18869 	return;
18870 
18871 }
18872 
common_idle_anim(entity * ent)18873 int common_idle_anim(entity* ent)
18874 {
18875 	/*
18876 	common_idle_anim
18877 	Damon Vaughn Caskey
18878 	11012009
18879 	Determine and set appropriate idle animation based on condition and range.
18880 	Returns 1 if any animation is set.
18881 	*/
18882 
18883 	int i;                                                                              //Loop counter.
18884 	int iAni;                                                                           //Animation.
18885 	entity* tempself = self;
18886 
18887 	self = ent;
18888 
18889 	if (ent->model->subtype != SUBTYPE_BIKER && ent->model->type != TYPE_NONE) // biker fix by Plombo // type none being "idle" prevented contra locked and loaded from working correctly. fixed by anallyst
18890 		ent->xdir = ent->zdir = 0;                                                      //Stop movement.
18891 
18892 	if(validanim(ent,ANI_FAINT) && ent->health <= ent->modeldata.health / 4)            //ANI_FAINT and health at/below 25%?
18893 	{
18894 		ent_set_anim(ent, ANI_FAINT, 0);                                                //Set ANI_FAINT.
18895 		goto found;                                                                      //Return 1 and exit.
18896 	}
18897 	else if(validanim(ent,ANI_SLEEP) && (time >= ent->sleeptime) && ent->animating)     //ANI_SLEEP, sleeptime up and currently animating?
18898 	{
18899 		ent_set_anim(ent, ANI_SLEEP, 0);                                                //Set sleep anim.
18900 		goto found;                                                                     //Return 1 and exit.
18901 	}
18902 	else
18903 	{
18904 		for (i=0; i<max_idles; i++)                                                     //Loop through all idle animations.
18905 		{
18906 			iAni = animidles[i];                                                        //Get current animation.
18907 
18908 			if (validanim(ent, iAni) && iAni != ANI_IDLE)                               //Valid and not ANI_IDLE?
18909 			{
18910 				tempself = self;
18911 				self = ent;
18912 				if (normal_find_target(iAni,0))                                           //Opponent in range of current animation?
18913 				{
18914 					ent_set_anim(ent, iAni, 0);                                         //Set animation.
18915 					goto found;                                                          //Return 1 and exit.
18916 				}
18917 			}
18918 		}
18919 
18920 		if (validanim(ent, ANI_IDLE))
18921 		{
18922 			ent_set_anim(ent, ANI_IDLE, 0);                                             //No alternates were set. Set ANI_IDLE.
18923 			goto found;                                                                  //Return 1 and exit.
18924 		}
18925 	}
18926 
18927 	self = tempself;
18928 	return 0;
18929 found:
18930 	self = tempself;
18931 	return 1;
18932 }
18933 
common_walk_anim(entity * ent)18934 int common_walk_anim(entity* ent)
18935 {
18936 	/*
18937 	common_walk_anim
18938 	Damon Vaughn Caskey
18939 	11032009
18940 	Determine and set appropriate walk animation based on condition and range.
18941 	Returns 1 if any animation is set.
18942 	*/
18943 
18944 	int i;                                                                          //Loop counter.
18945 	int iAni;                                                                       //Animation.
18946 
18947 	for (i=0; i<max_walks; i++)                                                     //Loop through all relevant animations.
18948 	{
18949 		iAni = animwalks[i];                                                        //Get current animation.
18950 
18951 		if (validanim(ent, iAni) && iAni != ANI_WALK)                               //Valid and not Default animation??
18952 		{
18953 			if (normal_find_target(iAni,0))                                         //Opponent in range of current animation?
18954 			{
18955 				ent_set_anim(ent, iAni, 0);                                         //Set animation.
18956 				return 1;                                                           //Return 1 and exit.
18957 			}
18958 		}
18959 	}
18960 
18961 	if (validanim(ent, ANI_WALK))
18962 	{
18963 		ent_set_anim(ent, ANI_WALK, 0);                                             //No alternates were set. Set default..
18964 		return 1;                                                                   //Return 1 and exit.
18965 	}
18966 
18967 	return 0;
18968 }
18969 
common_backwalk_anim(entity * ent)18970 int common_backwalk_anim(entity* ent)
18971 {
18972 	/*
18973 	common_backwalk_anim
18974 	Damon Vaughn Caskey
18975 	11032009
18976 	Determine and set appropriate backwalk animation based on condition and range.
18977 	Returns 1 if any animation is set.
18978 	*/
18979 
18980 	int i;                                                                          //Loop counter.
18981 	int iAni;                                                                       //Animation.
18982 
18983 	for (i=0; i<max_backwalks; i++)                                                 //Loop through all relevant animations.
18984 	{
18985 		iAni = animbackwalks[i];                                                    //Get current animation.
18986 
18987 		if (validanim(ent, iAni) && iAni != ANI_BACKWALK)                           //Valid and not Default animation??
18988 		{
18989 			if (normal_find_target(iAni,0))                                         //Opponent in range of current animation?
18990 			{
18991 				ent_set_anim(ent, iAni, 0);                                         //Set animation.
18992 				return 1;                                                           //Return 1 and exit.
18993 			}
18994 		}
18995 	}
18996 
18997 	if (validanim(ent, ANI_BACKWALK))
18998 	{
18999 		ent_set_anim(ent, ANI_BACKWALK, 0);                                         //No alternates were set. Set default..
19000 		return 1;                                                                   //Return 1 and exit.
19001 	}
19002 
19003 	return 0;
19004 }
19005 
common_up_anim(entity * ent)19006 int common_up_anim(entity* ent)
19007 {
19008 	/*
19009 	common_up_anim
19010 	Damon Vaughn Caskey
19011 	11032009
19012 	Determine and set appropriate up animation based on condition and range.
19013 	Returns 1 if any animation is set.
19014 	*/
19015 
19016 	int i;                                                                    //Loop counter.
19017 	int iAni;                                                                 //Animation.
19018 
19019 	for (i=0; i<max_ups; i++)                                                 //Loop through all relevant animations.
19020 	{
19021 		iAni = animups[i];                                                    //Get current animation.
19022 
19023 		if (validanim(ent, iAni) && iAni != ANI_UP)                           //Valid and not Default animation??
19024 		{
19025 			if (normal_find_target(iAni,0))                                   //Opponent in range of current animation?
19026 			{
19027 				ent_set_anim(ent, iAni, 0);                                   //Set animation.
19028 				return 1;                                                     //Return 1 and exit.
19029 			}
19030 		}
19031 	}
19032 
19033 	if (validanim(ent, ANI_UP))
19034 	{
19035 		ent_set_anim(ent, ANI_UP, 0);                                         //No alternates were set. Set default..
19036 		return 1;                                                             //Return 1 and exit.
19037 	}
19038 
19039 	return 0;
19040 }
19041 
common_down_anim(entity * ent)19042 int common_down_anim(entity* ent)
19043 {
19044 	/*
19045 	common_up_anim
19046 	Damon Vaughn Caskey
19047 	11032009
19048 	Determine and set appropriate up animation based on condition and range.
19049 	Returns 1 if any animation is set.
19050 	*/
19051 
19052 	int i;                                                                    //Loop counter.
19053 	int iAni;                                                                 //Animation.
19054 
19055 	for (i=0; i<max_downs; i++)                                               //Loop through all relevant animations.
19056 	{
19057 		iAni = animdowns[i];                                                  //Get current animation.
19058 
19059 		if (validanim(ent, iAni) && iAni != ANI_DOWN)                         //Valid and not Default animation??
19060 		{
19061 			if (normal_find_target(iAni,0))                                   //Opponent in range of current animation?
19062 			{
19063 				ent_set_anim(ent, iAni, 0);                                   //Set animation.
19064 				return 1;                                                     //Return 1 and exit.
19065 			}
19066 		}
19067 	}
19068 
19069 	if (validanim(ent, ANI_DOWN))
19070 	{
19071 		ent_set_anim(ent, ANI_DOWN, 0);                                       //No alternates were set. Set default..
19072 		return 1;                                                             //Return 1 and exit.
19073 	}
19074 
19075 	return 0;
19076 }
19077 
19078 //ammo count goes down
subtract_shot()19079 void subtract_shot()
19080 {
19081 	if(self->weapent && self->weapent->modeldata.shootnum)
19082 	{
19083 		self->weapent->modeldata.shootnum--;
19084 		if(!self->weapent->modeldata.shootnum)
19085 		{
19086 			self->weapent->modeldata.counter = 0;
19087 			dropweapon(0);
19088 		}
19089 	}
19090 
19091 }
19092 
19093 
dropweapon(int flag)19094 void dropweapon(int flag)
19095 {
19096 	int wall;
19097 	entity* other = NULL;
19098 
19099 	if(self->weapent)
19100 	{
19101 		if(self->weapent->modeldata.typeshot || (!self->weapent->modeldata.typeshot && self->weapent->modeldata.shootnum))
19102 		{
19103 			self->weapent->direction = self->direction;//same direction as players, 2007 -2 - 11   by UTunnels
19104 			if(flag < 2) self->weapent->modeldata.counter -= flag;
19105 			self->weapent->z = self->z;
19106 			self->weapent->x = self->x;
19107 			self->weapent->a = self->a;
19108 
19109 			other = check_platform(self->weapent->x, self->weapent->z, self);
19110 			wall = checkwall(self->weapent->x, self->weapent->z);
19111 
19112 			if(other && other != self->weapent)   self->weapent->base += other->a + other->animation->platform[other->animpos][7];
19113 			else if(wall >= 0) self->weapent->base += level->walls[wall][7];
19114 
19115 			if(validanim(self->weapent,ANI_RESPAWN)) ent_set_anim(self->weapent, ANI_RESPAWN, 1);
19116 			else if(validanim(self->weapent,ANI_SPAWN)) ent_set_anim(self->weapent, ANI_SPAWN, 1);
19117 			else ent_set_anim(self->weapent, ANI_IDLE, 1);
19118 
19119 			if(!self->weapent->modeldata.counter)
19120 			{
19121 				if(!self->modeldata.animal)
19122 				{
19123 					self->weapent->blink = 1;
19124 					self->weapent->takeaction = common_lie;
19125 				}
19126 				else{
19127 					self->weapent->modeldata.type = TYPE_NONE;
19128 					self->weapent->think = runanimal;
19129 				}
19130 			}
19131 			self->weapent->nextthink = time + 1;
19132 		}
19133 		self->weapent = NULL;
19134 	}
19135 	if(flag < 2)
19136 	{
19137 		if(self->modeldata.type == TYPE_PLAYER)
19138 		{
19139 			if(player[self->playerindex].weapnum)
19140 				set_weapon(self, player[self->playerindex].weapnum, 0);
19141 			else set_weapon(self, level->setweap, 0);
19142 		}
19143 		else set_weapon(self, 0, 0);
19144 	}
19145 
19146 	if(self->modeldata.weaploss[1]>0)
19147 	{
19148 		set_weapon(self, self->modeldata.weaploss[1], 0);
19149 	}
19150 }
19151 
19152 
player_takedamage(entity * other,s_attack * attack)19153 int player_takedamage(entity *other, s_attack* attack)
19154 {
19155 	s_attack atk;
19156 	//printf("damaged by: '%s' %d\n", other->name, attack->attack_force);
19157 	if(healthcheat)
19158 	{
19159 		memcpy(&atk, attack, sizeof(s_attack));
19160 		atk.attack_force = 0;
19161 		return common_takedamage(other, &atk);
19162 	}
19163 	return common_takedamage(other, attack);
19164 }
19165 
19166 
19167 ////////////////////////////////
19168 
19169 // Called when player re-enters the game.
19170 // Drop all enemies EXCEPT for the linked/frozen ones.
drop_all_enemies()19171 void drop_all_enemies()
19172 {
19173 	int i;
19174 	entity* weapself = self;
19175 	for(i=0; i<ent_max; i++)
19176 	{
19177 		if(ent_list[i]->exists &&
19178 			ent_list[i]->health>0 &&
19179 			ent_list[i]->modeldata.type==TYPE_ENEMY &&
19180 			!ent_list[i]->owner &&    // Don't want to knock down a projectile
19181 			!ent_list[i]->frozen &&    // Don't want to unfreeze a frozen enemy
19182 			!ent_list[i]->modeldata.nomove &&
19183 			!ent_list[i]->modeldata.nodrop &&
19184 			validanim(ent_list[i],ANI_FALL) )
19185 		{
19186 			ent_list[i]->attacking = 0;
19187 			ent_list[i]->projectile = 0;
19188 			ent_list[i]->takeaction = common_fall;//enemy_fall;
19189 			ent_list[i]->damage_on_landing = 0;
19190 			self = ent_list[i];
19191 			ent_unlink(self);
19192 			ent_list[i]->xdir = (self->direction)?(-1.2):1.2;
19193 			dropweapon(1);
19194 			toss(ent_list[i], 2.5 + randf(1));
19195 			ent_list[i]->knockdowncount = ent_list[i]->modeldata.knockdowncount;
19196 
19197 			ent_list[i]->knockdowntime = 0;
19198 			set_fall(ent_list[i], ATK_NORMAL, 1, self, 0, 0, 0, 0, 0, 0);
19199 		}
19200 	}
19201 	self = weapself;
19202 }
19203 
19204 
19205 
19206 // Called when boss dies
kill_all_enemies()19207 void kill_all_enemies()
19208 {
19209 	int i;
19210 	s_attack attack;
19211 	entity * tmpself = NULL;
19212 
19213 	attack = emptyattack;
19214 	attack.attack_type = max_attack_types;
19215 	attack.dropv[0] = default_model_dropv[0];
19216 	attack.dropv[1] = default_model_dropv[1];
19217 	attack.dropv[2] = default_model_dropv[2];
19218 
19219 	tmpself = self;
19220 	for(i=0; i<ent_max; i++)
19221 	{
19222 		if(  ent_list[i]->exists
19223 			&& ent_list[i]->health>0
19224 			&& ent_list[i]->modeldata.type==TYPE_ENEMY
19225 			&& ent_list[i]->takedamage)
19226 		{
19227 			self = ent_list[i];
19228 			attack.attack_force = self->health;
19229 			self->takedamage(tmpself, &attack);
19230 			self->dead = 1;
19231 		}
19232 	}
19233 	self = tmpself;
19234 }
19235 
19236 
19237 
smart_bomb(entity * e,s_attack * attack)19238 void smart_bomb(entity* e, s_attack* attack)    // New method for smartbombs
19239 {
19240 	int i, hostile, hit=0;
19241 	entity * tmpself = NULL;
19242 
19243 	hostile = e->modeldata.hostile;
19244 	if(e->modeldata.type == TYPE_PLAYER)
19245 		hostile &= ~(TYPE_PLAYER);
19246 
19247 	tmpself = self;
19248 	for(i=0; i<ent_max; i++)
19249 	{
19250 		if( ent_list[i]->exists
19251 			&& ent_list[i] != e
19252 			&& ent_list[i]->health>0
19253 			&& (ent_list[i]->modeldata.type&(e->modeldata.hostile)))
19254 		{
19255 			self = ent_list[i];
19256 			hit = 1; // for nocost, if the bomb doesn't hit, it won't cost energy
19257 			if(self->takedamage)
19258 			{
19259 				//attack.attack_drop = self->modeldata.knockdowncount+1;
19260 				self->takedamage(e, attack);
19261 			}
19262 			else
19263 			{
19264 				self->health -= attack->attack_force;
19265 				if(self->health<=0) kill(self);
19266 			}
19267 		}
19268 	}
19269 	if(nocost && hit && smartbomber) // don't use e, because this can be an item-bomb
19270 	{
19271 		self = smartbomber;
19272 		if(check_energy(1, ANI_SPECIAL))
19273 		{
19274 			self->mp -= self->modeldata.animation[ANI_SPECIAL]->energycost.cost;
19275 		}
19276 		else self->health -= self->modeldata.animation[ANI_SPECIAL]->energycost.cost;
19277 	}
19278 	self = tmpself;
19279 
19280 }
19281 
19282 
19283 ////////////////////////////////
19284 
anything_walk()19285 void anything_walk()
19286 {
19287 	if(self->x < advancex - 80 || self->x > advancex + (videomodes.hRes+80)){
19288 		kill(self);
19289 		return;
19290 	}
19291 	//self->x += self->xdir;
19292 }
19293 
knife_spawn(char * name,int index,float x,float z,float a,int direction,int type,int map)19294 entity * knife_spawn(char *name, int index, float x, float z, float a, int direction, int type, int map)
19295 {
19296 	entity *e = NULL;
19297 
19298 	if(index>=0 ||name) {e = spawn(x, z, a, direction, name, index, NULL);                            if(!e) return NULL; e->ptype = 0; e->a = a;}
19299 	else if(self->weapent && self->weapent->modeldata.project>=0) {e = spawn(x, z, a, direction, NULL, self->weapent->modeldata.project, NULL); if(!e) return NULL; e->ptype = 0; e->a = a;}
19300 	else if(self->animation->custknife>=0) {e = spawn(x, z, a, direction, NULL, self->animation->custknife, NULL);       if(!e) return NULL; e->ptype = 0; e->a = a;}
19301 	else if(self->animation->custpshotno>=0) {e = spawn(x, z, 0, direction, NULL, self->animation->custpshotno, NULL);     if(!e) return NULL; e->ptype = 1; e->a = 0;}
19302 	else if(self->modeldata.knife>=0) {e = spawn(x, z, a, direction, NULL, self->modeldata.knife, NULL);            if(!e) return NULL; e->ptype = 0; e->a = a;}
19303 	else if(self->modeldata.pshotno>=0) {e = spawn(x, z, 0, direction, NULL, self->modeldata.pshotno, NULL);          if(!e) return NULL; e->ptype = 1; e->a = 0;}
19304 	else if(type) {e = spawn(x, z, a, direction, "Shot", -1, NULL);                             if(!e) return NULL; e->ptype = 0; e->a = a;}
19305 	else {e = spawn(x, z, a, direction, "Knife", -1, NULL);                            if(!e) return NULL; e->ptype = 0; e->a = a;}
19306 
19307 	if(e==NULL) return NULL;
19308 	else if(self->modeldata.type == TYPE_PLAYER) e->modeldata.type = TYPE_SHOT;
19309 	else e->modeldata.type = self->modeldata.type;
19310 
19311 	if(self->animation->energycost.cost > 0 && nocost) self->cantfire = 1;    // Can't fire if still exists on screen
19312 
19313 	if(!e->model->speed && !e->modeldata.nomove) e->modeldata.speed = 2;
19314 	else if(e->modeldata.nomove) e->modeldata.speed = 0;
19315 
19316 	e->owner = self;                                                     // Added so projectiles don't hit the owner
19317 	e->nograb = 1;                                                       // Prevents trying to grab a projectile
19318 	e->attacking = 1;
19319 	//e->direction = direction;
19320 	e->think = common_think;
19321 	e->nextthink = time+1;
19322 	e->trymove = NULL;
19323 	e->takedamage = arrow_takedamage;
19324 	e->takeaction = NULL;
19325 	e->modeldata.aimove = AIMOVE1_ARROW;
19326 	if(!e->modeldata.offscreenkill) e->modeldata.offscreenkill = 200; //default value
19327 	e->modeldata.aiattack = AIATTACK1_NOATTACK;
19328 	e->remove_on_attack = e->modeldata.remove;
19329 	e->autokill = e->modeldata.nomove;
19330 
19331 	ent_set_colourmap(e, map);
19332 
19333 	if(e->ptype) e->base = 0;
19334 	else e->base = a;
19335 
19336 	if(e->modeldata.hostile < 0)   e->modeldata.hostile = self->modeldata.hostile;
19337 	if(e->modeldata.candamage < 0) e->modeldata.candamage = self->modeldata.candamage;
19338 
19339 	e->modeldata.subject_to_wall = e->modeldata.subject_to_platform = e->modeldata.subject_to_hole = e->modeldata.subject_to_gravity = 1;
19340 	e->modeldata.no_adjust_base  = 1;
19341 	return e;
19342 }
19343 
19344 
19345 
bomb_explode()19346 void bomb_explode()
19347 {
19348 	if(self->animating) return;
19349 	kill(self);
19350 }
19351 
19352 
bomb_spawn(char * name,int index,float x,float z,float a,int direction,int map)19353 entity * bomb_spawn(char *name, int index, float x, float z, float a, int direction, int map)
19354 {
19355 	entity *e = NULL;
19356 
19357 	if(index>=0 ||name) e = spawn(x, z, a, direction, name, index, NULL);
19358 	else if(self->weapent && self->weapent->modeldata.subtype == SUBTYPE_PROJECTILE && self->weapent->modeldata.project>=0) e = spawn(x, z, a, direction, NULL, self->weapent->modeldata.project, NULL);
19359 	else if(self->animation->custbomb>=0) e = spawn(x, z, a, direction, NULL, self->animation->custbomb, NULL);
19360 	else if(self->modeldata.bomb>=0) e = spawn(x, z, a, direction, NULL, self->modeldata.bomb, NULL);
19361 
19362 	if(e==NULL) return NULL;
19363 
19364 	e->a = a + 0.5;
19365 
19366 	if(self->animation->energycost.cost > 0 && nocost) self->cantfire = 1;    // Can't fire if still exists on screen
19367 
19368 	if(!e->model->speed && !e->modeldata.nomove) e->modeldata.speed = 2;
19369 	else if(e->modeldata.nomove) e->modeldata.speed = 0;
19370 
19371 	e->attacking = 1;
19372 	e->owner = self;                                                     // Added so projectiles don't hit the owner
19373 	e->nograb = 1;                                                       // Prevents trying to grab a projectile
19374 	e->toexplode = 1;                                                    // Set to distinguish exploding projectiles and also so stops falling when hitting an opponent
19375 	ent_set_colourmap(e, map);
19376 	//e->direction = direction;
19377 	toss(e, e->modeldata.jumpheight);
19378 	e->think = common_think;
19379 	e->nextthink = time+1;
19380 	e->trymove = NULL;
19381 	e->takeaction = NULL;
19382 	e->modeldata.aimove = AIMOVE1_BOMB;
19383 	e->modeldata.aiattack = AIATTACK1_NOATTACK;                                    // Well, bomb's attack animation is passive, dont use any A.I. code.
19384 	e->takedamage = common_takedamage;
19385 	e->remove_on_attack = 0;
19386 	e->autokill = e->modeldata.nomove;
19387 
19388 
19389 	// Ok, some old mods use type none, will have troubles.
19390 	// so we give them some default hostile types.
19391 	if(e->modeldata.hostile <0) e->modeldata.hostile = self->modeldata.hostile;
19392 	if(e->modeldata.candamage <0) e->modeldata.candamage = self->modeldata.candamage;
19393 	e->modeldata.no_adjust_base = 0;
19394 	e->modeldata.subject_to_wall = e->modeldata.subject_to_platform = e->modeldata.subject_to_hole = e->modeldata.subject_to_gravity = 1;
19395 	return e;
19396 }
19397 
19398 
19399 // Spawn 3 stars
star_spawn(float x,float z,float a,int direction)19400 int star_spawn(float x, float z, float a, int direction){ // added entity to know which star to load
19401 	entity *e = NULL;
19402 	int i, index = -1;
19403 	char* starname = NULL;
19404 	float fd = (float)((direction ? 2 : -2));
19405 
19406 	//merge enemy/player together, use the same rules
19407 	if(self->weapent && self->weapent->modeldata.subtype==SUBTYPE_PROJECTILE && self->weapent->modeldata.project>=0) index = self->weapent->modeldata.project;
19408 	else if(self->animation->custstar>=0) index = self->animation->custstar; //use any star
19409 	else if(self->modeldata.star>=0) index = self->modeldata.star;
19410 	else starname = "Star"; // this is default star
19411 
19412 	for(i = 0; i<3; i++){
19413 		e = spawn(x, z, a, direction, starname, index, NULL);
19414 		if(e == NULL) return 0;
19415 
19416 		self->attacking = 0;
19417 
19418 		e->takedamage = arrow_takedamage;//enemy_takedamage;    // Players can now hit projectiles
19419 		e->owner = self;    // Added so enemy projectiles don't hit the owner
19420 		e->attacking = 1;
19421 		e->nograb = 1;    // Prevents trying to grab a projectile
19422 		e->xdir = fd/2 * (float)i;
19423 		e->think = common_think;
19424 		e->nextthink = time+1;
19425 		e->trymove = NULL;
19426 		e->takeaction = NULL;
19427 		e->modeldata.aimove = AIMOVE1_STAR;
19428 		e->modeldata.aiattack = AIATTACK1_NOATTACK;
19429 		e->remove_on_attack = e->modeldata.remove;
19430 		e->base = a;
19431 		e->a = a;
19432 		//e->direction = direction;
19433 
19434 		if(e->modeldata.hostile <0) e->modeldata.hostile = self->modeldata.hostile;
19435 		if(e->modeldata.candamage <0) e->modeldata.candamage = self->modeldata.candamage;
19436 
19437 		e->modeldata.subject_to_wall = e->modeldata.subject_to_platform =
19438 		e->modeldata.subject_to_hole = e->modeldata.subject_to_gravity = 1;
19439 		e->modeldata.no_adjust_base = 1;
19440 	}
19441 	return 1;
19442 }
19443 
19444 
19445 
steam_think()19446 void steam_think()
19447 {
19448 	if(!self->animating)
19449 	{
19450 		kill(self);
19451 		return;
19452 	}
19453 
19454 	self->base += 1;
19455 	self->a = self->base;
19456 }
19457 
19458 
19459 
19460 // for the "trap" type   7-1-2005  trap start
trap_think()19461 void trap_think()
19462 {
19463 	if(self->x < advancex-80 || self->x > advancex+(videomodes.hRes+80)){
19464 		//        kill(self);   // 6-2-2005 removed temporarily
19465 		return;
19466 	}
19467 
19468 	self->attacking = 1;
19469 	self->nextthink = time + 1;
19470 }
19471 //    7-1-2005  trap end
19472 
19473 
19474 
19475 
steam_spawn(float x,float z,float a)19476 void steam_spawn(float x, float z, float a){
19477 	entity *e = NULL;
19478 
19479 	e = spawn(x, z, a, 0, "Steam", -1, NULL);
19480 
19481 	if(e==NULL) return;
19482 
19483 	e->base = a;
19484 	e->modeldata.no_adjust_base = 1;
19485 	e->think = steam_think;
19486 }
19487 
19488 
19489 
steamer_think()19490 void steamer_think()
19491 {
19492 	if(self->x < advancex-80 || self->x > advancex+(videomodes.hRes+80)){
19493 		kill(self);
19494 		return;
19495 	}
19496 
19497 	steam_spawn(self->x, self->z, self->a);
19498 	self->nextthink = time + (GAME_SPEED/10) + (rand32()&31);
19499 }
19500 
19501 
19502 
text_think()19503 void text_think(){    // New function so text can be displayed
19504 	 // wait to suicide
19505 	if(!self->animating) kill(self);
19506 }
19507 
19508 ////////////////////////////////
19509 
19510 //homing arrow find its target
19511 // type : target type
homing_find_target(int type)19512 entity * homing_find_target(int type){
19513 	int i, min, max;
19514 	int index = -1;
19515 	//use the walk animation's range
19516 	if(validanim(self,ANI_WALK)){
19517 		min = self->modeldata.animation[ANI_WALK]->range.xmin;
19518 		max = self->modeldata.animation[ANI_WALK]->range.xmax;
19519 	} else {
19520 		min = 0;
19521 		max = 999;
19522 	}
19523 	//find the 'nearest' one
19524 	for(i=0; i<ent_max; i++){
19525 		if( ent_list[i]->exists && ent_list[i] != self //cant target self
19526 			&& (ent_list[i]->modeldata.type & type)
19527 			&& diff(ent_list[i]->x,self->x)+ diff(ent_list[i]->z,self->z) >= min
19528 			&& diff(ent_list[i]->x,self->x)+ diff(ent_list[i]->z,self->z) <= max
19529 			&& ent_list[i]->animation->vulnerable[ent_list[i]->animpos]  )
19530 		{
19531 			if(index <0 || diff(ent_list[i]->x, self->x)+diff(ent_list[i]->z, self->z) < diff(ent_list[index]->x, self->x)+diff(ent_list[index]->z, self->z))
19532 				index = i;
19533 		}
19534 	}
19535 	if( index >=0) return ent_list[index];
19536 	return NULL;
19537 }
19538 
19539 
bike_crash()19540 void bike_crash(){
19541 	int i;
19542 	if(self->direction) self->xdir = 2;
19543 	else self->xdir = -2;
19544 	self->nextthink = time + THINK_SPEED / 2;
19545 	for(i=0; i<levelsets[current_set].maxplayers; i++) control_rumble(i, 100);
19546 	//if(self->x < advancex-100 || self->x > advancex+(videomodes.hRes+100)) kill(self);
19547 }
19548 
19549 
19550 
biker_takedamage(entity * other,s_attack * attack)19551 int biker_takedamage(entity *other, s_attack* attack)
19552 {
19553 	entity *driver = NULL;
19554 	entity* tempself = NULL;
19555 	if(self->dead) return 0;
19556 	// Fell in a hole
19557 	if(self->a < PIT_DEPTH)
19558 	{
19559 		kill(self);
19560 		return 0;
19561 	}
19562 	if(other!=self)set_opponent(other, self);
19563 
19564 	if(attack->no_pain) // don't drop driver until it is dead, because the attack has no pain effect
19565 	{
19566 		checkdamage(other, attack);
19567 		if(self->health>0) return 1; // not dead yet
19568 	}
19569 
19570 	set_pain(self,  self->damagetype, 1);
19571 	self->attacking = 1;
19572 	if(!self->modeldata.offscreenkill) self->modeldata.offscreenkill = 100;
19573 	self->think = bike_crash;
19574 	self->nextthink = time + THINK_SPEED;
19575 	// well, this is the real entity, the driver who take the damage
19576 	if((driver = drop_driver(self)))
19577 	{
19578 		driver->a = self->a;
19579 		tempself = self;
19580 		self = driver;
19581 		self->drop = 1;
19582 		self->direction = tempself->direction;
19583 		if(self->takedamage) self->takedamage(self, attack);
19584 		else self->health -= attack->attack_force;
19585 		self = tempself;
19586 
19587 	}
19588 	self->health = 0;
19589 	checkdeath();
19590 	return 1;
19591 }
19592 
19593 
19594 
obstacle_fall()19595 void obstacle_fall()
19596 {
19597 	if(inair(self)) return;
19598 
19599 	self->xdir = self->zdir = 0;
19600 	if((!self->animating && validanim(self,ANI_DIE)) || !validanim(self,ANI_DIE)) kill(self);    // Fixed so ANI_DIE can be used
19601 }
19602 
19603 
19604 
obstacle_fly()19605 void obstacle_fly()    // Now obstacles can fly when hit like on Simpsons/TMNT
19606 {
19607 	//self->x += self->xdir * 4;    // Equivelant of speed 40
19608 	if(self->x > advancex+(videomodes.hRes + 200) || self->x < advancex-200) kill(self);
19609 
19610 	self->nextthink = time + 2;
19611 }
19612 
19613 
19614 
obstacle_takedamage(entity * other,s_attack * attack)19615 int obstacle_takedamage(entity *other, s_attack* attack)
19616 {
19617 	if(self->a <= PIT_DEPTH)
19618 	{
19619 		kill(self);
19620 		return 0;
19621 	}
19622 
19623 	//self->pain_time = time + (attack->pain_time?attack->pain_time:(GAME_SPEED / 5));
19624 	set_opponent(other, self);
19625 	if(self->opponent && self->opponent->modeldata.type==TYPE_PLAYER)
19626 	{
19627 		control_rumble(self->opponent->playerindex, 75);
19628 	}
19629 	checkdamage(other, attack);
19630 	self->playerindex = other->playerindex;    // Added so points go to the correct player
19631 	addscore(other->playerindex, attack->attack_force*self->modeldata.multiple);    // Points can now be given for hitting an obstacle
19632 
19633 	if(self->health<=0){
19634 
19635 		checkdeath();
19636 
19637 		if(other->x < self->x) self->xdir = 1;
19638 		else self->xdir = -1;
19639 
19640 		self->attacking = 1;    // So obstacles can explode and hurt players/enemies
19641 
19642 		if(self->modeldata.subtype == SUBTYPE_FLYDIE){    // Now obstacles can fly like on Simpsons/TMNT
19643 			self->xdir *= 4;
19644 			self->think = obstacle_fly;
19645 			ent_set_anim(self, ANI_FALL, 0);
19646 		}
19647 		else{
19648 			self->think = obstacle_fall;
19649 
19650 			if(validanim(self,ANI_DIE)) ent_set_anim(self, ANI_DIE, 0);    //  LTB 1-13-05  Die before toss
19651 			else{
19652 				toss(self, self->modeldata.jumpheight/1.333);
19653 				ent_set_anim(self, ANI_FALL, 0);
19654 			}
19655 
19656 			if(!self->modeldata.nodieblink) self->blink = 1;
19657 		}
19658 	}
19659 
19660 	self->nextthink = time + 1;
19661 	return 1;
19662 }
19663 
19664 
smartspawn(s_spawn_entry * props)19665 entity * smartspawn(s_spawn_entry * props){   // 7-1-2005 Entire section replaced with lord balls code
19666 	entity *e = NULL;
19667 	entity* wp = NULL;
19668 	int playercount;
19669 
19670 	if(props == NULL || level == NULL) return NULL;
19671 
19672 	// Now you can make it so enemies/obstacles/etc only spawn if there are 2 players
19673 	if(props->spawnplayer_count >= (playercount = MAX(1,count_ents(TYPE_PLAYER)))){
19674 		if(props->boss) --level->bosses;
19675 		return NULL;
19676 	}
19677 
19678 	if((level->scrolldir&SCROLL_INWARD) || (level->scrolldir&SCROLL_OUTWARD))
19679 		 e = spawn(props->x, props->z + advancey, props->a, props->flip, props->name, props->index, props->model);
19680 	else e = spawn(props->x + advancex, props->z, props->a, props->flip, props->name, props->index, props->model);
19681 
19682 
19683 	if(e == NULL) return NULL;
19684 
19685 	//printf("%s, (%f, %f, %f) - (%f, %f, %f)", props->name, props->x, props->z, props->a, e->x, e->z, e->a);
19686 
19687 	// Alias?
19688 	if(props->alias[0]) strncpy(e->name, props->alias, MAX_NAME_LEN);
19689 	if(props->item) e->item = props->itemindex;
19690 	if(props->itemalias[0]) strncpy(e->itemalias, props->itemalias, MAX_NAME_LEN);
19691 	if(props->itemmap) e->itemmap = props->itemmap;
19692 	if(props->itemhealth) e->itemhealth = props->itemhealth;
19693 	e->itemplayer_count = props->itemplayer_count;
19694 
19695 	if(props->spawntype) e->spawntype = props->spawntype;   //2011_03_23, Pass spawntype.
19696 
19697 	if(props->health[playercount-1] != 0){
19698 		e->health = e->modeldata.health = props->health[playercount-1];
19699 	}
19700 
19701 	if(props->mp != 0){
19702 		e->mp = e->modeldata.mp = props->mp;
19703 	}
19704 
19705 	if(props->score != 0) e->modeldata.score = props->score;    // Overwrite score if exists in the level's. txt file
19706 	if(props->multiple != 0)e->modeldata.multiple = props->multiple;    // Overwrite multiple if exists in the level's .txt file
19707 
19708 	if(!e->map && props->colourmap)
19709 	{
19710 		ent_set_colourmap(e, props->colourmap);
19711 	}
19712 
19713 	if(props->aggression) e->modeldata.aggression = props->aggression;  // Aggression can be changed with spawn points now
19714 	if(props->itemtrans) e->itemtrans = props->itemtrans;
19715 	if(props->alpha) e->modeldata.alpha = props->alpha;
19716 
19717 	// Feb 26, 2005 - Store the original map to be able to restore with dying flash
19718 	if(props->dying){
19719 		e->dying = props->dying;    // Feb 26, 2005 - Used to define which colourmap is used for the dying flash
19720 		e->per1 = props->per1;    // Mar 21, 2005 - Used to store custom percentages
19721 		e->per2 = props->per2;    // Mar 21, 2005 - Used to store custom percentages
19722 	}
19723 
19724 	if(props->nolife) e->modeldata.nolife = props->nolife;    // Overwrite whether live is visible or not
19725 	e->boss = props->boss;
19726 
19727 	if(props->boss && level && level->bossmusic[0])
19728 	{
19729 		music(level->bossmusic, 1, level->bossmusic_offset);
19730 	}
19731 
19732 	// give the entity a weapon item
19733 	if(props->weapon)
19734 	{
19735 		wp = spawn(e->x, 100000, 0, 0, props->weapon, props->weaponindex, props->weaponmodel);
19736 		if(wp){
19737 			//ent_default_init(wp);
19738 			set_weapon(e, wp->modeldata.weapnum, 0);
19739 			e->weapent = wp;
19740 		}
19741 	}
19742 
19743 	//ent_default_init(e);
19744 	execute_onspawn_script(e);
19745 	execute_spawn_script(props, e);
19746 	return e;
19747 }   // 7-1-2005 replaced section ends here
19748 
19749 
19750 
spawnplayer(int index)19751 void spawnplayer(int index)
19752 {
19753 	s_spawn_entry p;
19754 	//s_model * model = NULL;
19755 	int wall;
19756 	int xc, zc, find = 0;
19757 	index &= 3;
19758 
19759 //    model = find_model(player[index].name);
19760 //    if(model == NULL) return;
19761 
19762 	memset(&p, 0, sizeof(s_spawn_entry));
19763 	p.name= player[index].name;
19764 	p.index = -1;
19765 	p.itemindex = -1;
19766 	p.weaponindex = -1;
19767 	p.colourmap = player[index].colourmap;
19768 	p.spawnplayer_count = -1;
19769 
19770 	if(level->scrolldir&SCROLL_LEFT){
19771 		if(level->spawn[index][0]) p.x = (float)(videomodes.hRes - level->spawn[index][0]);
19772 		else p.x = (float)((videomodes.hRes-20) - 30*index);
19773 	}
19774 	else{
19775 		if(level->spawn[index][0]) p.x = (float)(level->spawn[index][0]);
19776 		else p.x = (float)(20 + 30*index);
19777 		p.flip = 1;
19778 	}
19779 	if(level->spawn[index][1]){
19780 		if(level->scrolldir&(SCROLL_INWARD|SCROLL_OUTWARD))
19781 			p.z = (float)(level->spawn[index][1]);
19782 		else p.z = (float)(PLAYER_MIN_Z + level->spawn[index][1]);
19783 	}
19784 	else if(PLAYER_MAX_Z - PLAYER_MIN_Z > 5) p.z = (float)(PLAYER_MIN_Z + 5);
19785 	else p.z = (float)PLAYER_MIN_Z;
19786 	//////////////////checking holes/ walls///////////////////////////////////
19787 	for(xc = 0; xc < videomodes.hRes / 4; xc++){
19788 		if(p.x > videomodes.hRes) p.x -= videomodes.hRes;
19789 		if(p.x < 0) p.x += videomodes.hRes;
19790 		if(PLAYER_MIN_Z==PLAYER_MAX_Z)
19791 		{
19792 			wall = checkwall(advancex + p.x, p.z);
19793 			if(wall >= 0 && level->walls[wall][7] < MAX_WALL_HEIGHT) break; //found
19794 			if(checkhole(advancex + p.x, p.z) || (wall>=0 && level->walls[wall][7] >= MAX_WALL_HEIGHT)) find = 0;
19795 			else break; // found
19796 		}
19797 		else for(zc=0;zc < (PLAYER_MAX_Z - PLAYER_MIN_Z) / 3; zc++, p.z += 3){
19798 			if(p.z > PLAYER_MAX_Z) p.z -= PLAYER_MAX_Z - PLAYER_MIN_Z;
19799 			if(p.z < PLAYER_MIN_Z) p.z += PLAYER_MAX_Z - PLAYER_MIN_Z;
19800 			wall = checkwall(advancex + p.x, p.z);
19801 			if(wall >= 0 && level->walls[wall][7] < MAX_WALL_HEIGHT) {find = 1; break;}
19802 			else if(wall >=0 && level->walls[wall][7] >= MAX_WALL_HEIGHT) continue;
19803 			if(checkhole(advancex + p.x, p.z)) continue;
19804 			find = 1;
19805 			break;
19806 		}
19807 		if(find) break;
19808 		p.x += (level->scrolldir&SCROLL_LEFT)?-4:4;
19809 	}
19810 	///////////////////////////////////////////////////////////////////////
19811 	currentspawnplayer = index;
19812 	player[index].ent = smartspawn(&p);
19813 
19814 	if(player[index].ent==NULL) shutdown(1, "Fatal: unable to spawn player from '%s'", &p.name);
19815 
19816 	player[index].ent->playerindex = index;
19817 	if(nomaxrushreset[4] >= 1) player[index].ent->rush[1] = nomaxrushreset[index];
19818 	else player[index].ent->rush[1] = 0;
19819 
19820 	memset(player[index].combokey, 0, sizeof(u32)*MAX_SPECIAL_INPUTS);
19821 	memset(player[index].inputtime, 0, sizeof(u32)*MAX_SPECIAL_INPUTS);
19822 	player[index].combostep = 0;
19823 
19824 	if(player[index].spawnhealth) player[index].ent->health = player[index].spawnhealth + 5;
19825 	if(player[index].ent->health > player[index].ent->modeldata.health) player[index].ent->health = player[index].ent->modeldata.health;
19826 
19827 	//mp little recorver after a level by tails
19828 	if(player[index].spawnmp) player[index].ent->mp = player[index].spawnmp + 2;
19829 	if(player[index].ent->mp > player[index].ent->modeldata.mp) player[index].ent->mp = player[index].ent->modeldata.mp;
19830 
19831 	if(player[index].weapnum) set_weapon(player[index].ent, player[index].weapnum, 0);
19832 	else set_weapon(player[index].ent, level->setweap, 0);
19833 }
19834 
19835 
19836 
19837 
19838 
time_over()19839 void time_over()
19840 {
19841 	int i;
19842 	s_attack attack;
19843 
19844 	attack = emptyattack;
19845 	attack.attack_type = max_attack_types;
19846 	attack.dropv[0] = default_model_dropv[0];
19847 	attack.dropv[1] = default_model_dropv[1];
19848 	attack.dropv[2] = default_model_dropv[2];
19849 	if(level->type == 1) level_completed = 1;        //    Feb 25, 2005 - Used for bonus levels so a life isn't taken away if time expires.level->type == 1 means bonus level, else regular
19850 	else if(!level_completed)
19851 	{
19852 		endgame = 1;
19853 		for(i=0; i<4; i++)
19854 		{
19855 			if(player[i].ent)
19856 			{
19857 				endgame = 0;
19858 				self = player[i].ent;
19859 				attack.attack_force = self->health;
19860 				self->takedamage(self, &attack);
19861 			}
19862 		}
19863 
19864 		if(SAMPLE_TIMEOVER >= 0) sound_play_sample(SAMPLE_TIMEOVER, 0, savedata.effectvol,savedata.effectvol, 100);
19865 
19866 		timeleft = level->settime * COUNTER_SPEED;    // Feb 24, 2005 - This line moved here to set custom time
19867 		if(!endgame)showtimeover = 1;
19868 	}
19869 }
19870 
19871 
19872 // ----------------------- Update functions ------------------------------
19873 
update_scroller()19874 void update_scroller(){
19875 	float to=0;
19876 	int i, againstend = 0;
19877 	int numplay=0; //4player
19878 	float tx = advancex, ty = advancey;
19879 	static int scrolladd = 0;
19880 	scrolldx = scrolldy = 0;
19881 
19882 	if(time < level->advancetime || freezeall) return;    // Added freezeall so backgrounds/scrolling don't update if animations are frozen
19883 
19884 /*
19885 	//level->advancetime = time + (GAME_SPEED/100);    // Changed so scrolling speeds up for faster players
19886 	level->advancetime = time  -
19887 		((player[0].ent && (player[0].ent->modeldata.speed >= 12 || player[0].ent->modeldata.runspeed >= 12)) ||
19888 		 (player[1].ent && (player[1].ent->modeldata.speed >= 12 || player[1].ent->modeldata.runspeed >= 12)) ||
19889 		 (player[2].ent && (player[2].ent->modeldata.speed >= 12 || player[2].ent->modeldata.runspeed >= 12)) ||
19890 		 (player[3].ent && (player[3].ent->modeldata.speed >= 12 || player[3].ent->modeldata.runspeed >= 12)) );    // Changed so if your player is faster the backgrounds scroll faster*/
19891 
19892 	level->advancetime = time;
19893 
19894 	if(level_completed) return;
19895 
19896 	if(current_spawn>=level->numspawns && !findent(TYPE_ENEMY) &&
19897 	((player[0].ent && !player[0].ent->dead) || (player[1].ent && !player[1].ent->dead) || (player[2].ent && !player[2].ent->dead) || (player[3].ent && !player[3].ent->dead))
19898 	){
19899 		if(!findent(TYPE_ENDLEVEL) && ((!findent(TYPE_ITEM|TYPE_OBSTACLE) && level->type==1) || level->type == 0)){    // Feb 25, 2005 - Added so obstacles
19900 			level_completed = 1;                                                // can be used for bonus levels
19901 		}
19902 	}
19903 	else if(count_ents(TYPE_ENEMY) < groupmin){
19904 		while(count_ents(TYPE_ENEMY) < groupmax &&
19905 			current_spawn<level->numspawns &&
19906 			level->pos >= level->spawnpoints[current_spawn].at
19907 			){
19908 				if(level->spawnpoints[current_spawn].musicfade){
19909 					musicfade[0] = (float)level->spawnpoints[current_spawn].musicfade;
19910 					musicfade[1] = (float)savedata.musicvol;
19911 				}
19912 				else if(level->spawnpoints[current_spawn].music[0]){
19913 					strncpy(musicname, level->spawnpoints[current_spawn].music, 128);
19914 					musicoffset = level->spawnpoints[current_spawn].musicoffset;
19915 					musicloop = 1;
19916 				}
19917 				else if(level->spawnpoints[current_spawn].wait){
19918 					level->waiting = 1;
19919 					go_time = 0;
19920 				}
19921 				else if(level->spawnpoints[current_spawn].groupmin || level->spawnpoints[current_spawn].groupmax){
19922 					groupmin = level->spawnpoints[current_spawn].groupmin;
19923 					groupmax = level->spawnpoints[current_spawn].groupmax;
19924 				}
19925 				else if(level->spawnpoints[current_spawn].nojoin!=0){
19926 					nojoin = (level->spawnpoints[current_spawn].nojoin==1);
19927 				}
19928 				else if(level->spawnpoints[current_spawn].scrollminz ||
19929 					level->spawnpoints[current_spawn].scrollmaxz){
19930 						scrollminz = (float)level->spawnpoints[current_spawn].scrollminz;
19931 						scrollmaxz = (float)level->spawnpoints[current_spawn].scrollmaxz;
19932 						if(!time) advancey = scrollminz; // reset y if spawn at very beginning
19933 					}
19934 				else if(level->spawnpoints[current_spawn].blockade){
19935 					// assume level spawn entry will not roll back, so just change it to 0 here
19936 					if(level->spawnpoints[current_spawn].blockade<0) level->spawnpoints[current_spawn].blockade = 0;
19937 					blockade = (float)level->spawnpoints[current_spawn].blockade;
19938 				}
19939 				else if(level->spawnpoints[current_spawn].palette!=0){
19940 					// assume level spawn entry will not roll back, so just change it to 0 here
19941 					if(level->spawnpoints[current_spawn].palette<0) level->spawnpoints[current_spawn].palette = 0;
19942 					change_system_palette(level->spawnpoints[current_spawn].palette);
19943 				}
19944 				else if(level->spawnpoints[current_spawn].light[1]){ // change light direction for gfxshadow
19945 					light[0] = level->spawnpoints[current_spawn].light[0];
19946 					light[1] = level->spawnpoints[current_spawn].light[1];
19947 				}
19948 				else if(level->spawnpoints[current_spawn].shadowcolor){ // change color for gfxshadow
19949 					shadowcolor = level->spawnpoints[current_spawn].shadowcolor;
19950 					if(shadowcolor==-1) shadowcolor = 0;
19951 					else if(shadowcolor==-2) shadowcolor = -1;
19952 				}
19953 				else if(level->spawnpoints[current_spawn].shadowalpha){ // change color for gfxshadow
19954 					shadowalpha = level->spawnpoints[current_spawn].shadowalpha;
19955 					if(shadowalpha==-1) shadowalpha = 0;
19956 				}
19957 				else smartspawn(&level->spawnpoints[current_spawn]);
19958 				++current_spawn;
19959 			}
19960 	}
19961 
19962 	for(i=0; i<levelsets[current_set].maxplayers; i++)
19963 	{
19964 		if(player[i].ent) numplay++;
19965 	}
19966 
19967 	if(level->waiting){
19968 		// Wait for all enemies to be defeated
19969 		if(!findent(TYPE_ENEMY))
19970 		{
19971 			level->waiting = 0;
19972 			if(level->noreset<=1) timeleft = level->settime * COUNTER_SPEED;    // Feb 24, 2005 - This line moved here to set custom time
19973 			go_time = time + 3*GAME_SPEED;
19974 		}
19975 	}
19976 	if(numplay == 0) return;
19977 
19978 
19979 
19980 	if(!level->waiting)
19981 	{
19982 		if(level->scrolldir&SCROLL_RIGHT){
19983 
19984 			againstend = (level->width<=videomodes.hRes);
19985 
19986 			for(i=0; i<levelsets[current_set].maxplayers; i++)
19987 			{
19988 				if(player[i].ent)
19989 				{
19990 					to += (int)player[i].ent->x;
19991 				}
19992 			}
19993 
19994 			to /= numplay;
19995 			to -= (videomodes.hRes/2);
19996 
19997 			to += level->cameraxoffset;
19998 
19999 			if((level->scrolldir&SCROLL_BACK) && to < blockade) to = blockade;
20000 
20001 			if(to > advancex){
20002 				if(to > advancex+level->scrollspeed) to = advancex+level->scrollspeed;
20003 				advancex = (float)to;
20004 			}
20005 
20006 			if(level->scrolldir&SCROLL_BACK){    // Can't go back to the beginning
20007 
20008 				if(to < advancex && to > blockade){
20009 					if(to < advancex-level->scrollspeed) to = advancex-level->scrollspeed;
20010 					advancex = (float)to;
20011 				}
20012 			}
20013 
20014 			if(advancex < 0) advancex = 0;
20015 			if(advancex > level->width-videomodes.hRes) {
20016 				advancex = (float)level->width-videomodes.hRes;
20017 				againstend = 1;
20018 			}
20019 
20020 			if(againstend) level->pos++;
20021 			else level->pos = (int)advancex;
20022 
20023 
20024 		}
20025 		else if(level->scrolldir&SCROLL_LEFT){
20026 
20027 			againstend = (level->width<=videomodes.hRes);
20028 
20029 			for(i=0; i<levelsets[current_set].maxplayers; i++)
20030 			{
20031 				if(player[i].ent)
20032 				{
20033 					to += (int)player[i].ent->x;
20034 				}
20035 			}
20036 
20037 			to /= numplay;
20038 			to -= (videomodes.hRes/2);
20039 
20040 			to += level->cameraxoffset;
20041 
20042 			if(to < advancex){
20043 				if(to < advancex-level->scrollspeed) {
20044 					to = advancex-level->scrollspeed;
20045 					againstend = 1;
20046 				}
20047 				advancex = (float)to;
20048 			}
20049 			if(level->scrolldir&SCROLL_BACK){    // Can't go back to the beginning
20050 
20051 				if(to > advancex){
20052 					if(to > advancex+level->scrollspeed) to = advancex+level->scrollspeed;
20053 					advancex = (float)to;
20054 				}
20055 			}
20056 			if(advancex > level->width-videomodes.hRes) advancex = (float)level->width-videomodes.hRes;
20057 			if((level->scrolldir&SCROLL_BACK) && level->width- videomodes.hRes - advancex < blockade) advancex = level->width- videomodes.hRes - blockade;
20058 			if(advancex < 0) advancex = 0;
20059 
20060 			if(againstend) level->pos++;
20061 			else level->pos = (int)((level->width-videomodes.hRes) - advancex);
20062 		}
20063 		else if(level->scrolldir&SCROLL_OUTWARD){ // z scroll only
20064 
20065 			for(i=0; i<levelsets[current_set].maxplayers; i++)
20066 			{
20067 				if(player[i].ent)
20068 				{
20069 					to += (int)player[i].ent->z;
20070 				}
20071 			}
20072 
20073 			to /= numplay;
20074 			to -= (videomodes.vRes/2);
20075 
20076 			to += level->cameraxoffset;
20077 
20078 			if(to > advancey){
20079 				if(to > advancey+level->scrollspeed) to = advancey+level->scrollspeed;
20080 				advancey = (float)to;
20081 			}
20082 
20083 			if(level->scrolldir&SCROLL_BACK){    // Can't go back to the beginning
20084 
20085 				if(to < advancey){
20086 					if(to < advancey-level->scrollspeed) to = advancey-level->scrollspeed;
20087 					advancey = (float)to;
20088 				}
20089 			}
20090 
20091 			if(advancey > panel_height-videomodes.vRes) {
20092 				advancey = (float)panel_height-videomodes.vRes;
20093 				againstend = 1;
20094 			}
20095 
20096 			if((level->scrolldir&SCROLL_BACK) && advancey < blockade) advancey = blockade;
20097 			if(advancey < 0) advancey = 0;
20098 
20099 			if(againstend) level->pos++;
20100 			else level->pos = (int)advancey;
20101 		}
20102 		else if(level->scrolldir&SCROLL_INWARD){
20103 			for(i=0; i<levelsets[current_set].maxplayers; i++)
20104 			{
20105 				if(player[i].ent)
20106 				{
20107 					to += (int)player[i].ent->z;
20108 				}
20109 			}
20110 
20111 			to /= numplay;
20112 			to -= (videomodes.vRes/2);
20113 
20114 			to += level->camerazoffset;
20115 
20116 			if(to < advancey){
20117 				if(to < advancey-level->scrollspeed){
20118 					to = advancey-level->scrollspeed;
20119 					againstend = 1;
20120 				}
20121 				advancey = (float)to;
20122 			}
20123 			if(level->scrolldir&SCROLL_BACK){    // Can't go back to the beginning
20124 
20125 				if(to > advancey){
20126 					if(to > advancey+level->scrollspeed) to = advancey+level->scrollspeed;
20127 					advancey = (float)to;
20128 				}
20129 			}
20130 			if(advancey > panel_height-videomodes.vRes) advancey = (float)panel_height-videomodes.vRes;
20131 			if((level->scrolldir&SCROLL_BACK) && panel_height- videomodes.vRes - advancey < blockade) advancey = panel_height- videomodes.vRes - blockade;
20132 			if(advancey < 0) advancey = 0;
20133 
20134 			if(againstend) level->pos++;
20135 			else level->pos = (int)((panel_height-videomodes.vRes) - advancey);
20136 		}
20137 		//up down, elevator stage
20138 		else if(level->scrolldir&(SCROLL_UP|SCROLL_DOWN))
20139 		{
20140 			//advancey += 0.5;
20141 			if(scrolladd==1)
20142 			{
20143 				scrolladd=0;
20144 				advancey++;
20145 			}
20146 			else
20147 			{
20148 				scrolladd++;
20149 			}
20150 			level->pos = (int)advancey;
20151 		}
20152 	}//if(!level->waiting)
20153 
20154 	// z auto-scroll, 2007 - 2 - 10 by UTunnels
20155 	if((level->scrolldir&SCROLL_LEFT) || (level->scrolldir&SCROLL_RIGHT)) // added scroll type both; weird things can happen, but only if the modder is lazy in using blockades, lol
20156 	{
20157 		for(i=0, to=0; i<levelsets[current_set].maxplayers; i++)
20158 		{
20159 			if(player[i].ent)
20160 			{
20161 				to += (int)(player[i].ent->z - (cameratype==1?player[i].ent->a:0));
20162 			}
20163 		}
20164 
20165 		to /= numplay;
20166 		to -= (videomodes.vRes/2);
20167 
20168 		to += level->camerazoffset;
20169 
20170 		// new scroll limit
20171 		if(scrollmaxz && to > scrollmaxz) to = scrollmaxz;
20172 		if(scrollminz && to < scrollminz) to = scrollminz;
20173 
20174 		if(to > advancey){
20175 			if(to > advancey+level->scrollspeed) to = advancey+level->scrollspeed;
20176 			advancey = (float)to;
20177 		}
20178 
20179 		if(to < advancey){
20180 			if(to < advancey-level->scrollspeed) to = advancey-level->scrollspeed;
20181 			advancey = (float)to;
20182 		}
20183 
20184 		if(advancey > panel_height - (level->rocking?16:12) -videomodes.vRes) advancey = (float)(panel_height - (level->rocking?16:12) -videomodes.vRes);
20185 		if(advancey < 0) advancey = 0;
20186 	}
20187 	// now x auto scroll
20188 	else if((level->scrolldir&SCROLL_INWARD) || (level->scrolldir&SCROLL_OUTWARD))
20189 	{
20190 		for(i=0, to=0; i<levelsets[current_set].maxplayers; i++)
20191 		{
20192 			if(player[i].ent)
20193 			{
20194 				to += (int)player[i].ent->x;
20195 			}
20196 		}
20197 
20198 		to /= numplay;
20199 		to -= (videomodes.hRes/2);
20200 
20201 		to += level->cameraxoffset;
20202 
20203 		// new scroll limit
20204 		if(scrollmaxz && to > scrollmaxz) to = scrollmaxz;
20205 		if(scrollminz && to < scrollminz) to = scrollminz;
20206 
20207 		if(to > advancex){
20208 			if(to > advancex+level->scrollspeed) to = advancex+level->scrollspeed;
20209 			advancex = (float)to;
20210 		}
20211 
20212 		if(to < advancex){
20213 			if(to < advancex-level->scrollspeed) to = advancex-level->scrollspeed;
20214 			advancex = (float)to;
20215 		}
20216 
20217 		if(advancex > level->width - videomodes.hRes) advancex = (float)(level->width - videomodes.hRes);
20218 		if(advancex < 0) advancex = 0;
20219 	}
20220 	//end of z auto-scroll
20221 	// global value for type_panel
20222 	scrolldx = advancex - tx;
20223 	scrolldy = advancey - ty;
20224 }
20225 
20226 
update_scrolled_bg()20227 void update_scrolled_bg(){
20228 	int i=0;
20229 	float rocktravel;
20230 	unsigned char neonp[32];//3*8
20231 	static int neon_count = 0;
20232 	static int rockpos = 0;
20233 	static int rockoffssine[32] = {
20234 		2, 2, 3, 4, 5, 6, 7, 7,
20235 			8, 8, 9, 9, 9, 9, 8, 8,
20236 			7, 7, 6, 5, 4, 3, 2, 2,
20237 			1, 1, 0, 0, 0, 0, 1, 1
20238 	};   // normal rock
20239 	static int rockoffsshake[32] = {
20240 		2, 2, 2, 2, 2, 2, 2, 2,
20241 			2, 2, 0, 4, 2, 0, 4, 2,
20242 			2, 2, 2, 2, 2, 2, 2, 2,
20243 			2, 2, 0, 4, 2, 0, 4, 2,
20244 	};   // slow, constant jarring rock, like on a train
20245 	static int rockoffsrumble[32] = {
20246 		2, 2, 3, 3, 2, 2, 3, 3,
20247 			2, 2, 3, 3, 2, 3, 2, 3,
20248 			2, 2, 3, 3, 2, 2, 3, 3,
20249 			2, 2, 3, 3, 2, 3, 2, 3,
20250 	};   // fast, constant rumbling, like in/on a van or trailer
20251 	int pb = pixelbytes[(int)screenformat];
20252 
20253 	if(time>=neon_time && !freezeall){    // Added freezeall so neon lights don't update if animations are frozen
20254 		if(pixelformat==PIXEL_8) // under 8bit mode just cycle the palette from 128 to 135
20255 		{
20256 			for(i=0; i<8; i++)  neontable[128+i] = 128 + ((i+neon_count) & 7);
20257 		}
20258 		else if(pixelformat==PIXEL_x8) // copy palette under 16/32bit mode
20259 		{
20260 			memcpy(neonp, neontable+128*pb, 8*pb);
20261 			memcpy(neontable+128*pb, neonp+2*pb, 6*pb);
20262 			memcpy(neontable+(128+6)*pb, neonp, 2*pb);
20263 		}
20264 		neon_time = time + (GAME_SPEED/3);
20265 		neon_count += 2;
20266 	}
20267 
20268 	if(!freezeall){
20269 		rocktravel = (level->rocking)?((time-traveltime)/((float)GAME_SPEED/30)):0; // no like in real life, maybe
20270 		if(level->bgspeed<0) rocktravel = -rocktravel;
20271 		bgtravelled += (time-traveltime)*level->bgspeed/30*4 + rocktravel;
20272 	}else texttime += time-traveltime;
20273 
20274 	timevar = time - texttime;
20275 
20276 	if(level->rocking){
20277 		rockpos = (timevar/(GAME_SPEED/8)) & 31;
20278 		if(level->rocking == 1) gfx_y_offset = level->quake - 4 - rockoffssine[rockpos];
20279 		else if(level->rocking == 2) gfx_y_offset = level->quake - 4 - rockoffsshake[rockpos];
20280 		else if(level->rocking == 3) gfx_y_offset = level->quake - 4 - rockoffsrumble[rockpos];
20281 	}
20282 	else{
20283 		if(level->quake >= 0) gfx_y_offset = level->quake-4;
20284 		else           gfx_y_offset = level->quake+4;
20285 	}
20286 
20287 	//if(level->scrolldir!=SCROLL_UP && level->scrolldir!=SCROLL_DOWN) gfx_y_offset -= advancey;
20288 	gfx_y_offset += gfx_y_offset_adj;   //2011_04_03, DC: Apply modder adjustment.
20289 
20290 	traveltime = time;
20291 
20292 	if(time>=level->quaketime){
20293 		level->quake /= 2;
20294 		level->quaketime = time + (GAME_SPEED/25);
20295 	}
20296 }
20297 
draw_scrolled_bg()20298 void draw_scrolled_bg(){
20299 	int index=0, x, z, i=0, j, l, m;
20300 	s_layer* layer;
20301 	int width, height;
20302 
20303 	int vpx, vpy, vpw, vph;
20304 
20305 	if(viewportw>0){
20306 		vpx = viewportx;
20307 		vpy = viewporty;
20308 		vpw = viewportw;
20309 		vph = viewporth;
20310 	}else{
20311 		vpx = vpy = 0;
20312 		vpw = videomodes.hRes;
20313 		vph = videomodes.vRes;
20314 	}
20315 
20316 	//if(level) printf("%d %d %d %d\n", vpx, vpy, vpw, vph);
20317 
20318 	s_drawmethod screenmethod=plainmethod, *pscreenmethod=&screenmethod;
20319 
20320 	for(i=0; i<level->numholes; i++) spriteq_add_sprite((int)(level->holes[i][0]-screenx+gfx_x_offset),(int)(level->holes[i][1] - level->holes[i][6] - screeny + gfx_y_offset), HOLE_Z, holesprite, pscreenmethod, 0);
20321 
20322 	for(index = 0; index < level->numlayersref; index++)
20323 	{
20324 		layer = level->layersref+index;
20325 
20326 		screenmethod=layer->drawmethod;
20327 
20328 		//printf("layer %d, handle:%u, z:%d\n", index, layer->gfx.handle, layer->z);
20329 
20330 		if(!layer->drawmethod.xrepeat || !layer->drawmethod.yrepeat || !layer->enabled) continue;
20331 
20332 		width = screenmethod.xspan = layer->width + layer->xspacing;
20333 		height = screenmethod.yspan = layer->height + layer->zspacing;
20334 
20335 		x = (int)(layer->xoffset - (advancex + bgtravelled *layer->bgspeedratio)*(1.0-layer->xratio) ) ;
20336 
20337 		//printf("layerxratio %f  %d %f\n ", layer->xratio, x, layer->bgspeedratio);
20338 
20339 		if((level->scrolldir&SCROLL_UP))
20340 			z = (int)(layer->zoffset + advancey*(1.0-layer->zratio) ) ;
20341 		else
20342 			z = (int)(layer->zoffset - advancey*(1.0-layer->zratio) ) ;
20343 
20344 		if(layer->quake) {
20345 			x += gfx_x_offset;
20346 			z += gfx_y_offset;
20347 			//printf("%d y %d %d\n", index, gfx_y_offset, z);
20348 		}
20349 
20350 		x -= vpx; z -= vpy;
20351 
20352 
20353 		if(x<0) {
20354 			i = (-x)/width;
20355 			x %= width;
20356 		} else i = 0;
20357 
20358 		if(i>0 && screenmethod.water.watermode!=3  && screenmethod.water.amplitude) {
20359 			i--;
20360 			x -= width;
20361 		}
20362 
20363 		if(z<0){
20364 			j = (-z)/height;
20365 			z %= height;
20366 		} else j = 0;
20367 		if(layer->neon){
20368 			if(pixelformat!=PIXEL_x8 || current_palette<=0)
20369 				screenmethod.table = neontable;
20370 		}else {
20371 			screenmethod.table = (pixelformat==PIXEL_x8)?(current_palette>0?(level->palettes[current_palette-1]):NULL):NULL;
20372 		}
20373 		screenmethod.water.wavetime =  (int)(timevar*screenmethod.water.wavespeed);
20374 		screenmethod.xrepeat = screenmethod.yrepeat = 0;
20375 		for(m=z; j<layer->drawmethod.yrepeat && m<vph; m+=height, j++, screenmethod.yrepeat++);
20376 		for(l=x; i<layer->drawmethod.xrepeat && l<vpw + (screenmethod.water.watermode==3?0:screenmethod.water.amplitude*2); l+=width, i++, screenmethod.xrepeat++);
20377 
20378 		if(layer->gfx.screen->magic==screen_magic){
20379 			spriteq_add_screen(x+vpx, z+vpy, layer->z, layer->gfx.screen, &screenmethod, index);
20380 		}
20381 		else if(layer->gfx.sprite->magic==sprite_magic){
20382 			spriteq_add_frame(x+vpx, z+vpy, layer->z, layer->gfx.sprite, &screenmethod, index);
20383 		}
20384 
20385 		//printf("******%d\t%d\t%d\t%d\t%d*****\n", x+vpx, z+vpy, layer->z, screenmethod.xrepeat, screenmethod.yrepeat);
20386 	}
20387 
20388 
20389 }
20390 
20391 #ifndef DISABLE_MOVIE
movie_openfile(int save)20392 void movie_openfile(int save)
20393 {
20394 	char path[256] = {""};
20395 	char tmpname[256] = {""};
20396 	moviebuffer = malloc(sizeof(*moviebuffer)*MOVIEBUF_LEN);
20397 	if(!moviebuffer) return ;
20398 	memset(moviebuffer, 0, sizeof(*moviebuffer)*MOVIEBUF_LEN);
20399 	getBasePath(path, "Saves", 0);
20400 	getPakName(tmpname, 3);
20401 	strcat(path, tmpname);
20402 	if(save) moviefile = fopen(path, "wb");
20403 	else moviefile = fopen(path, "rb");
20404 	if(moviefile == NULL) return;
20405 	if(save)
20406 	{
20407 		movielog = 1;
20408 		movieplay = 0;
20409 		movieloglen = 0;
20410 		moviebufptr = 0;
20411 	}
20412 	else
20413 	{
20414 		fseek(moviefile, 0, SEEK_END);
20415 		movielen = ftell(moviefile);
20416 		movielen /= sizeof(*moviebuffer);
20417 		fseek(moviefile, 0, SEEK_SET);
20418 		movielog = 0;
20419 		movieplay = 1;
20420 		movieloglen = 0;
20421 		moviebufptr = MOVIEBUF_LEN;
20422 	}
20423 }
20424 
movie_flushbuf()20425 void movie_flushbuf()
20426 {
20427 	if(!moviefile || !moviebuffer) return;
20428     fwrite(moviebuffer, sizeof(*moviebuffer), MOVIEBUF_LEN, moviefile);
20429 	memset(moviebuffer, 0, sizeof(*moviebuffer)*MOVIEBUF_LEN);
20430 	moviebufptr = 0;
20431 }
20432 
movie_closefile()20433 void movie_closefile()
20434 {
20435 	if(moviefile) fclose(moviefile);
20436 	if(moviebuffer) free(moviebuffer);
20437 	moviebuffer = NULL;
20438 	moviefile = NULL;
20439 	moviebufptr = 0;
20440 	movielog = 0;
20441 	movieplay = 0;
20442 }
20443 
movie_update(s_playercontrols ** pctrls)20444 void movie_update(s_playercontrols ** pctrls)
20445 {
20446 	int p;
20447 	if(!moviefile || !moviebuffer) return;
20448 	if(moviebufptr==MOVIEBUF_LEN)
20449 	{
20450 		moviebufptr = 0;
20451 		if(movieloglen<=movielen)
20452 		{
20453             fread(moviebuffer, sizeof(*moviebuffer), MOVIEBUF_LEN, moviefile);
20454 			movieloglen += MOVIEBUF_LEN;
20455 		}
20456 		else
20457 		{
20458 			movie_closefile();
20459 			return;
20460 		}
20461 	}
20462 	for(p=0; p<4; p++)
20463 	{
20464 		playercontrolpointers[p]->keyflags = moviebuffer[moviebufptr][p][0];
20465 		playercontrolpointers[p]->newkeyflags = moviebuffer[moviebufptr][p][1];
20466 	}
20467 	seed = moviebuffer[moviebufptr][4][0];
20468 	interval = moviebuffer[moviebufptr][4][1];
20469 	moviebufptr++;
20470 }
20471 
movie_save(s_playercontrols ** pctrls)20472 void movie_save(s_playercontrols ** pctrls)
20473 {
20474 	int p;
20475 	if(!moviefile || !moviebuffer) return;
20476 	if(moviebufptr==MOVIEBUF_LEN)
20477 	{
20478 		movie_flushbuf();
20479 		movieloglen += MOVIEBUF_LEN;
20480 	}
20481 	for(p=0; p<4; p++)
20482 	{
20483 		moviebuffer[moviebufptr][p][0] = playercontrolpointers[p]->keyflags;
20484 		moviebuffer[moviebufptr][p][1] = playercontrolpointers[p]->newkeyflags;
20485 	}
20486 	moviebuffer[moviebufptr][4][0] = seed;
20487 	moviebuffer[moviebufptr][4][1] = interval;
20488 	moviebufptr++;
20489 }
20490 
20491 #endif
20492 
20493 
inputrefresh()20494 void inputrefresh()
20495 {
20496 	int p;
20497 	s_player* pl;
20498 	u32 k;
20499 
20500 #ifndef DISABLE_MOVIE
20501 	int moviestop = 0;
20502 	if(movieplay)
20503 	{
20504 		control_update(playercontrolpointers, MAX_PLAYERS);
20505 		for(p=0; p<MAX_PLAYERS; p++)
20506 		{
20507 			if(playercontrolpointers[p]->newkeyflags & FLAG_ESC)
20508 			{
20509 				moviestop = 1;
20510 				break;
20511 			}
20512 		}
20513 		if(!moviestop)
20514 		{
20515 			movie_update(playercontrolpointers);
20516 			font_printf(2, 2, 1, 0, "Playing movie, frames: %d/%d", movieloglen + moviebufptr-MOVIEBUF_LEN, movielen);
20517 		}
20518 		else
20519 		{
20520 			movie_closefile();
20521 		}
20522 	}
20523 	else
20524 	{
20525 #endif
20526 		 control_update(playercontrolpointers, MAX_PLAYERS);
20527 		 interval = timer_getinterval(GAME_SPEED); // so interval can be logged into movie
20528 		 if(interval > GAME_SPEED) interval = GAME_SPEED/GAME_SPEED;
20529 		 if(interval > GAME_SPEED/4) interval = GAME_SPEED/4;
20530 
20531 #ifndef DISABLE_MOVIE
20532 	}
20533 
20534 	if(movielog && !pause)
20535 	{
20536 		movie_save(playercontrolpointers);
20537 		font_printf(2, 2, 1, 0, "Recording movie, frames: %d", movieloglen + moviebufptr);
20538 	}
20539 #endif
20540 	bothkeys = 0;
20541 	bothnewkeys = 0;
20542 
20543 	for(p=0; p<MAX_PLAYERS; p++)
20544 	{
20545 		pl = player + p;
20546 		pl->releasekeys = (playercontrolpointers[p]->keyflags|pl->keys) - playercontrolpointers[p]->keyflags;
20547 		pl->keys = playercontrolpointers[p]->keyflags;
20548 		pl->newkeys = playercontrolpointers[p]->newkeyflags;
20549 		pl->playkeys |= pl->newkeys;
20550 		pl->playkeys &= pl->keys;
20551 
20552 		if(pl->ent && pl->ent->movetime<time){
20553 			memset(pl->combokey, 0, sizeof(u32)*MAX_SPECIAL_INPUTS);
20554 			memset(pl->inputtime, 0, sizeof(u32)*MAX_SPECIAL_INPUTS);
20555 			pl->combostep = 0;
20556 		}
20557 		if(pl->newkeys){
20558 			k = pl->newkeys;
20559 			if(pl->ent) {
20560 				pl->ent->movetime = time + GAME_SPEED/4;
20561 				if(k&FLAG_MOVELEFT)
20562 					k |= pl->ent->direction?FLAG_BACKWARD:FLAG_FORWARD;
20563 				else if(k&FLAG_MOVERIGHT)
20564 					k |= pl->ent->direction?FLAG_FORWARD:FLAG_BACKWARD;
20565 			}
20566 			pl->inputtime[pl->combostep] = time;
20567 			pl->combokey[pl->combostep] = k;
20568 			pl->combostep++;
20569 			pl->combostep %= MAX_SPECIAL_INPUTS;
20570 		}
20571 
20572 		bothkeys |= player[p].keys;
20573 		bothnewkeys |= player[p].newkeys;
20574 #ifndef DISABLE_MOVIE
20575 		if(movielog && (bothnewkeys & FLAG_ESC) && !pause)
20576 		{
20577 			movie_flushbuf();
20578 			movie_closefile();
20579 		}
20580 #endif
20581 	}
20582 
20583 }
20584 
execute_keyscripts()20585 void execute_keyscripts()
20586 {
20587 	int p;
20588 	for(p=0; p<levelsets[current_set].maxplayers; p++)
20589 	{
20590 		if(!pause && (level||selectScreen) && (player[p].newkeys || (keyscriptrate && player[p].keys) || player[p].releasekeys)){
20591 			if(level){
20592 				execute_level_key_script(p);
20593 				execute_entity_key_script(player[p].ent);
20594 			}
20595 			execute_key_script(p);
20596 			execute_key_script_all(p);
20597 		}
20598 	}
20599 }
20600 
execute_updatescripts()20601 void execute_updatescripts()
20602 {
20603 	if(Script_IsInitialized(&update_script))
20604 	{
20605 		Script_Execute(&(update_script));
20606 	}
20607 	if(level && Script_IsInitialized(&(level->update_script)))
20608 	{
20609 		Script_Execute(&(level->update_script));
20610 	}
20611 }
20612 
execute_updatedscripts()20613 void execute_updatedscripts()
20614 {
20615 	if(Script_IsInitialized(&updated_script))
20616 	{
20617 		Script_Execute(&(updated_script));
20618 	}
20619 	if(level && Script_IsInitialized(&(level->updated_script)))
20620 	{
20621 		Script_Execute(&(level->updated_script));
20622 	}
20623 }
20624 
draw_textobjs()20625 void draw_textobjs()
20626 {
20627 	int i;
20628 	s_textobj* textobj;
20629 	if(!level) return;
20630 	for(i = 0;i < LEVEL_MAX_TEXTOBJS;i++)
20631 	{
20632 		 textobj = level->textobjs + i;
20633 
20634 		if(textobj->t && textobj->t <= time)		//If a time was set and passed, remove the text object.
20635 		{
20636 			level->textobjs[i].t	= 0;
20637 			level->textobjs[i].x	= 0;
20638 			level->textobjs[i].y	= 0;
20639 			level->textobjs[i].font = 0;
20640 			level->textobjs[i].z	= 0;
20641 			if(level->textobjs[i].text)
20642 			{
20643 				free(level->textobjs[i].text);
20644 				level->textobjs[i].text = NULL;
20645 			}
20646 		}
20647 		else
20648 		{
20649 			if(textobj->text)
20650 			  font_printf(textobj->x, textobj->y, textobj->font, textobj->z, textobj->text);
20651 		}
20652 	}
20653 }
20654 
20655 
update(int ingame,int usevwait)20656 void update(int ingame, int usevwait)
20657 {
20658 	newtime = 0;
20659 	inputrefresh();
20660 
20661 	if ((!pause && ingame == 1) || alwaysupdate) execute_updatescripts();
20662 
20663 	if(!pause)
20664 	{
20665 		if(ingame == 1 || selectScreen) execute_keyscripts();
20666 
20667 		if((level_completed && !level->noslow && !tospeedup) || slowmotion[0])
20668 		{
20669 			if(slowmotion[1] == slowmotion[2]) newtime = time + interval;
20670 		}
20671 		else newtime = time + interval;
20672 
20673 		slowmotion[2]++;
20674 		if(slowmotion[2] == (slowmotion[1] + 1))
20675 		{
20676 			slowmotion[2] = 0;
20677 			if(slowmotion[0] > 1) slowmotion[1] = slowmotion[0];
20678 		}
20679 		if(newtime > time + 100) newtime = time + 100;
20680 
20681 		while(time < newtime)
20682 		{
20683 			if(ingame == 1)
20684 			{
20685 				update_scroller();
20686 				if(!freezeall)
20687 				{
20688 					if(level->settime > 0 || (level->type!=2 && !player[0].ent && !player[1].ent && !player[2].ent && !player[3].ent))
20689 					{
20690 						if(timeleft>0) --timeleft;
20691 						else if((level->settime > 0 && !player[0].joining && !player[1].joining && !player[2].joining && !player[3].joining) ||
20692 								(((!noshare && credits < 1) || (noshare && player[0].credits < 1 && player[1].credits < 1 && player[2].credits <1 && player[3].credits <1))
20693 								 && !player[0].joining && !player[1].joining && !player[2].joining && !player[3].joining )
20694 								)
20695 						{
20696 							time_over();
20697 						}
20698 					}
20699 				}
20700 			}
20701 			if(ingame==1 || selectScreen) update_ents();
20702 			++time;
20703 		}
20704 
20705 	}
20706 
20707 	/************ gfx queueing ************/
20708 
20709 	clearscreen(vscreen);
20710 
20711 	if(ingame == 1 && !pause)
20712 	{
20713 		update_scrolled_bg();
20714 		if(level->type!=2) updatestatus();
20715 
20716 		draw_scrolled_bg();
20717 		if(level->type!=2) predrawstatus();
20718 		if(level->type!=2) drawstatus();
20719 		draw_textobjs();
20720 	}
20721 
20722 	if(!ingame)
20723 	{
20724 		if(background) spriteq_add_screen(0,0,MIN_INT,background,NULL,0);
20725 	}
20726 
20727 	// entity sprites queueing
20728 	if(ingame==1 || selectScreen)
20729 		if(!pause) display_ents();
20730 
20731 	/************ updated script  ************/
20732 	if(ingame == 1 || alwaysupdate)
20733 	{
20734 		execute_updatedscripts();
20735 	}
20736 
20737 	// 2011/10/22 UT: move pause menu logic here
20738 	if(ingame==1 &&
20739 #ifndef DISABLE_MOVIE
20740 		!movieplay &&
20741 #endif
20742 		!pause && !nopause &&
20743 	   ((player[0].ent && (player[0].newkeys & FLAG_START)) ||
20744 		(player[1].ent && (player[1].newkeys & FLAG_START)) ||
20745 		(player[2].ent && (player[2].newkeys & FLAG_START)) ||
20746 		(player[3].ent && (player[3].newkeys & FLAG_START)))
20747 	)
20748 	{
20749 		sound_pause_music(1);
20750 		sound_pause_sample(1);
20751 		sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
20752 		pausemenu();
20753 		return;
20754 	}
20755 
20756 	/********** update screen **************/
20757 
20758 	spriteq_draw(vscreen, 0, MIN_INT, MAX_INT, 0, 0); // notice, always draw sprites at the very end of other methods
20759 
20760 	if(pause!=2 && !noscreenshot && (bothnewkeys&FLAG_SCREENSHOT)) screenshot(vscreen, getpal, 1);
20761 
20762 	// Debug stuff, should not appear on screenshot
20763 	if(debug_time==0xFFFFFFFF) debug_time = time + GAME_SPEED * 5;
20764 	if(time<debug_time && debug_msg[0])
20765 	{
20766 		screen_printf(vscreen, 0 , 230, 0, debug_msg);
20767 	}
20768 	else
20769 	{
20770 		debug_msg[0] = 0;
20771 #ifdef DEBUG_MODE
20772 		if(level->pos) debug_printf("Position: %i, width: %i, spawn: %i, offsets: %i/%i", level->pos, level->width, current_spawn, level->quake, gfx_y_offset);
20773 #endif
20774 	}
20775 
20776 	if(usevwait) vga_vwait();
20777 	video_copy_screen(vscreen);
20778 
20779 	spriteq_clear();
20780 
20781 	check_music();
20782 	sound_update_music();
20783 }
20784 
20785 
20786 
20787 
20788 // ----------------------------------------------------------------------
20789 /* Plombo 9/4/2010: New function that can use brightness/gamma correction
20790  * independent from the global palette on platforms where it's available.
20791  * Hardware accelerated brightness/gamma correction is available on Wii and
20792  * OpenGL platforms using TEV and GLSL, respectively. Returns 1 on success, 0 on
20793  * error. */
set_color_correction(int gm,int br)20794 int set_color_correction(int gm, int br)
20795 {
20796 #if WII
20797 	vga_set_color_correction(gm, br);
20798 	return 1;
20799 #elif SDL
20800 	if(opengl)
20801 	{
20802 		vga_set_color_correction(gm, br);
20803 		return 1;
20804 	}
20805 	else if(screenformat == PIXEL_8)
20806 	{
20807 		palette_set_corrected(pal, savedata.gamma,savedata.gamma,savedata.gamma, savedata.brightness,savedata.brightness,savedata.brightness);
20808 		return 1;
20809 	}
20810 	else return 0;
20811 #else
20812 	if(screenformat == PIXEL_8)
20813 	{
20814 		palette_set_corrected(pal, savedata.gamma,savedata.gamma,savedata.gamma, savedata.brightness,savedata.brightness,savedata.brightness);
20815 		return 1;
20816 	}
20817 	else return 0;
20818 #endif
20819 }
20820 
20821 // copied from palette.c, seems it works well
_fade_screen(s_screen * screen,int gr,int gg,int gb,int br,int bg,int bb)20822 static void _fade_screen(s_screen* screen, int gr, int gg, int gb, int br, int bg, int bb)
20823 {
20824 	int i, len = screen->width*screen->height;
20825 	int pb = pixelbytes[(int)screenformat];
20826 	unsigned c, r, g, b;
20827 
20828 
20829 	if(gr<-255) gr = -255;
20830 	else if(gr>255) gr = 255;
20831 	if(gg<-255) gg = -255;
20832 	else if(gg>255) gg = 255;
20833 	if(gb<-255) gb = -255;
20834 	else if(gb>255) gb = 255;
20835 
20836 	if(br<-255) br = -255;
20837 	else if(br>255) br = 255;
20838 	if(bg<-255) bg = -255;
20839 	else if(bg>255) bg = 255;
20840 	if(bb<-255) bb = -255;
20841 	else if(bb>255) bb = 255;
20842 
20843 	if(pb==2) for(i=0; i<len; i++)
20844 	{
20845 		c = ((unsigned short*)screen->data)[i];
20846 		b = (c>>11)*0xFF/0x1F;
20847 		g = ((c&0x7E0)>>5)*0xFF/0x3F;
20848 		r = (c&0x1F)*0xFF/0x1F;
20849 		((unsigned short*)screen->data)[i] = colour16(gbcorrect(r, gr, br), gbcorrect(g, gg, bg), gbcorrect(b, gb, bb));
20850 	}
20851 	else for(i=0; i<len; i++){
20852 		screen->data[i*pb] =   gbcorrect(screen->data[i*pb],   gr, br);
20853 		screen->data[i*pb+1] = gbcorrect(screen->data[i*pb+1], gg, bg);
20854 		screen->data[i*pb+2] = gbcorrect(screen->data[i*pb+2], gb, bb);
20855 	}
20856 }
20857 
20858 // Simple palette fade / vscreen fade
fade_out(int type,int speed)20859 void fade_out(int type, int speed)
20860 {
20861 	int i, j = 0;
20862 	int b, g = 0;
20863 	u32 interval = 0;
20864 	int current = speed ? speed : fade;
20865 
20866 	for(i=0, j=0; j<64; )
20867 	{
20868 		while(j<=i)
20869 		{
20870 			if(!type || type == 1)
20871 			{
20872 				b = ((savedata.brightness+256) * (64-j) / 64) - 256;
20873 				g = 256 - ((savedata.gamma+256) * (64-j) / 64);
20874 				vga_vwait();
20875 				if(!set_color_correction(g, b))
20876 					_fade_screen(vscreen, g,savedata.gamma,savedata.gamma, b,b,b);
20877 			}
20878 			j++;
20879 			if(!type || type == 1)
20880 			{
20881 				video_copy_screen(vscreen);
20882 			}
20883 		}
20884 		if(!type || type == 2)
20885 		{
20886 			sound_update_music();
20887 	        if(!musicoverlap) sound_volume_music(savedata.musicvol*(64-j)/64, savedata.musicvol*(64-j)/64);
20888 		}
20889 		interval = timer_getinterval(current);
20890 		if(interval > current) interval = current/60;
20891 		if(interval > current/4) interval = current/4;
20892 		i += interval;
20893 	}
20894 
20895 	if(!type || type == 2)
20896 	{
20897 		if(!musicoverlap) sound_close_music();
20898 	}
20899 
20900 	if(!type || type == 1)
20901 	{
20902 		clearscreen(vscreen);
20903 		video_copy_screen(vscreen);
20904 	    vga_vwait();
20905 		//the black screen, so we return to normal palette
20906 		set_color_correction(savedata.gamma, savedata.brightness);
20907 	}
20908 }
20909 
20910 
20911 
apply_controls()20912 void apply_controls(){
20913 	int p;
20914 
20915 	for(p=0; p<4; p++){
20916 		control_setkey(playercontrolpointers[p], FLAG_ESC,        CONTROL_ESC);
20917 		control_setkey(playercontrolpointers[p], FLAG_MOVEUP,     savedata.keys[p][SDID_MOVEUP]);
20918 		control_setkey(playercontrolpointers[p], FLAG_MOVEDOWN,   savedata.keys[p][SDID_MOVEDOWN]);
20919 		control_setkey(playercontrolpointers[p], FLAG_MOVELEFT,   savedata.keys[p][SDID_MOVELEFT]);
20920 		control_setkey(playercontrolpointers[p], FLAG_MOVERIGHT,  savedata.keys[p][SDID_MOVERIGHT]);
20921 		control_setkey(playercontrolpointers[p], FLAG_ATTACK,     savedata.keys[p][SDID_ATTACK]);
20922 		control_setkey(playercontrolpointers[p], FLAG_ATTACK2,    savedata.keys[p][SDID_ATTACK2]);
20923 		control_setkey(playercontrolpointers[p], FLAG_ATTACK3,    savedata.keys[p][SDID_ATTACK3]);
20924 		control_setkey(playercontrolpointers[p], FLAG_ATTACK4,    savedata.keys[p][SDID_ATTACK4]);
20925 		control_setkey(playercontrolpointers[p], FLAG_JUMP,       savedata.keys[p][SDID_JUMP]);
20926 		control_setkey(playercontrolpointers[p], FLAG_SPECIAL,    savedata.keys[p][SDID_SPECIAL]);
20927 		control_setkey(playercontrolpointers[p], FLAG_START,      savedata.keys[p][SDID_START]);
20928 		control_setkey(playercontrolpointers[p], FLAG_SCREENSHOT, savedata.keys[p][SDID_SCREENSHOT]);
20929 	}
20930 }
20931 
20932 
20933 
20934 // ----------------------------------------------------------------------
20935 
display_credits()20936 void display_credits()
20937 {
20938 	u32 finishtime = time + 10 * GAME_SPEED;
20939 	int done = 0;
20940 	int s = videomodes.vShift/2 + 3;
20941 	int v = (videomodes.vRes-videomodes.vShift)/23;
20942 	int h = videomodes.hRes/2;
20943 	int col1 = h - fontmonowidth(0)*16;
20944 	int col2 = h + fontmonowidth(0)*4;
20945 
20946 	if(savedata.logo != 1) return;
20947 	fade_out(0, 0);
20948 	unload_background();
20949 
20950 	bothnewkeys = 0;
20951 
20952 	while(!done)
20953 	{
20954 		font_printf(_strmidx(2, "Credits"), s,   2, 0, "Credits");
20955 		font_printf(_strmidx(1, "Beats Of Rage"), s+v*2,  1, 0, "Beats Of Rage");
20956 		font_printf(_strmidx(0, "Senile Team"), s+v*3,  0, 0, "Senile Team");
20957 
20958 		font_printf(_strmidx(1, "OpenBOR"), s+v*5,  1, 0, "OpenBOR");
20959 		font_printf(_strmidx(0, "SX"), s+v*6,  0, 0, "SX");
20960 		font_printf(col1,  s+v*7,  0, 0, "CGRemakes");
20961 		font_printf(col2, s+v*7,  0, 0, "Fugue");
20962 		font_printf(col1,  s+v*8,  0, 0, "uTunnels");
20963 		font_printf(col2, s+v*8,  0, 0, "Kirby");
20964 		font_printf(col1,  s+v*9,  0, 0, "LordBall");
20965 		font_printf(col2, s+v*9,  0, 0, "Tails");
20966 		font_printf(col1,  s+v*10, 0, 0, "KBAndressen");
20967 		font_printf(col2, s+v*10, 0, 0, "Damon Caskey");
20968 		font_printf(col1,  s+v*11, 0, 0, "Plombo");
20969 		font_printf(col2, s+v*11, 0, 0, "Orochi_X");
20970 
20971 		font_printf(_strmidx(1, "Consoles"), s+v*12,  1, 0, "Consoles");
20972 		font_printf(col1,  s+v*13, 0, 0, "PSP/PS3/Linux/OSX");
20973 		font_printf(col2, s+v*13, 0, 0, "SX");
20974 		font_printf(col1,  s+v*14, 0, 0, "Dingoo");
20975 		font_printf(col2, s+v*14, 0, 0, "Shin-NiL");
20976 		font_printf(col1,  s+v*15, 0, 0, "Windows");
20977 		font_printf(col2, s+v*15, 0, 0, "SX & Nazo");
20978 		font_printf(col1,  s+v*16, 0, 0, "GamePark");
20979 		font_printf(col2, s+v*16, 0, 0, "SX & Lemon");
20980 		font_printf(col1,  s+v*17, 0, 0, "DreamCast");
20981 		font_printf(col2, s+v*17, 0, 0, "SX & Neill Corlett");
20982 		font_printf(col1,  s+v*18, 0, 0, "MS XBoX");
20983 		font_printf(col2, s+v*18, 0, 0, "SX & XPort");
20984 		font_printf(col1,  s+v*19, 0, 0, "Wii");
20985 		font_printf(col2, s+v*19, 0, 0, "SX & Plombo");
20986 
20987 		font_printf(_strmidx(1, "Menu Design"), s+v*21,  1, 0, "Menu Design");
20988 		font_printf(col1, s+v*22,  0, 0, "SX");
20989 		font_printf(col2, s+v*22, 0, 0, "Fightn Words");
20990 
20991 		update(2,0);
20992 
20993 		done |= (time > finishtime);
20994 		done |= (bothnewkeys & (FLAG_START+FLAG_ESC));
20995 	}
20996 	fade = 75;
20997 	fade_out(0, 0);
20998 }
20999 
21000 
shutdown(int status,char * msg,...)21001 void shutdown(int status, char *msg, ...)
21002 {
21003 	char buf[1024] = "";
21004 	va_list arglist;
21005 	int i;
21006 
21007 	static int shuttingdown = 0;
21008 
21009 	if(shuttingdown) return;
21010 
21011 	shuttingdown = 1;
21012 
21013 	//printf("savedata.logo %d\n", savedata.logo);
21014 
21015 	va_start(arglist, msg);
21016 	vsprintf(buf, msg, arglist);
21017 	va_end(arglist);
21018 
21019 	if(!disablelog)
21020 	{
21021 		switch(status)
21022 		{
21023 		case 0:
21024 			printf("\n************ Shutting Down ************\n\n");
21025 			break;
21026 		default:
21027 			printf("\n********** An Error Occurred **********"
21028 				"\n*            Shutting Down            *\n\n");
21029 			break;
21030 		}
21031 	}
21032 
21033 	if(!disablelog) printf("%s", buf);
21034 
21035 
21036 	getRamStatus(BYTES);
21037 	savesettings();
21038 
21039 	if(status != 2) display_credits();
21040 	if(startup_done) term_videomodes();
21041 
21042 	if(!disablelog) printf("Release level data");
21043 	if (startup_done) unload_levelorder();
21044 	if(!disablelog) printf("...........");
21045 	if(startup_done) unload_level();
21046 	if(!disablelog) printf("\tDone!\n");
21047 
21048 	if(!disablelog) printf("Release graphics data");
21049 	if(!disablelog) printf("..");
21050 	if(startup_done) freescreen(&vscreen); // allocated by init_videomodes
21051 	if(startup_done && pixelformat==PIXEL_x8) for(i=0; i<MAX_BLENDINGS; i++) free(blendtables[i]);
21052 	if(!disablelog) printf("..");
21053 	if(startup_done) freescreen(&background);
21054 	if(!disablelog) printf("..");
21055 #if WII
21056 	if(startup_done) for(i=0; i<MAX_CACHED_BACKGROUNDS; i++) freescreen(&bg_cache[i]);
21057 	if(!disablelog) printf("..");
21058 #endif
21059 	if(startup_done) freesprites();
21060 	if(!disablelog) printf("..");
21061 	if(startup_done) unload_all_fonts();
21062 	if(!disablelog) printf("\tDone!\n");
21063 
21064 
21065 	if(!disablelog) printf("Release game data............\n\n");
21066 
21067 	if(startup_done) free_ents();
21068 	if(startup_done) free_models();
21069 	if(startup_done) free_modelcache();
21070 	if(startup_done) clear_scripts();
21071 	if(!disablelog) printf("\nRelease game data............\tDone!\n");
21072 
21073 	if(!disablelog) printf("Release timer................");
21074 	if(startup_done) borTimerExit();
21075 	if(!disablelog) printf("\tDone!\n");
21076 
21077 	if(!disablelog) printf("Release input hardware.......");
21078 	if(startup_done) control_exit();
21079 	if(!disablelog) printf("\tDone!\n");
21080 
21081 	if(!disablelog) printf("Release sound system.........");
21082 	if(startup_done) sound_exit();
21083 	if(!disablelog) printf("\tDone!\n");
21084 
21085 	if(!disablelog) printf("Release FileCaching System...");
21086 	if(startup_done) pak_term();
21087 	if(!disablelog) printf("\tDone!\n");
21088 
21089 	if(modelcmdlist)
21090 		freeCommandList(modelcmdlist); // moved here because list is not initialized if shutdown is initiated from inside the menu
21091 	if(modelstxtcmdlist)
21092 		freeCommandList(modelstxtcmdlist);
21093 	if(levelcmdlist)
21094 		freeCommandList(levelcmdlist);
21095 	if(levelordercmdlist)
21096 		freeCommandList(levelordercmdlist);
21097 
21098 	freeModelList();
21099 
21100 	freefilenamecache();
21101 
21102 
21103 	if(!disablelog) printf("\n**************** Done *****************\n\n");
21104 
21105 	if(!disablelog) printf("%s", buf);
21106 	#ifdef DEBUG
21107 	assert(status == 0); // this way we can haz backtrace.
21108 	#endif
21109 
21110 	shuttingdown = 0;
21111 	exit(status);
21112 }
21113 
21114 
21115 #if XBOX || DC
guistartup()21116 void guistartup(){
21117 	int i;
21118 
21119 	if(!font_load(0, "menu/font1", packfile, 0)) shutdown(1, "Unable to load font #1!\n");
21120 	if(!font_load(1, "menu/font2", packfile, 0)) shutdown(1, "Unable to load font #2!\n");
21121 	if(!font_load(2, "menu/font3", packfile, 0)) shutdown(1, "Unable to load font #3!\n");
21122 
21123 
21124 	borTimerInit();
21125 
21126 	control_init(2);
21127 	apply_controls();
21128 
21129 	init_videomodes(0);
21130 	if(!video_set_mode(videomodes)) shutdown(1, "Unable to set video mode: %d x %d!\n", videomodes.hRes, videomodes.vRes);
21131 
21132 	for(i=0; i<256; i++) neontable[i] = i;
21133 }
21134 #endif
21135 
startup()21136 void startup(){
21137 	int i;
21138 
21139 	printf("FileCaching System Init......\t");
21140 	if(pak_init()) printf("Enabled\n");
21141 	else           printf("Disabled\n");
21142 
21143 #if PSP
21144 	if(savedata.pspcpuspeed<0) savedata.pspcpuspeed = 2;
21145 	if(savedata.pspcpuspeed>2) savedata.pspcpuspeed = 0;
21146 	switch(savedata.pspcpuspeed){
21147 		case 0:
21148 			scePowerSetClockFrequency(222, 222, 111);
21149 			break;
21150 		case 1:
21151 			scePowerSetClockFrequency(266, 266, 133);
21152 			break;
21153 		case 2:
21154 			scePowerSetClockFrequency(333, 333, 166);
21155 			break;
21156 	}
21157 #endif
21158 
21159 	loadHighScoreFile();
21160 	clearSavedGame();
21161 
21162 	init_videomodes(1);
21163 	if(!video_set_mode(videomodes)) shutdown(1, "Unable to set video mode: %d x %d!\n", videomodes.hRes, videomodes.vRes);
21164 
21165 	printf("Loading menu.txt.............\t");
21166 	load_menu_txt();
21167 	printf("Done!\n");
21168 
21169 	printf("Loading fonts................\t");
21170 	load_all_fonts();
21171 	printf("Done!\n");
21172 
21173 	printf("Timer init...................\t");
21174 	borTimerInit();
21175 	printf("Done!\n");
21176 
21177 	printf("Initialize Sound..............\t");
21178 	if(savedata.usesound && sound_init(12)){
21179 		if(load_special_sounds()) printf("Done!\n");
21180 		else printf("\n");
21181 		if(!sound_start_playback(savedata.soundbits,savedata.soundrate)) printf("Warning: can't play sound at %u Hz!\n", savedata.soundrate);
21182 		SB_setvolume(SB_MASTERVOL, 15);
21183 		SB_setvolume(SB_VOICEVOL, savedata.soundvol);
21184 	}
21185 	else shutdown(1, "Unable to Initialize Sound.\n");
21186 
21187 	printf("Loading sprites..............\t");
21188 	load_special_sprites();
21189 	printf("Done!\n");
21190 
21191 	printf("Loading level order..........\t");
21192 	load_levelorder();
21193 	printf("Done!\n");
21194 
21195 	printf("Loading script settings......\t");
21196 	load_script_setting();
21197 	printf("Done!\n");
21198 
21199 	printf("Loading scripts..............\t");
21200 	load_scripts();
21201 	printf("Done!\n");
21202 
21203 	printf("Loading models...............\n\n");
21204 	load_models();
21205 
21206 	printf("Object engine init...........\t");
21207 	if(!alloc_ents()) shutdown(1, "Not enough memory for game objects!\n");
21208 	printf("Done!\n");
21209 
21210 	printf("Input init...................\t");
21211 	control_init(savedata.usejoy);
21212 	apply_controls();
21213 	printf("Done!\n");
21214 
21215 #if WII
21216 	printf("Caching backgrounds..........\t");
21217 	cache_all_backgrounds();
21218 	printf("Done!\n");
21219 #endif
21220 
21221 	printf("\n\n");
21222 
21223 	if(pixelformat==PIXEL_x8)
21224 		create_blend_tables_x8(blendtables);
21225 
21226 	for(i=0; i<MAX_PAL_SIZE/4; i++) neontable[i] = i;
21227 	if(savedata.logo++ > 10) savedata.logo = 0;
21228 	savesettings();
21229 	startup_done = 1;
21230 
21231 }
21232 
21233 
update_backbuffer(s_screen * backbuffer,s_screen ** gifbuffer)21234 static void update_backbuffer(s_screen* backbuffer, s_screen** gifbuffer){
21235 	int i, l = backbuffer->width*backbuffer->height;
21236 	unsigned short *ps16, *ppr16, *ppg16, *ppb16;
21237 	unsigned int *ps32, *ppr32, *ppg32, *ppb32;
21238 	switch(screenformat){
21239 	case PIXEL_16:
21240 		ps16 = (unsigned short*)(backbuffer->data);
21241 		ppr16 = (unsigned short*)(gifbuffer[0]->data);
21242 		ppg16 = (unsigned short*)(gifbuffer[1]->data);
21243 		ppb16 = (unsigned short*)(gifbuffer[2]->data);
21244 		for(i=0; i<l; i++){
21245 			ps16[i] =  ppr16[i]|ppg16[i]|ppb16[i];
21246 		}
21247 		break;
21248 	case PIXEL_32:
21249 		ps32 = (unsigned int*)(backbuffer->data);
21250 		ppr32 = (unsigned int*)(gifbuffer[0]->data);
21251 		ppg32 = (unsigned int*)(gifbuffer[1]->data);
21252 		ppb32 = (unsigned int*)(gifbuffer[2]->data);
21253 		for(i=0; i<l; i++){
21254 			ps32[i] = ppr32[i]|ppg32[i]|ppb32[i];
21255 			//printf(" %u %u %u\n", ppr32[i], ppg32[i], ppb32[i]);
21256 		}
21257 		break;
21258 	}
21259 
21260 }
21261 
21262 
21263 
21264 
21265 // ----------------------------------------------------------------------------
21266 
21267 // Returns 0 on error, -1 on escape
playgif(char * filename,int x,int y,int noskip)21268 int playgif(char *filename, int x, int y, int noskip){
21269 	unsigned char gifpal[3][1024] ;
21270 	char tname[256] = {""};
21271 	int code[3];
21272 	int delay[3];
21273 	u32 milliseconds;
21274 	u32 nextframe[3];
21275 	u32 lasttime;
21276 	u32 temptime, tempnewtime; // temporary patch for ingame gif play
21277 	int done;
21278 	int frame = 0;
21279 	int synctosound = 0;
21280 	s_screen* backbuffer = NULL, *gifbuffer[3] = {NULL, NULL, NULL}, *tempbg = background;
21281 	static anigif_info info[3];
21282 	int isRGB = (pixelformat==PIXEL_x8);
21283 
21284 	strcpy(tname, filename);
21285 	if(stricmp(tname + strlen(tname)-4, ".gif")==0) tname[strlen(tname)-4] = 0;
21286 
21287 	strcat(tname, "_.gif");
21288 
21289 	if(isRGB){
21290 		tname[strlen(tname)-5] = 'r';
21291 		if(testpackfile(tname, packfile)<0) isRGB = 0;
21292 		tname[strlen(tname)-5] = 'g';
21293 		if(testpackfile(tname, packfile)<0) isRGB = 0;
21294 		tname[strlen(tname)-5] = 'b';
21295 		if(testpackfile(tname, packfile)<0) isRGB = 0;
21296 	}
21297 
21298 
21299 
21300 	background = gifbuffer[0] = allocscreen(videomodes.hRes, videomodes.vRes, screenformat);
21301 	clearscreen(background);
21302 	info->noblackenbg = (info+1)->noblackenbg = (info+2)->noblackenbg = isRGB;
21303 
21304 	if(isRGB) {
21305 		backbuffer = allocscreen(videomodes.hRes, videomodes.vRes, screenformat);
21306 		gifbuffer[1] = allocscreen(videomodes.hRes, videomodes.vRes, screenformat);
21307 		clearscreen(gifbuffer[1]);
21308 		gifbuffer[2] = allocscreen(videomodes.hRes, videomodes.vRes, screenformat);
21309 		clearscreen(gifbuffer[2]);
21310 		background = NULL;
21311 	}
21312 	standard_palette(1);
21313 
21314 	if(!isRGB){
21315 		if(!anigif_open(filename, packfile, gifpal[0], info))
21316 			goto playgif_error;
21317 	}else{
21318 		tname[strlen(tname)-5] = 'r';
21319 		if(!anigif_open(tname, packfile, gifpal[0], info)) goto playgif_error;
21320 		tname[strlen(tname)-5] = 'g';
21321 		if(!anigif_open(tname, packfile, gifpal[1], info+1)) goto playgif_error;
21322 		tname[strlen(tname)-5] = 'b';
21323 		if(!anigif_open(tname, packfile, gifpal[2], info+2)) goto playgif_error;
21324 	}
21325 
21326 	temptime = time;
21327 	tempnewtime = newtime;
21328 	time = 0;
21329 	lasttime = 0;
21330 	milliseconds = 0;
21331 	nextframe[0] = nextframe[1] = nextframe[2] = 0;
21332 	delay[0] = delay[1] = delay[2] = 100;
21333 	code[0] = code[1] = code[2] = ANIGIF_DECODE_RETRY;
21334 	done = 0;
21335 	synctosound = (sound_getinterval() != 0xFFFFFFFF);
21336 
21337 	while(!done){
21338 		//printf("gif\n");
21339 		if(milliseconds >= nextframe[0]){
21340 			if(code[0] != ANIGIF_DECODE_END){
21341 				while((code[0] = anigif_decode(gifbuffer[0], delay, x, y, gifpal[0], info)) == ANIGIF_DECODE_RETRY);
21342 				// if(code == ANIGIF_DECODE_FRAME){
21343 				// Set time for next frame
21344 				nextframe[0] += delay[0] * 10;
21345 			// }
21346 			}
21347 			else done |= 1;
21348 		}
21349 		if(code[0] == ANIGIF_DECODE_END) break;
21350 
21351 		if(isRGB){
21352 			//g
21353 			if(milliseconds >= nextframe[1]){
21354 				if(code[1] != ANIGIF_DECODE_END){
21355 					while((code[1] = anigif_decode(gifbuffer[1], delay+1, x, y, gifpal[1], info+1)) == ANIGIF_DECODE_RETRY);
21356 					nextframe[1] += delay[1] * 10;
21357 				}
21358 				else done |= 1;
21359 			}
21360 			//b
21361 			if(milliseconds >= nextframe[2]){
21362 				if(code[2] != ANIGIF_DECODE_END){
21363 					while((code[2] = anigif_decode(gifbuffer[2], delay+2, x, y, gifpal[2], info+2)) == ANIGIF_DECODE_RETRY);
21364 					nextframe[2] += delay[2] * 10;
21365 				}
21366 				else done |= 1;
21367 			}
21368 			if(backbuffer) update_backbuffer(backbuffer, gifbuffer);
21369 		}
21370 
21371 		if(backbuffer){
21372 			spriteq_add_screen(0,0,0,backbuffer,NULL,0);
21373 		}
21374 
21375 		if(frame==0){
21376 			vga_vwait();
21377 			if(background)
21378 				palette_set_corrected(gifpal[0], savedata.gamma,savedata.gamma,savedata.gamma, savedata.brightness,savedata.brightness,savedata.brightness);
21379 			update(0,0);
21380 		}
21381 		else update(0,1);
21382 
21383 		++frame;
21384 
21385 		if(synctosound){
21386 			milliseconds += sound_getinterval();
21387 			if(milliseconds==0xFFFFFFFF) synctosound = 0;
21388 		}
21389 		if(!synctosound) milliseconds += (time-lasttime) * 1000 / GAME_SPEED;
21390 		lasttime = time;
21391 
21392 		if(!noskip && (bothnewkeys & (FLAG_ESC | FLAG_ANYBUTTON))) done = 1;
21393 	}
21394 	anigif_close(info);
21395 	if(isRGB){
21396 		anigif_close(info+1);
21397 		anigif_close(info+2);
21398 	}
21399 
21400 	time = temptime;
21401 	newtime = tempnewtime;
21402 
21403 	if(backbuffer) freescreen(&backbuffer);
21404 	if(gifbuffer[0]) freescreen(&(gifbuffer[0]));
21405 	if(gifbuffer[1]) freescreen(&(gifbuffer[1]));
21406 	if(gifbuffer[2]) freescreen(&(gifbuffer[2]));
21407 	background = tempbg;
21408 	standard_palette(1);
21409 	if(bothnewkeys & (FLAG_ESC | FLAG_ANYBUTTON)) return -1;
21410 	return 1;
21411 
21412 playgif_error:
21413 	if(info->handle>=0) anigif_close(info);
21414 	if((info+1)->handle>=0) anigif_close(info+1);
21415 	if((info+2)->handle>=0) anigif_close(info+2);
21416 	if(backbuffer) freescreen(&backbuffer);
21417 	if(gifbuffer[0]) freescreen(&(gifbuffer[0]));
21418 	if(gifbuffer[1]) freescreen(&(gifbuffer[1]));
21419 	if(gifbuffer[2]) freescreen(&(gifbuffer[2]));
21420 	background = tempbg;
21421 	standard_palette(1);
21422 	return 0;
21423 }
21424 
21425 
21426 
21427 
21428 
playscene(char * filename)21429 void playscene(char *filename)
21430 {
21431 	char *buf;
21432 	size_t size;
21433 	int pos;
21434 	char * command = NULL;
21435 	char giffile[256];
21436 	int x=0, y=0, skipone=0, noskip=0, i;
21437 	int closing = 0;
21438 
21439 	ArgList arglist;
21440 	char argbuf[MAX_ARG_LEN+1] = "";
21441 
21442 	// Read file
21443 	if(buffer_pakfile(filename, &buf, &size)!=1) return;
21444 
21445 	currentScene = filename;
21446 
21447 	// Now interpret the contents of buf line by line
21448 	pos = 0;
21449 	while(buf[pos]){
21450 	    ParseArgs(&arglist,buf+pos,argbuf);
21451 		command = GET_ARG(0);
21452 		if(command[0]){
21453 			if(!closing && stricmp(command, "music")==0){
21454 				music(GET_ARG(1), GET_INT_ARG(2), atol(GET_ARG(3)));
21455 			}
21456 			else if(!closing && stricmp(command, "animation")==0){
21457 				strcpy(giffile, GET_ARG(1));
21458 				x = GET_INT_ARG(2);
21459 				y = GET_INT_ARG(3);
21460 				skipone = GET_INT_ARG(4);
21461 				noskip = GET_INT_ARG(5);
21462 				if(playgif(giffile, x, y, noskip) == -1 && !skipone) closing = 1;
21463 			}
21464 			else if(stricmp(command, "silence")==0){
21465 				sound_close_music();
21466 			}
21467 		}
21468 		// Go to next non-blank line
21469 	pos += getNewLineStart(buf + pos);
21470 	}
21471 	if(buf != NULL){
21472 		free(buf);
21473 		buf = NULL;
21474 	}
21475 	currentScene = NULL;
21476 	for(i=0; i<MAX_PLAYERS; i++)
21477 		player[i].newkeys = player[i].playkeys = 0;
21478 }
21479 
21480 
21481 
21482 
21483 // ----------------------------------------------------------------------------
21484 
21485 
21486 
21487 
gameover()21488 void gameover(){
21489 	int done = 0;
21490 	char tmpBuff[128] = {""};
21491 
21492 	music("data/music/gameover", 0, 0);
21493 
21494 	time = 0;
21495 	gameOver = 1;
21496 
21497 	if(custScenes != NULL)
21498 	{
21499 		strcpy(tmpBuff,custScenes);
21500 		strncat(tmpBuff,"gameover.txt", 12);
21501 		if(testpackfile(tmpBuff, packfile) >=0) {
21502 			playscene(tmpBuff);
21503 			done = 1;
21504 		}
21505 	}
21506 	else
21507 	{
21508 		if(testpackfile("data/scenes/gameover.txt", packfile) >=0) {
21509 			playscene("data/scenes/gameover.txt");
21510 			done = 1;
21511 		}
21512 
21513 	}
21514 
21515 	while(!done)
21516 	{
21517 		font_printf(_strmidx(3, "GAME OVER"),110+videomodes.vShift, 3, 0, "GAME OVER");
21518 		done |= (time>GAME_SPEED*8 && !sound_query_music(NULL,NULL));
21519 		done |= (bothnewkeys & (FLAG_ESC|FLAG_ANYBUTTON));
21520 		update(0,0);
21521 	}
21522 	gameOver = 0;
21523 }
21524 
21525 
21526 
21527 
hallfame(int addtoscore)21528 void hallfame(int addtoscore)
21529 {
21530 	int done = 0;
21531 	int topten[10] = { 0,0,0,0,0,0,0,0,0,0 };
21532 	u32 score;
21533 	char name[MAX_NAME_LEN+1];
21534 	int i, p, y;
21535 	char tmpBuff[128] = {""};
21536 	int col1 = -8;
21537 	int col2 = 6;
21538 
21539 	hallOfFame = 1;
21540 
21541 	if(hiscorebg)
21542 	{
21543 		// New alternative background path for PSP
21544 		if(custBkgrds != NULL)
21545 		{
21546 			strcpy(tmpBuff,custBkgrds);
21547 			strncat(tmpBuff,"hiscore", 7);
21548 			load_background(tmpBuff, 0);
21549 		}
21550 		else load_cached_background("data/bgs/hiscore", 0);
21551 	}
21552 
21553 	if(addtoscore)
21554 	{
21555 		for(p = 0; p < levelsets[current_set].maxplayers; p++)
21556 		{
21557 			if(player[p].score > savescore.highsc[9])
21558 			{
21559 				savescore.highsc[9] = player[p].score;
21560 				strcpy(savescore.hscoren[9], player[p].name);
21561 				topten[9] = 1;
21562 
21563 				for(i = 8; i >= 0 && player[p].score > savescore.highsc[i]; i--)
21564 				{
21565 					score = savescore.highsc[i];
21566 					strcpy(name, savescore.hscoren[i]);
21567 					savescore.highsc[i] = player[p].score;
21568 					strcpy(savescore.hscoren[i], player[p].name);
21569 					topten[i] = 1;
21570 					savescore.highsc[i + 1] = score;
21571 					strcpy(savescore.hscoren[i + 1], name);
21572 					topten[i + 1] = 0;
21573 				}
21574 			}
21575 		}
21576 		saveHighScoreFile();
21577 	}
21578 
21579 	time = 0;
21580 
21581 	while(!done)
21582 	{
21583 		y = 56;
21584 		if(!hiscorebg) font_printf(_strmidx(3, "Hall Of Fame"), y-fontheight(3)-10+videomodes.vShift, 3, 0, "Hall Of Fame");
21585 
21586 		for(i = 0; i < 10; i++)
21587 		{
21588 			font_printf(_colx(topten[i], col1), y+videomodes.vShift, topten[i], 0, "%2i.  %s", i+1, savescore.hscoren[i]);
21589 			font_printf(_colx(topten[i], col2), y+videomodes.vShift, topten[i], 0, (scoreformat ? "%09lu" : "%u"), savescore.highsc[i]);
21590 			y += (videomodes.vRes-videomodes.vShift-56-32)/10; //font_heights[topten[i]] + 6;
21591 		}
21592 
21593 		update(0,0);
21594 		done |= (time>GAME_SPEED*8);
21595 		done |= (bothnewkeys & (FLAG_START+FLAG_ESC));
21596 	}
21597 	unload_background();
21598 	hallOfFame = 0;
21599 }
21600 
21601 
21602 
21603 
21604 // Level completed, show bonus stuff
showcomplete(int num)21605 void showcomplete(int num)
21606 {
21607 	int done = 0;
21608 	int i, j, k;
21609 	u32 clearbonus[4] = { 10000, 10000, 10000, 10000 };
21610 	u32 lifebonus[4] = { 10000, 10000, 10000, 10000 };
21611 	u32 rushbonus[4] = { 10000, 10000, 10000, 10000 };
21612 	u32 nexttime = 0;
21613 	u32 finishtime = 0;
21614 	int chan = 0;
21615 	char tmpBuff[128] = {""};
21616 
21617 	showComplete = 1;
21618 
21619 	if(completebg)
21620 	{
21621 		// New alternative background path for PSP
21622 		if(custBkgrds != NULL)
21623 		{
21624 			strcpy(tmpBuff,custBkgrds);
21625 			strncat(tmpBuff,"complete", 8);
21626 			load_background(tmpBuff, 0);
21627 		}
21628 		else load_cached_background("data/bgs/complete", 0);
21629 	}
21630 
21631 	music("data/music/complete", 0, 0);
21632 
21633 	for(i=0; i<levelsets[current_set].maxplayers; i++)
21634 	{
21635 		if(rush[0] >= 1 && showrushbonus == 1)
21636 		{
21637 			rushbonus[i] = nomaxrushreset[i] * scbonuses[2];
21638 		}
21639 		if(scbonuses[3] == 1) clearbonus[i] = num * scbonuses[0];
21640 		else clearbonus[i] = scbonuses[0];
21641 		lifebonus[i] = player[i].lives * scbonuses[1];
21642 	}
21643 
21644 	update(0,0);
21645 
21646 	time = 0;
21647 	while(!done)
21648 	{
21649 		if(!scomplete[5]) font_printf(videomodes.hShift+scomplete[0],videomodes.vShift+scomplete[1], 3, 0, "Stage %i Complete!", num);
21650 		else
21651 		{
21652 			font_printf(videomodes.hShift+scomplete[0],videomodes.vShift+scomplete[1], 3, 0, "Stage");
21653 			font_printf(videomodes.hShift+scomplete[2],videomodes.vShift+scomplete[3], 3, 0, "%i",num);
21654 			font_printf(videomodes.hShift+scomplete[4],videomodes.vShift+scomplete[5], 3, 0, "Complete");
21655 		}
21656 
21657 		font_printf(videomodes.hShift+cbonus[0],videomodes.vShift+cbonus[1], 0, 0, "Clear Bonus");
21658 		for(i=0, j=2, k=3; i < levelsets[current_set].maxplayers; i++, j=j+2, k=k+2) if(player[i].lives > 0) font_printf(videomodes.hShift+cbonus[j],videomodes.vShift+cbonus[k], 0, 0, (scoreformat ? "%09lu" : "%lu"), clearbonus[i]);
21659 		font_printf(videomodes.hShift+lbonus[0],videomodes.vShift+lbonus[1], 0, 0, "Life bonus");
21660 		for(i=0, j=2, k=3; i < levelsets[current_set].maxplayers; i++, j=j+2, k=k+2) if(player[i].lives > 0) font_printf(videomodes.hShift+lbonus[j],videomodes.vShift+lbonus[k], 0, 0, (scoreformat ? "%09lu" : "%lu"), lifebonus[i]);
21661 		if(rush[0] >= 1 && showrushbonus == 1)
21662 		{
21663 			font_printf(videomodes.hShift+rbonus[0],videomodes.vShift+rbonus[1], 0, 0, "Rush Bonus");
21664 			for(i=0, j=2, k=3; i < levelsets[current_set].maxplayers; i++, j=j+2, k=k+2) if(player[i].lives > 0) font_printf(videomodes.hShift+rbonus[j],videomodes.vShift+rbonus[k], 0, 0, (scoreformat ? "%09lu" : "%lu"), rushbonus[i]);
21665 		}
21666 		font_printf(videomodes.hShift+tscore[0],videomodes.vShift+tscore[1], 0, 0, "Total Score");
21667 		for(i=0, j=2, k=3; i < levelsets[current_set].maxplayers; i++, j=j+2, k=k+2) if(player[i].lives > 0) font_printf(videomodes.hShift+tscore[j],videomodes.vShift+tscore[k], 0, 0, (scoreformat ? "%09lu" : "%lu"), player[i].score);
21668 
21669 		while(time > nexttime)
21670 		{
21671 			if(!finishtime)    finishtime = time + 4 * GAME_SPEED;
21672 
21673 			for(i=0; i<levelsets[current_set].maxplayers; i++)
21674 			{
21675 				if(player[i].lives > 0)
21676 				{
21677 					if(clearbonus[i] > 0)
21678 					{
21679 						addscore(i, 10);
21680 						clearbonus[i] -= 10;
21681 						finishtime = 0;
21682 					}
21683 					else if(lifebonus[i] > 0)
21684 					{
21685 						addscore(i, 10);
21686 						lifebonus[i] -= 10;
21687 						finishtime = 0;
21688 					}
21689 					else if(rush[0] >= 1 && showrushbonus == 1 && (rushbonus[i] > 0))
21690 					{
21691 						addscore(i, 10);
21692 						rushbonus[i] -= 10;
21693 						finishtime = 0;
21694 					}
21695 				}
21696 			}
21697 
21698 			if(!finishtime && !(nexttime&15))
21699 			{
21700 				sound_stop_sample(chan);
21701 				chan = sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol/2,savedata.effectvol/2, 100);
21702 			}
21703 			nexttime++;
21704 		}
21705 
21706 		if(bothnewkeys & (FLAG_ANYBUTTON|FLAG_ESC)) done = 1;
21707 		if(finishtime && time>finishtime) done = 1;
21708 
21709 		update(0,0);
21710 	}
21711 
21712 	// Add remainder of score, incase player skips counter
21713 	for(i=0; i<levelsets[current_set].maxplayers; i++)
21714 	{
21715 		if(player[i].lives > 0)
21716 		{
21717 			if(rush[0] >= 1 && showrushbonus == 1)
21718 			{
21719 				addscore(i, rushbonus[i]);
21720 			}
21721 		addscore(i, clearbonus[i]);
21722 		addscore(i, lifebonus[i]);
21723 		}
21724 	}
21725 	unload_background();
21726 
21727 	showComplete = 0;
21728 }
21729 
savelevelinfo()21730 void savelevelinfo()
21731 {
21732 	int i;
21733 	s_set_entry* set = levelsets + current_set;
21734 	s_savelevel* save = savelevel + current_set;
21735 
21736 	save->flag = set->saveflag;
21737 	// don't check flag here save all info, for simple logic
21738 	for(i=0; i<set->maxplayers; i++)
21739 	{
21740 		save->pLives[i] = player[i].lives;
21741 		save->pCredits[i] = player[i].credits;
21742 		save->pScores[i] = player[i].score;
21743 		save->pSpawnhealth[i] = player[i].spawnhealth;
21744 		save->pSpawnmp[i] = player[i].spawnmp;
21745 		save->pWeapnum[i] = player[i].weapnum;
21746 		save->pColourmap[i] = player[i].colourmap;
21747 		strncpy(save->pName[i], player[i].name, MAX_NAME_LEN);
21748 	}
21749 	save->credits = credits;
21750 	save->level = current_level;
21751 	save->stage = current_stage;
21752 	save->which_set = current_set;
21753 	strncpy(save->dName, set->name, MAX_NAME_LEN);
21754 }
21755 
21756 
21757 
playlevel(char * filename)21758 int playlevel(char *filename)
21759 {
21760 	int i, type;
21761 
21762 	kill_all();
21763 
21764 	savelevelinfo(); // just in case we lose them after level is freed
21765 
21766 	load_level(filename);
21767 
21768 	if(!nosave)
21769 	{
21770 		saveGameFile();
21771 		saveHighScoreFile();
21772 		saveScriptFile();
21773 	}
21774 	nosave = 0;
21775 
21776 	time = 0;
21777 	nextplan = 0;
21778 	stalker = NULL;
21779 	firstplayer = NULL;
21780 	type = level->type;
21781 
21782 	// Fixes the start level executing last button bug
21783 	for(i=0; i<levelsets[current_set].maxplayers; i++)
21784 	{
21785 		if(player[i].lives > 0)
21786 		{
21787 			player[i].newkeys = player[i].playkeys = 0;
21788 			player[i].weapnum = level->setweap;
21789 			spawnplayer(i);
21790 			player[i].ent->rush[1] = 0;
21791 		}
21792 	}
21793 
21794 
21795 	//execute a script when level started
21796 	if(Script_IsInitialized(&level_script)) Script_Execute(&level_script);
21797 	if(Script_IsInitialized(&(level->level_script))) Script_Execute(&(level->level_script));
21798 
21799 	while(!endgame)
21800 	{
21801 		update(1,0);
21802 		if(level_completed) endgame |= (!findent(TYPE_ENEMY) || level->type || findent(TYPE_ENDLEVEL));    // Ends when all enemies die or a bonus level
21803 	}
21804 	//execute a script when level finished
21805 	if(Script_IsInitialized(&endlevel_script)) Script_Execute(&endlevel_script);
21806 	if(Script_IsInitialized(&(level->endlevel_script))) Script_Execute(&(level->endlevel_script));
21807 	if(!nofadeout) fade_out(0, 0);
21808 
21809 	for(i=0; i<levelsets[current_set].maxplayers; i++)
21810 	{
21811 		if(player[i].ent)
21812 		{
21813 			nomaxrushreset[i] = player[i].ent->rush[1];
21814 			player[i].spawnhealth = player[i].ent->health;
21815 			player[i].spawnmp = player[i].ent->mp;
21816 		}
21817 	}
21818 
21819 	if(!musicoverlap) sound_close_music();
21820 	sound_stopall_sample();
21821 
21822 	kill_all();
21823 	unload_level();
21824 
21825 	return type==2 || (player[0].lives > 0 || player[1].lives > 0 || player[2].lives > 0|| player[3].lives > 0); //4player
21826 }
21827 
21828 
selectplayer(int * players,char * filename)21829 int selectplayer(int *players, char* filename)
21830 {
21831 	s_model* tempmodel;
21832 	entity *example[4] = {NULL,NULL,NULL,NULL};
21833 	int i,x;
21834 	int cmap[MAX_PLAYERS] = {0,1,2,3};
21835 	int tperror = 0;
21836 	int exit = 0;
21837 	int ready[MAX_PLAYERS] = {0,0,0,0};
21838 	int escape = 0;
21839 	int players_busy = 0;
21840 	int players_ready = 0;
21841 	int immediate[MAX_PLAYERS]= {0,0,0,0};
21842 	char string[128] = {""};
21843 	char* buf, *command;
21844 	size_t size = 0;
21845 	ptrdiff_t pos = 0;
21846 	ArgList arglist;
21847 	char argbuf[MAX_ARG_LEN+1] = "";
21848 	s_set_entry* set = levelsets+current_set;
21849 
21850 	selectScreen = 1;
21851 	kill_all();
21852 	reset_playable_list(1);
21853 
21854 	if(loadGameFile())
21855 	{
21856 		bonus = 0;
21857 		if(savelevel)
21858 		for(i=0; i<num_difficulties; i++) if(savelevel[i].times_completed > 0) bonus += savelevel[i].times_completed;
21859 	}
21860 
21861 	if(filename && filename[0])
21862 	{
21863 		if(buffer_pakfile(filename, &buf, &size)!=1) shutdown(1, "Failed to load player select file '%s'", filename);
21864 		while(pos < size)
21865 		{
21866 			ParseArgs(&arglist,buf+pos,argbuf);
21867 			command = GET_ARG(0);
21868 			if(command && command[0])
21869 			{
21870 				if(stricmp(command, "music")==0)
21871 				{
21872 					music(GET_ARG(1), GET_INT_ARG(2), atol(GET_ARG(3)));
21873 				}
21874 				else if(stricmp(command, "allowselect")==0)
21875 				{
21876 					load_playable_list(buf+pos);
21877 				}
21878 				else if(stricmp(command, "background")==0)
21879 				{
21880 					load_background(GET_ARG(1), 1);
21881 				}
21882 				else if(stricmp(command, "load")==0){
21883 					tempmodel = findmodel(GET_ARG(1));
21884 					if (!tempmodel)
21885 						load_cached_model(GET_ARG(1), filename, GET_INT_ARG(2));
21886 					else
21887 						update_model_loadflag(tempmodel, GET_INT_ARG(2));
21888 				}
21889 				else
21890 					if(command && command[0])
21891 						printf("Command '%s' is not understood in file '%s'", command, filename);
21892 			}
21893 
21894 			pos += getNewLineStart(buf + pos);
21895 		}
21896 		if(buf != NULL)
21897 		{
21898 			free(buf);
21899 			buf = NULL;
21900 		}
21901 		for(i=0; i<set->maxplayers; i++)
21902 		{
21903 			if(players[i])
21904 			{
21905 				if(!psmenu[i][0] && !psmenu[i][1])
21906 				{
21907 					if(set->maxplayers > 2) example[i] = spawn((float)((111-(set->maxplayers*14))+((i*(320-(166/set->maxplayers))/set->maxplayers)+videomodes.hShift)),(float)(230+videomodes.vShift),0 ,spdirection[i] , NULL, -1, nextplayermodel(NULL));
21908 					else example[i] = spawn((float)(83+(videomodes.hShift/2)+(i*(155+videomodes.hShift))),(float)(230+videomodes.vShift),0 ,spdirection[i] , NULL, -1, nextplayermodel(NULL));
21909 				}
21910 				else example[i] = spawn((float)psmenu[i][0], (float)psmenu[i][1], 0, spdirection[i], NULL, -1, nextplayermodel(NULL));
21911 			}
21912 		}
21913 	}
21914 	else // without select.txt
21915 	{
21916 		if(skipselect[0][0] || set->noselect)
21917 		{
21918 			for(i=0; i<set->maxplayers; i++)
21919 			{
21920 				memset(&player[i], 0, sizeof(s_player));
21921 				if(!players[i]) continue;
21922 
21923 				strncpy(player[i].name, skipselect[i], MAX_NAME_LEN);
21924 				//else continue;
21925 				if(!noshare) credits = CONTINUES;
21926 				else
21927 				{
21928 					player[i].credits = CONTINUES;
21929 					player[i].hasplayed = 1;
21930 				}
21931 				if(!creditscheat)
21932 				{
21933 					if(noshare) --player[i].credits;
21934 					else --credits;
21935 				}
21936 				player[i].lives = PLAYER_LIVES;
21937 			}
21938 			selectScreen = 0;
21939 			return 1;
21940 		}
21941 
21942 		if(unlockbg && bonus)
21943 		{
21944 			// New alternative background path for PSP
21945 			if(custBkgrds != NULL)
21946 			{
21947 				strcpy(string, custBkgrds);
21948 				strncat(string, "unlockbg", 8);
21949 				load_background(string, 1);
21950 			}
21951 			else load_cached_background("data/bgs/unlockbg", 1);
21952 		}
21953 		else
21954 		{
21955 			// New alternative background path for PSP
21956 			if(custBkgrds != NULL)
21957 			{
21958 				strncpy(string, custBkgrds, 128);
21959 				strncat(string, "select", 6);
21960 				load_background(string, 1);
21961 			}
21962 			else load_cached_background("data/bgs/select", 1);
21963 		}
21964 		if(!music("data/music/menu", 1, 0))
21965 			music("data/music/remix",1,0);
21966 		if(!noshare) credits = CONTINUES;
21967 		for(i=0; i<MAX_PLAYERS; i++)
21968 		{
21969 			memset(&player[i], 0, sizeof(s_player));
21970 			immediate[i] = players[i];
21971 		}
21972 	}
21973 
21974 
21975 	while(!(exit || escape))
21976 	{
21977 		players_busy = 0;
21978 		players_ready = 0;
21979 		for(i=0; i<set->maxplayers; i++)
21980 		{
21981 			// you can't have that character!
21982 			if((tperror == i+1) && !ready[i]) font_printf(75+videomodes.hShift,123+videomodes.vShift,0, 0,"Player %d Choose a Different Character!", i+1);
21983 			if(!ready[i])
21984 			{
21985 				if(player[i].lives <= 0 && (noshare || credits>0) && ((player[i].newkeys & FLAG_ANYBUTTON) || immediate[i]))
21986 				{
21987 					if(noshare)
21988 					{
21989 						player[i].credits = CONTINUES;
21990 						player[i].hasplayed = 1;
21991 					}
21992 
21993 					if(!creditscheat)
21994 					{
21995 						if(noshare) --player[i].credits;
21996 						else --credits;
21997 					}
21998 
21999 					player[i].lives = PLAYER_LIVES;
22000 
22001 					if(!psmenu[i][0] && !psmenu[i][1])
22002 					{
22003 						if(set->maxplayers > 2) example[i] = spawn((float)((111-(set->maxplayers*14))+((i*(320-(166/set->maxplayers))/set->maxplayers)+videomodes.hShift)),(float)(230+videomodes.vShift),0 ,spdirection[i] , NULL, -1, nextplayermodel(NULL));
22004 						else example[i] = spawn((float)(83+(videomodes.hShift/2)+(i*(155+videomodes.hShift))),(float)(230+videomodes.vShift),0 ,spdirection[i] , NULL, -1, nextplayermodel(NULL));
22005 					}
22006 					else example[i] = spawn((float)psmenu[i][0], (float)psmenu[i][1], 0, spdirection[i], NULL, -1, nextplayermodel(NULL));
22007 
22008 					if(example[i]==NULL) shutdown(1, "Failed to create player selection object!");
22009 
22010 					// Select Player Direction for select player screen
22011 					// example[i]->direction = spdirection[i]; // moved to spawn method
22012 
22013 					// Make player 2 different colour automatically
22014 					player[i].colourmap = i;
22015 
22016 					while((example[i]->modeldata.maps.hide_start) && (example[i]->modeldata.maps.hide_end) &&
22017 					cmap[i] >= example[i]->modeldata.maps.hide_start &&
22018 					cmap[i] <= example[i]->modeldata.maps.hide_end )
22019 					{
22020 						cmap[i]++;
22021 						if(cmap[i] > example[i]->modeldata.maps_loaded) cmap[i] = 0;
22022 					}
22023 
22024 					player[i].playkeys = 0;
22025 					ent_set_colourmap(example[i], cmap[i]);
22026 
22027 					if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22028 				}
22029 				else if(player[i].newkeys & FLAG_MOVELEFT && example[i])
22030 				{
22031 					if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22032 					ent_set_model(example[i], prevplayermodel(example[i]->model)->name, 0);
22033 					cmap[i] = i;
22034 
22035 					while((example[i]->modeldata.maps.hide_start) && (example[i]->modeldata.maps.hide_end) &&
22036 					cmap[i] >= example[i]->modeldata.maps.hide_start &&
22037 					cmap[i] <= example[i]->modeldata.maps.hide_end )
22038 					{
22039 						cmap[i]++;
22040 						if(cmap[i] > example[i]->modeldata.maps_loaded) cmap[i] = 0;
22041 					}
22042 
22043 					ent_set_colourmap(example[i], cmap[i]);
22044 					tperror = 0;
22045 				}
22046 				else if(player[i].newkeys & FLAG_MOVERIGHT && example[i])
22047 				{
22048 					if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22049 					ent_set_model(example[i], nextplayermodel(example[i]->model)->name, 0);
22050 					cmap[i] = i;
22051 
22052 					while((example[i]->modeldata.maps.hide_start) && (example[i]->modeldata.maps.hide_end) &&
22053 					cmap[i] >= example[i]->modeldata.maps.hide_start && cmap[i] <= example[i]->modeldata.maps.hide_end )
22054 					{
22055 						cmap[i]++;
22056 						if(cmap[i] > example[i]->modeldata.maps_loaded) cmap[i] = 0;
22057 					}
22058 
22059 					ent_set_colourmap(example[i], cmap[i]);
22060 					tperror = 0;
22061 				}
22062 				// oooh pretty colors! - selectable color scheme for player characters
22063 				else if(player[i].newkeys & FLAG_MOVEUP && colourselect && example[i])
22064 				{
22065 					do
22066 					{
22067 						cmap[i]++;
22068 						if(cmap[i] > example[i]->modeldata.maps_loaded) cmap[i] = 0;
22069 					}
22070 					while(
22071 					(example[i]->modeldata.maps.frozen &&
22072 					cmap[i] - 1 == example[i]->modeldata.maps.frozen - 1) ||
22073 					((example[i]->modeldata.maps.hide_start) && (example[i]->modeldata.maps.hide_end) &&
22074 					cmap[i] - 1 >= example[i]->modeldata.maps.hide_start - 1 &&
22075 					cmap[i] - 1 <= example[i]->modeldata.maps.hide_end - 1)
22076 					);
22077 
22078 					ent_set_colourmap(example[i], cmap[i]);
22079 				}
22080 				else if(player[i].newkeys & FLAG_MOVEDOWN && colourselect && example[i])
22081 				{
22082 					do
22083 					{
22084 						cmap[i]--;
22085 						if(cmap[i] < 0) cmap[i] = example[i]->modeldata.maps_loaded;
22086 					}
22087 					while(
22088 					(example[i]->modeldata.maps.frozen &&
22089 					cmap[i] - 1 == example[i]->modeldata.maps.frozen - 1) ||
22090 					((example[i]->modeldata.maps.hide_start) && (example[i]->modeldata.maps.hide_end) &&
22091 					cmap[i] - 1 >= example[i]->modeldata.maps.hide_start - 1 &&
22092 					cmap[i] - 1 <= example[i]->modeldata.maps.hide_end - 1)
22093 					);
22094 
22095 					ent_set_colourmap(example[i], cmap[i]);
22096 				}
22097 				else if((player[i].newkeys & FLAG_ANYBUTTON) && example[i])
22098 				{
22099 
22100 					if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
22101 					strcpy(player[i].name, example[i]->modeldata.name);
22102 					player[i].colourmap = cmap[i];
22103 
22104 					// reports error if players try to use the same character and sameplay mode is off
22105 					if(sameplayer)
22106 					{
22107 						for(x=0; x<set->maxplayers; x++)
22108 						{
22109 							if((strncmp(player[i].name,player[x].name,strlen(player[i].name)) == 0) && (i != x))
22110 							{
22111 								tperror = i+1;
22112 								break;
22113 							}
22114 						}
22115 					}
22116 
22117 					if(!tperror)
22118 					{
22119 						time=0;
22120 						// yay you picked me!
22121 						if(validanim(example[i],ANI_PICK)) ent_set_anim(example[i], ANI_PICK, 0);
22122 						while(!ready[i] && example[i] != NULL)
22123 						{
22124 							update(0,0);
22125 							if((!validanim(example[i],ANI_PICK) || example[i]->modeldata.animation[ANI_PICK]->loop.mode) && time>GAME_SPEED*2) ready[i] = 1;
22126 							else if(!example[i]->animating) ready[i] = 1;
22127 							if(ready[i]) time=0;
22128 						}
22129 					}
22130 				}
22131 			}
22132 			else
22133 			{
22134 				if(!psmenu[i][2] && !psmenu[i][3])
22135 				{
22136 					if(set->maxplayers > 2) font_printf((95-(set->maxplayers*14))+((i*(320-(166/set->maxplayers))/set->maxplayers)+videomodes.hShift), 225+videomodes.vShift, 0, 0, "Ready!");
22137 					else font_printf(67+(videomodes.hShift/2)+(i*(155+videomodes.hShift)), 225+videomodes.vShift, 0, 0, "Ready!");
22138 				}
22139 				else font_printf(psmenu[i][2], psmenu[i][3], 0, 0, "Ready!");
22140 			}
22141 
22142 			if(example[i] != NULL) players_busy++;
22143 			if(ready[i]) players_ready++;
22144 		}
22145 
22146 		if(players_busy && players_busy==players_ready && time>GAME_SPEED) exit = 1;
22147 		update(0,0);
22148 
22149 		if(bothnewkeys & FLAG_ESC) escape = 1;
22150 	}
22151 
22152 	// No longer at the select screen
22153 	kill_all();
22154 	sound_close_music();
22155 	selectScreen = 0;
22156 
22157 	return (!escape);
22158 }
22159 
playgame(int * players,unsigned which_set,int useSavedGame)22160 void playgame(int *players,  unsigned which_set, int useSavedGame)
22161 {
22162 	int i;
22163 	current_level = 0;
22164 	current_stage = 1;
22165 	current_set = which_set;
22166 	s_set_entry* set = levelsets + current_set;
22167 	s_savelevel* save = savelevel + current_set;
22168 	s_level_entry* le;
22169 
22170 	if(which_set>=num_difficulties) return;
22171 	// shutdown(1, "Illegal set chosen: index %i (there are only %i sets)!", which_set, num_difficulties);
22172 
22173 	allow_secret_chars = set->ifcomplete;
22174 	PLAYER_LIVES = set->lives;
22175 	musicoverlap = set->musicoverlap;
22176 	fade = set->custfade;
22177 	CONTINUES = set->credits;
22178 	magic_type = set->typemp;
22179 	if(PLAYER_LIVES == 0) PLAYER_LIVES = 3;
22180 	if(CONTINUES == 0) CONTINUES = 5;
22181 	if(fade == 0) fade = 24;
22182 	sameplayer = set->nosame;
22183 
22184 	memset(player, 0, sizeof(s_player)*4);
22185 
22186 	for(i=0; i<MAX_PLAYERS; i++)
22187 	{
22188 		if(set->skipselect[i]) strcpy(skipselect[i], set->skipselect[i]);
22189 		else skipselect[i][0] = 0;
22190 	}
22191 
22192 	if(useSavedGame && save->flag)
22193 	{
22194 		if(!loadScriptFile()) printf("Warning, failed to load script save!\n");
22195 		current_level = save->level;
22196 		current_stage = save->stage;
22197 		if(save->flag == 2) // don't check 1 or 0 becuase if we use saved game the flag must be >0
22198 		{
22199 			for(i=0; i<set->maxplayers; i++)
22200 			{
22201 				player[i].lives = save->pLives[i];
22202 				player[i].score = save->pScores[i];
22203 				player[i].colourmap = save->pColourmap[i];
22204 				player[i].weapnum = save->pWeapnum[i];
22205 				player[i].spawnhealth = save->pSpawnhealth[i];
22206 				player[i].spawnmp = save->pSpawnmp[i];
22207 				strncpy(player[i].name, save->pName[i], MAX_NAME_LEN);
22208 			}
22209 			credits = save->credits;
22210 			reset_playable_list(1); // add this because there's no select screen, temporary solution
22211 			//TODO: change sav format to support custom allowselect list.
22212 		}
22213 	}
22214 
22215 	nosave = 1;
22216 
22217 	if((useSavedGame && save->flag == 2) || selectplayer(players, NULL)) // if save flag is 2 don't select player
22218 	{
22219 		while(current_level < set->numlevels)
22220 		{
22221 			if(branch_name[0])  // branch checking
22222 			{
22223 				//current_stage = 1; //jump, jump... perhaps we don't need to reset it, modders should take care of it.
22224 				for(i=0; i<set->numlevels; i++)
22225 				{
22226 					if(set->levelorder[i].branchname && stricmp(set->levelorder[i].branchname, branch_name)==0)
22227 					{
22228 						current_level = i;
22229 						break;
22230 					}
22231 					//if(levelorder[which_set][i]->gonext==1) ++current_stage; OX. Commented this line out. Seems to be cause of inacurate stage # complete message.
22232 				}
22233 				branch_name[0] = 0;// clear up so we won't stuck here
22234 			}
22235 			le = set->levelorder+current_level;
22236 			PLAYER_MIN_Z = le->z_coords[0];
22237 			PLAYER_MAX_Z = le->z_coords[1];
22238 			BGHEIGHT = le->z_coords[2];
22239 
22240 			if(le->type==cut_scene)
22241 				playscene(le->filename);
22242 			else if(le->type==select_screen)
22243 			{
22244 				for(i=0; i<set->maxplayers ; i++) players[i] = (player[i].lives>0);
22245 				if(selectplayer(players, le->filename)==0)
22246 				{
22247 					break;
22248 				}
22249 			}
22250 			else if(!playlevel(le->filename))
22251 			{
22252 				if(player[0].lives <= 0 && player[1].lives <= 0 && player[2].lives <= 0 && player[3].lives <= 0){
22253 					gameover();
22254 					if(!set->noshowhof) hallfame(1);
22255 					for(i=0; i<set->maxplayers; i++)
22256 					{
22257 						player[i].hasplayed = 0;
22258 						player[i].weapnum = 0;
22259 					}
22260 				}
22261 				break;
22262 			}
22263 			if(le->gonext==1)
22264 			{
22265 				showcomplete(current_stage);
22266 				for(i=0; i<set->maxplayers; i++)
22267 				{
22268 					player[i].spawnhealth = 0;
22269 					player[i].spawnmp = 0;
22270 				}
22271 				++current_stage;
22272 				save->stage = current_stage;
22273 			}
22274 			current_level++;
22275 			le = set->levelorder+current_level;
22276 			save->level = current_level;
22277 			//2007-2-24, gonext = 2, end game
22278 			if((le-1)->gonext == 2)
22279 			{
22280 				current_level = set->numlevels;
22281 			}
22282 			if(useSave) goto endgame; //quick exit without saving, for script load game logic
22283 		}//while
22284 
22285 		if(current_level >= set->numlevels)
22286 		{
22287 			bonus += save->times_completed++;
22288 			saveGameFile();
22289 			if(!nofadeout) fade_out(0, 0);
22290 			if(!set->noshowhof) hallfame(1);
22291 		}
22292 	}
22293 
22294 endgame:
22295 	// clear global script variant list
22296 	branch_name[0] = 0;
22297 	//max_global_var_index = -1;
22298 	//for(i=0; i<max_indexed_vars; i++) ScriptVariant_Clear(indexed_var_list+i);
22299 	sound_close_music();
22300 }
22301 
choose_difficulty()22302 int choose_difficulty()
22303 {
22304 	int quit = 0;
22305 	int selector = 0;
22306 	int maxdisplay = 5;
22307 	int i, j;
22308 	//float slider = 0;
22309 	int barx, bary, barw, barh;
22310 
22311 	barx = videomodes.hRes/5; bary = _liney(0,0)-2; barw = videomodes.hRes*3/5; barh = 5*(fontheight(0)+1)+4;
22312 	bothnewkeys = 0;
22313 
22314 	if(loadGameFile())
22315 	{
22316 		bonus = 0;
22317 		for(i=0; i<num_difficulties; i++) if(savelevel[i].times_completed > 0) bonus += savelevel[i].times_completed;
22318 	}
22319 
22320 	while(!quit)
22321 	{
22322 		if(num_difficulties > 1)
22323 		{
22324 			_menutextm(2, -2, 0, "Game Mode");
22325 			for(j=0,i=num_difficulties <= maxdisplay?0:(selector>=maxdisplay?maxdisplay:0); i<num_difficulties; j++,i++)
22326 			{
22327 				if(j < maxdisplay)
22328 				{
22329 					if(bonus >= levelsets[i].ifcomplete) _menutextm((selector==i), j, 0, "%s", levelsets[i].name);
22330 					else
22331 					{
22332 						if(levelsets[i].ifcomplete>1) _menutextm((selector==i), j, 0, "%s - Finish Game %i Times To UnLock", levelsets[i].name, levelsets[i].ifcomplete);
22333 						else _menutextm((selector==i), 2+j, 0, "%s - Finish Game To UnLock", levelsets[i].name);
22334 					}
22335 				}
22336 				else break;
22337 			}
22338 			_menutextm((selector==i), 6, 0, "Back");
22339 
22340 			//draw the scroll bar
22341 			if(num_difficulties>maxdisplay)
22342 			{
22343 				spriteq_add_box(barx,  bary,        barw,     barh,   0, color_black, 1); //outerbox
22344 				spriteq_add_line(barx, bary,  barx+8, bary, 1, color_white, 0);
22345 				spriteq_add_line(barx, bary, barx, bary + barh, 1, color_white, 0);
22346 				spriteq_add_line(barx + 8, bary, barx+8, bary+barh,  1, color_white, 0);
22347 				spriteq_add_line(barx, bary+barh, barx+8, bary+barh,  1, color_white, 0);
22348 				spriteq_add_box(barx+1,  bary + selector*(barh-3)/num_difficulties, 7,             3,            2, color_white, 0); //slider
22349 			}
22350 		}
22351 
22352 		update(0,0);
22353 
22354 		if(num_difficulties==1){ // OX. Mods with only one set will auto load that difficulty.
22355 			if(selector==num_difficulties) quit = 1;
22356 			else if(bonus >= levelsets[selector].ifcomplete){
22357 				saveslot = selector;
22358 				strncpy(savelevel[saveslot].dName, levelsets[saveslot].name, MAX_NAME_LEN+1);
22359 				return saveslot;
22360 		}
22361 		}
22362 
22363 		if(bothnewkeys & FLAG_ESC) quit = 1;
22364 		if(bothnewkeys & FLAG_MOVEUP)
22365 		{
22366 			--selector;
22367 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22368 		}
22369 		if(bothnewkeys & FLAG_MOVEDOWN)
22370 		{
22371 			++selector;
22372 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22373 		}
22374 		if(selector<0) selector = num_difficulties;
22375 		if(selector>num_difficulties) selector = 0;
22376 		//if(selector<num_difficulties) slider = selector * 4.5;
22377 
22378 		if(bothnewkeys & FLAG_ANYBUTTON){
22379 
22380 			if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
22381 
22382 			if(selector==num_difficulties) quit = 1;
22383 			else if(bonus >= levelsets[selector].ifcomplete){
22384 				saveslot = selector;
22385 				strncpy(savelevel[saveslot].dName, levelsets[saveslot].name, MAX_NAME_LEN+1);
22386 				return saveslot;
22387 			}
22388 		}
22389 	}
22390 	bothnewkeys = 0;
22391 	return -1;
22392 }
22393 
load_saved_game()22394 int load_saved_game()
22395 {
22396 	int quit = 0;
22397 	int selector = 0;
22398 	int savedStatus = 0;
22399 	char name[256] = {""};
22400 	int col1 = -8, col2=6;
22401 
22402 	bothnewkeys = 0;
22403 
22404 	if((savedStatus = loadGameFile())) getPakName(name,0);
22405 	for(saveslot=0; saveslot<num_difficulties; saveslot++) if(savelevel[saveslot].flag && savelevel[saveslot].level) break;
22406 
22407 	while(!quit)
22408 	{
22409 		if(saveslot>=num_difficulties) // not found
22410 		{
22411 			_menutextm(2, -4, 0, "Load Game");
22412 			_menutext(0, col1, -2, "Saved File:");
22413 			_menutext(0, col2, -2, "Not Found!");
22414 			_menutextm(1, 6, 0, "Back");
22415 
22416 			selector = 2;
22417 		}
22418 		else
22419 		{
22420 			_menutextm(2, -4, 0, "Load Game");
22421 			_menutext(0, col1, -2, "Saved File:");
22422 			if(savedStatus) _menutext(0, col2, -2, "%s", name);
22423 			else _menutext(0, col2, -2, "Not Found!");
22424 
22425 			if(savedStatus){
22426 				_menutext((selector==0), col1, -1, "Mode:");
22427 				_menutext((selector==0), col2, -1, "%s", savelevel[saveslot].dName);
22428 				_menutext(0, col1, 0, "Stage:");
22429 				_menutext(0, col2, 0, "%d", savelevel[saveslot].stage);
22430 				_menutext(0, col1, 1, "Level:");
22431 				_menutext(0, col2, 1, "%d", savelevel[saveslot].level);
22432 				_menutext(0, col1, 2, "Credits:");
22433 				_menutext(0, col2, 2, "%d", savelevel[saveslot].credits);
22434 				_menutext(0, col1, 3, "Player Lives:");
22435 				_menutext(0, col2, 3, "%d/%d/%d/%d",
22436 					savelevel[saveslot].pLives[0],
22437 					savelevel[saveslot].pLives[1], savelevel[saveslot].pLives[2],
22438 					savelevel[saveslot].pLives[3]);
22439 				_menutextm((selector==1), 5, 0, "Start Game");
22440 			}
22441 			_menutextm((selector==2), 6, 0, "Back");
22442 		}
22443 		update(0,0);
22444 
22445 		if(bothnewkeys & FLAG_ESC) quit = 1;
22446 		if(selector == 0 && (bothnewkeys & FLAG_MOVELEFT)){
22447 			while(1){
22448 				--saveslot;
22449 				if(saveslot<0) saveslot = num_difficulties - 1;
22450 				if(savelevel[saveslot].flag && savelevel[saveslot].level) break;
22451 			}
22452 			sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22453 		}
22454 		if(selector == 0 && (bothnewkeys & FLAG_MOVERIGHT)){
22455 			while(1){
22456 				++saveslot;
22457 				if(saveslot>num_difficulties - 1) saveslot = 0;
22458 				if(savelevel[saveslot].flag && savelevel[saveslot].level) break;
22459 			}
22460 			sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22461 		}
22462 		if(bothnewkeys & FLAG_MOVEUP){
22463 			--selector;
22464 			sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22465 		}
22466 		if(bothnewkeys & FLAG_MOVEDOWN){
22467 			++selector;
22468 			sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22469 		}
22470 		if(savedStatus){
22471 			if(selector<0) selector = 2;
22472 			if(selector>2) selector = 0;
22473 		}
22474 		else selector = 2;
22475 
22476 		if(selector > 0 && (bothnewkeys & FLAG_ANYBUTTON)){
22477 			sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
22478 			switch(selector){
22479 				case 1:
22480 					return saveslot;
22481 					break;
22482 				case 2:
22483 					quit = 1;
22484 					break;
22485 			}
22486 		}
22487 	}
22488 	bothnewkeys = 0;
22489 	return -1;
22490 }
22491 
choose_mode(int * players)22492 int choose_mode(int *players)
22493 {
22494 	int quit = 0;
22495 	int relback = 0;
22496 	int selector = 0;
22497 	int status = 0;
22498 
22499 	bothnewkeys = 0;
22500 
22501 	while(!quit)
22502 	{
22503 		_menutextm(2, 1, 0, "Choose Mode");
22504 		_menutextm((selector==0), 3, 0, "New Game");
22505 		_menutextm((selector==1), 4, 0, "Load Game");
22506 		_menutextm((selector==2), 6, 0, "Back");
22507 
22508 		update(0,0);
22509 
22510 		if(bothnewkeys & FLAG_ESC) quit = 1;
22511 		if(bothnewkeys & FLAG_MOVEUP)
22512 		{
22513 			--selector;
22514 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22515 		}
22516 		if(bothnewkeys & FLAG_MOVEDOWN)
22517 		{
22518 			++selector;
22519 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22520 		}
22521 		if(selector<0) selector = 2;
22522 		if(selector>2) selector = 0;
22523 
22524 		if(bothnewkeys & FLAG_ANYBUTTON)
22525 		{
22526 			if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
22527 			switch(selector)
22528 			{
22529 				case 0:
22530 					status = choose_difficulty();
22531 					if(status != -1)
22532 					{
22533 						playgame(players, status, 0);
22534 						relback = 1;
22535 						quit = 1;
22536 					}
22537 					break;
22538 				case 1:
22539 					status = load_saved_game();
22540 					if(status != -1)
22541 					{
22542 						playgame(players, status, 1);
22543 						relback = 1;
22544 						quit = 1;
22545 					}
22546 					break;
22547 				default:
22548 					quit = 1;
22549 					break;
22550 			}
22551 		}
22552 	}
22553 	bothnewkeys = 0;
22554 	return relback;
22555 }
22556 
term_videomodes()22557 void term_videomodes()
22558 {
22559 	videomodes.hRes = 0;
22560 	videomodes.vRes = 0;
22561 	video_set_mode(videomodes);
22562 	if(custScenes != NULL) free(custScenes); custScenes = NULL;
22563 	if(custBkgrds != NULL) free(custBkgrds); custBkgrds = NULL;
22564 	if(custLevels != NULL) free(custLevels); custLevels = NULL;
22565 	if(custModels != NULL) free(custModels); custModels = NULL;
22566 }
22567 
22568 // Load Video Mode from file
init_videomodes(int log)22569 void init_videomodes(int log)
22570 {
22571 	char *filename = "data/video.txt";
22572 	int bits = 8, tmp;
22573 	ptrdiff_t pos, len;
22574 	size_t size;
22575 	char *buf = NULL;
22576 	char *command = NULL;
22577 	char *value = NULL;
22578 	ArgList arglist;
22579 	char argbuf[MAX_ARG_LEN+1] = "";
22580 
22581 	if(log) printf("Initializing video............\n");
22582 
22583 	// Use an alternative video.txt if there is one.  Some of these are long filenames; create your PAKs with borpak and you'll be fine.
22584 #define tryfile(X) if((tmp=openpackfile(X,packfile))!=-1) { closepackfile(tmp); filename=X; goto readfile; }
22585 #if WIN || LINUX
22586 	tryfile("data/videopc.txt");
22587 #elif WII
22588 	tryfile("data/videowii.txt");
22589 	if(CONF_GetAspectRatio() == CONF_ASPECT_16_9) { tryfile("data/video169.txt") }
22590 	else tryfile("data/video43.txt");
22591 #elif PSP
22592 	tryfile("data/videopsp.txt");
22593 	tryfile("data/video169.txt");
22594 #elif DC
22595 	tryfile("data/videodc.txt");
22596 	tryfile("data/video43.txt");
22597 #elif WIZ
22598 	tryfile("data/videowiz.txt");
22599 	tryfile("data/video169.txt");
22600 #elif GP2X
22601 	tryfile("data/videogp2x.txt");
22602 	tryfile("data/video43.txt");
22603 #elif DINGOO
22604 	tryfile("data/videodingoo.txt");
22605 	tryfile("data/video43.txt");
22606 #elif SYMBIAN
22607 	tryfile("data/videosymbian.txt");
22608 #endif
22609 #undef tryfile
22610 
22611 readfile:
22612 	// Read file
22613 	if(buffer_pakfile(filename, &buf, &size)!=1)
22614 	{
22615 		videoMode = 0;
22616 		printf("'%s' not found.\n", filename);
22617 		goto VIDEOMODES;
22618 	}
22619 
22620 	printf("Reading video settings from '%s'.\n", filename);
22621 
22622 	// Now interpret the contents of buf line by line
22623 	pos = 0;
22624 	while(pos<size){
22625 		ParseArgs(&arglist,buf+pos,argbuf);
22626 		command = GET_ARG(0);
22627 
22628 		if(command && command[0]){
22629 			if(stricmp(command, "video")==0){
22630 				videoMode = GET_INT_ARG(1);
22631 			}
22632 			else if(stricmp(command, "scenes")==0){
22633 				len = strlen(GET_ARG(1));
22634 				custScenes = malloc(len + 1);
22635 				strcpy(custScenes, GET_ARG(1));
22636 				custScenes[len] = 0;
22637 			}
22638 			else if(stricmp(command, "backgrounds")==0){
22639 				len = strlen(GET_ARG(1));
22640 				custBkgrds = malloc(len + 1);
22641 				strcpy(custBkgrds, GET_ARG(1));
22642 				custBkgrds[len] = 0;
22643 			}
22644 			else if(stricmp(command, "levels")==0){
22645 				len = strlen(GET_ARG(1));
22646 				custLevels = malloc(len + 1);
22647 				strcpy(custLevels, GET_ARG(1));
22648 				custLevels[len] = 0;
22649 			}
22650 			else if(stricmp(command, "models")==0){
22651 				len = strlen(GET_ARG(1));
22652 				custModels = malloc(len + 1);
22653 				strcpy(custModels, GET_ARG(1));
22654 				custModels[len] = 0;
22655 			}
22656 			else if(stricmp(command, "colourdepth")==0){
22657 				pixelformat=PIXEL_x8;
22658 				value = GET_ARG(1);
22659 				if(stricmp(value, "8bit")==0)
22660 				{
22661 					screenformat=PIXEL_8;
22662 					pixelformat=PIXEL_8;
22663 				}
22664 				else if(stricmp(value, "16bit")==0) { screenformat=PIXEL_16; bits=16; }
22665 				else if(stricmp(value, "32bit")==0) { screenformat=PIXEL_32; bits=32; }
22666 				else if(value[0]==0) screenformat=PIXEL_32;
22667 				else shutdown(1, "Screen colour depth can only be either 8bit, 16bit or 32bit.");
22668 			}
22669 			else
22670 				if(stricmp(command, "forcemode")==0) {}
22671 			else
22672 				if(command && command[0])
22673 					printf("Command '%s' not understood in file '%s'!", command, filename);
22674 		}
22675 		// Go to next line
22676 	pos += getNewLineStart(buf + pos);
22677 	}
22678 
22679 	if(buf != NULL){
22680 		free(buf);
22681 		buf = NULL;
22682 	}
22683 
22684 #if DINGOO || GP2X
22685 	videoMode = 0;
22686 #endif
22687 
22688 #if SYMBIAN
22689 	if(videoMode != 0 && videoMode != 2)
22690 	{
22691 		videoMode = 0;
22692 	}
22693 #endif
22694 
22695 VIDEOMODES:
22696 	switch (videoMode)
22697 	{
22698 		// 320x240 - All Platforms
22699 		case 0:
22700 			videomodes.mode    = savedata.screen[videoMode][0];
22701 			videomodes.filter  = savedata.screen[videoMode][1];
22702 			videomodes.hRes    = 320;
22703 			videomodes.vRes    = 240;
22704 			videomodes.hScale  = 1;
22705 			videomodes.vScale  = 1;
22706 			videomodes.hShift  = 0;
22707 			videomodes.vShift  = 0;
22708 			videomodes.dOffset = 231;
22709 			PLAYER_MIN_Z       = 160;
22710 			PLAYER_MAX_Z       = 232;
22711 			BGHEIGHT           = 160;
22712 	        break;
22713 
22714 		// 480x272 - All Platforms
22715 		case 1:
22716 			videomodes.mode    = savedata.screen[videoMode][0];
22717 			videomodes.filter  = savedata.screen[videoMode][1];
22718 	        videomodes.hRes    = 480;
22719 			videomodes.vRes    = 272;
22720 			videomodes.hScale  = (float)1.5;
22721 			videomodes.vScale  = (float)1.13;
22722 			videomodes.hShift  = 80;
22723 			videomodes.vShift  = 20;
22724 			videomodes.dOffset = 263;
22725 			PLAYER_MIN_Z       = 182;
22726 			PLAYER_MAX_Z       = 264;
22727 			BGHEIGHT           = 182;
22728 			break;
22729 
22730 		// 640x480 - PC, Dreamcast, Wii
22731 		case 2:
22732 			videomodes.mode    = savedata.screen[videoMode][0];
22733 			videomodes.filter  = savedata.screen[videoMode][1];
22734 	        videomodes.hRes    = 640;
22735 			videomodes.vRes    = 480;
22736 			videomodes.hScale  = 2;
22737 			videomodes.vScale  = 2;
22738 			videomodes.hShift  = 160;
22739 			videomodes.vShift  = 35;
22740 			videomodes.dOffset = 464;
22741 			PLAYER_MIN_Z       = 321;
22742 			PLAYER_MAX_Z       = 465;
22743 			BGHEIGHT           = 321;
22744 			break;
22745 
22746 		// 720x480 - PC, Wii
22747 		case 3:
22748 			videomodes.mode    = savedata.screen[videoMode][0];
22749 			videomodes.filter  = savedata.screen[videoMode][1];
22750 	        videomodes.hRes    = 720;
22751 			videomodes.vRes    = 480;
22752 			videomodes.hScale  = 2.25;
22753 			videomodes.vScale  = 2;
22754 			videomodes.hShift  = 200;
22755 			videomodes.vShift  = 35;
22756 			videomodes.dOffset = 464;
22757 			PLAYER_MIN_Z       = 321;
22758 			PLAYER_MAX_Z       = 465;
22759 			BGHEIGHT           = 321;
22760 			break;
22761 
22762 		// 800x480 - PC, Wii, Pandora
22763 		case 4:
22764 			videomodes.mode    = savedata.screen[videoMode][0];
22765 			videomodes.filter  = savedata.screen[videoMode][1];
22766 			videomodes.hRes    = 800;
22767 			videomodes.vRes    = 480;
22768 			videomodes.hScale  = 2.5;
22769 			videomodes.vScale  = 2;
22770 			videomodes.hShift  = 240;
22771 			videomodes.vShift  = 35;
22772 			videomodes.dOffset = 464;
22773 			PLAYER_MIN_Z       = 321;
22774 			PLAYER_MAX_Z       = 465;
22775 			BGHEIGHT           = 321;
22776 			break;
22777 
22778 		// 800x600 - PC, Dreamcast, Wii
22779 		case 5:
22780 			videomodes.mode    = savedata.screen[videoMode][0];
22781 			videomodes.filter  = savedata.screen[videoMode][1];
22782 			videomodes.hRes    = 800;
22783 			videomodes.vRes    = 600;
22784 			videomodes.hScale  = 2.5;
22785 			videomodes.vScale  = 2.5;
22786 			videomodes.hShift  = 240;
22787 			videomodes.vShift  = 44;
22788 			videomodes.dOffset = 580;
22789 			PLAYER_MIN_Z       = 401;
22790 			PLAYER_MAX_Z       = 582;
22791 			BGHEIGHT           = 401;
22792 			break;
22793 
22794 		// 960x540 - PC, Wii
22795 		case 6:
22796 			videomodes.mode    = savedata.screen[videoMode][0];
22797 			videomodes.filter  = savedata.screen[videoMode][1];
22798 	        videomodes.hRes    = 960;
22799 			videomodes.vRes    = 540;
22800 			videomodes.hScale  = 3;
22801 			videomodes.vScale  = 2.25;
22802 			videomodes.hShift  = 320;
22803 			videomodes.vShift  = 40;
22804 			videomodes.dOffset = 522;
22805 			PLAYER_MIN_Z       = 362;
22806 			PLAYER_MAX_Z       = 524;
22807 			BGHEIGHT           = 362;
22808 			break;
22809 
22810 		default:
22811 			shutdown(1, "Invalid video mode: %d in 'data/video.txt', supported modes:\n"
22812 				        "0 - 320x240\n"
22813 						"1 - 480x272\n"
22814 						"2 - 640x480\n"
22815 						"3 - 720x480\n"
22816 						"4 - 800x480\n"
22817 						"5 - 800x600\n"
22818 						"6 - 960x540\n\n", videoMode);
22819 			break;
22820 	}
22821 
22822 #if SDL || WII
22823 	video_stretch(savedata.stretch);
22824 #endif
22825 
22826 	if((vscreen = allocscreen(videomodes.hRes, videomodes.vRes, screenformat)) == NULL) shutdown(1, "Not enough memory!\n");
22827 	videomodes.pixel = pixelbytes[(int)vscreen->pixelformat];
22828 	video_set_mode(videomodes);
22829 	clearscreen(vscreen);
22830 
22831 	if(log) printf("Initialized video.............\t%dx%d (Mode: %d, Depth: %d Bit)\n\n",videomodes.hRes, videomodes.vRes, videoMode, bits);
22832 }
22833 
22834 
22835 
22836 // ----------------------------------------------------------------------------
22837 
22838 
22839 // Set key or button safely (with switching)
safe_set(int * arr,int index,int newkey,int oldkey)22840 void safe_set(int *arr, int index, int newkey, int oldkey){
22841 	int i;
22842 	for(i=0; i<12; i++){
22843 		if(arr[i]==newkey) arr[i] = oldkey;
22844 	}
22845 	arr[index] = newkey;
22846 }
22847 
22848 
keyboard_setup(int player)22849 void keyboard_setup(int player){
22850 	int quit = 0,
22851 		selector = 0,
22852 		setting = -1,
22853 		i, k, ok = 0,
22854 		disabledkey[12] = {0,0,0,0,0,0,0,0,0,0,0,0},
22855 		col1 =-8, col2 = 6;
22856 	ptrdiff_t pos, voffset;
22857 	size_t size;
22858 	ArgList arglist;
22859 	char argbuf[MAX_ARG_LEN+1] = "";
22860 	char *buf, *command, *filename = "data/menu.txt",
22861 	     buttonnames[12][16];
22862 
22863 	printf("Loading control settings.......\t");
22864 
22865 	strncpy(buttonnames[0], "Move Up", 16);
22866 	strncpy(buttonnames[1], "Move Down", 16);
22867 	strncpy(buttonnames[2], "Move Left", 16);
22868 	strncpy(buttonnames[3], "Move Right", 16);
22869 	strncpy(buttonnames[4], "Attack 1", 16);
22870 	strncpy(buttonnames[5], "Attack 2", 16);
22871 	strncpy(buttonnames[6], "Attack 3", 16);
22872 	strncpy(buttonnames[7], "Attack 4", 16);
22873 	strncpy(buttonnames[8], "Jump", 16);
22874 	strncpy(buttonnames[9], "Special", 16);
22875 	strncpy(buttonnames[10], "Start", 16);
22876 	strncpy(buttonnames[11], "Screenshot", 16);
22877 
22878 	savesettings();
22879 	bothnewkeys = 0;
22880 
22881 	// Read file
22882 	if(buffer_pakfile(filename, &buf, &size)){
22883 		// Now interpret the contents of buf line by line
22884 		pos = 0;
22885 		while(pos<size){
22886 			ParseArgs(&arglist,buf+pos,argbuf);
22887 			command = GET_ARG(0);
22888 			if(command[0]){
22889 				if(stricmp(command, "disablekey")==0){
22890 
22891 					if(stricmp(GET_ARG(1), "moveup")==0)
22892 						disabledkey[0] = 1;
22893 					else if(stricmp(GET_ARG(1), "movedown")==0)
22894 						disabledkey[1] = 1;
22895 					else if(stricmp(GET_ARG(1), "moveleft")==0)
22896 						disabledkey[2] = 1;
22897 					else if(stricmp(GET_ARG(1), "moveright")==0)
22898 						disabledkey[3] = 1;
22899 					else if(stricmp(GET_ARG(1), "attack")==0)
22900 						disabledkey[4] = 1;
22901 					else if(stricmp(GET_ARG(1), "attack2") == 0)
22902 						disabledkey[5] = 1;
22903 					else if(stricmp(GET_ARG(1), "attack3") == 0)
22904 						disabledkey[6] = 1;
22905 					else if(stricmp(GET_ARG(1), "attack4") == 0)
22906 						disabledkey[7] = 1;
22907 					else if(stricmp(GET_ARG(1), "jump") == 0)
22908 						disabledkey[8] = 1;
22909 					else if(stricmp(GET_ARG(1), "special") == 0)
22910 						disabledkey[9] = 1;
22911 					else if(stricmp(GET_ARG(1), "start") == 0)
22912 						disabledkey[10] = 1;
22913 					else if(stricmp(GET_ARG(1), "screenshot") == 0)
22914 						disabledkey[11] = 1;
22915 				}
22916 				else if(stricmp(command, "renamekey")==0){
22917 					if(stricmp(GET_ARG(1), "moveup") == 0)
22918 						strncpy(buttonnames[0], GET_ARG(2), 16);
22919 					else if(stricmp(GET_ARG(1), "movedown") == 0)
22920 						strncpy(buttonnames[1], GET_ARG(2), 16);
22921 					else if(stricmp(GET_ARG(1), "moveleft") == 0)
22922 						strncpy(buttonnames[2], GET_ARG(2), 16);
22923 					else if(stricmp(GET_ARG(1), "moveright") == 0)
22924 						strncpy(buttonnames[3], GET_ARG(2), 16);
22925 					else if(stricmp(GET_ARG(1), "attack") == 0)
22926 						strncpy(buttonnames[4], GET_ARG(2), 16);
22927 					else if(stricmp(GET_ARG(1), "attack2") == 0)
22928 						strncpy(buttonnames[5], GET_ARG(2), 16);
22929 					else if(stricmp(GET_ARG(1), "attack3") == 0)
22930 						strncpy(buttonnames[6], GET_ARG(2), 16);
22931 					else if(stricmp(GET_ARG(1), "attack4") == 0)
22932 						strncpy(buttonnames[7], GET_ARG(2), 16);
22933 					else if(stricmp(GET_ARG(1), "jump") == 0)
22934 						strncpy(buttonnames[8], GET_ARG(2), 16);
22935 					else if(stricmp(GET_ARG(1), "special") == 0)
22936 						strncpy(buttonnames[9], GET_ARG(2), 16);
22937 					else if(stricmp(GET_ARG(1), "start") == 0)
22938 						strncpy(buttonnames[10], GET_ARG(2), 16);
22939 					else if(stricmp(GET_ARG(1), "screenshot") == 0)
22940 						strncpy(buttonnames[11], GET_ARG(2), 16);
22941 				}
22942 				else if(stricmp(command, "fontmonospace")==0){
22943 					 // here to keep from crashing
22944 				}
22945 				else if(stricmp(command, "fontmbs")==0){
22946 					 // here to keep from crashing
22947 				}
22948 				else
22949 					if(command && command[0])
22950 						printf("Command '%s' not understood in file '%s'!", command, filename);
22951 
22952 			}
22953 			// Go to next line
22954 			pos += getNewLineStart(buf + pos);
22955 		}
22956 		if(buf != NULL){
22957 			free(buf);
22958 			buf = NULL;
22959 		}
22960 	}
22961 
22962 	while(disabledkey[selector]) if(++selector>11) break;
22963 
22964 	while(!quit){
22965 		voffset = -6;
22966 		_menutextm(2, -8, 0, "Player %i", player+1);
22967 		for(i = 0; i < 12; i++){
22968 			  if(!disabledkey[i]){
22969 					_menutext((selector==i), col1, voffset, "%s", buttonnames[i]);
22970 					_menutext((selector==i), col2, voffset, "%s", control_getkeyname(savedata.keys[player][i]));
22971 					voffset++;
22972 			  }
22973 		}
22974 		_menutextm((selector==12), ++voffset, 0, "OK");
22975 		_menutextm((selector==13), ++voffset, 0, "Cancel");
22976 		update((level!=NULL),0);
22977 
22978 		if(setting > -1){
22979 			if(bothnewkeys & FLAG_ESC){
22980 				savedata.keys[player][setting] = ok;
22981 				sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 50);
22982 				setting = -1;
22983 			}
22984 			if(setting > -1){
22985 				k = control_scankey();
22986 				if(k){
22987 					safe_set(savedata.keys[player], setting, k, ok);
22988 					sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
22989 					setting = -1;
22990 					// Prevent accidental screenshot
22991 					bothnewkeys = 0;
22992 				}
22993 			}
22994 		}
22995 		else{
22996 			if(bothnewkeys & FLAG_ESC) quit = 1;
22997 			if(bothnewkeys & FLAG_MOVEUP){
22998 				do{ if(--selector<0) break; }while(disabledkey[selector]);
22999 				sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23000 			}
23001 			if(bothnewkeys & FLAG_MOVEDOWN){
23002 				do{ if(++selector>11) break; }while(disabledkey[selector]);
23003 				sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23004 			}
23005 			if(selector<0) selector = 13;
23006 			if(selector>13){
23007 				 selector = 0;
23008 				 while(disabledkey[selector]) if(++selector>11) break;
23009 			}
23010 			if(bothnewkeys & FLAG_ANYBUTTON){
23011 				sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
23012 				if(selector==12) quit = 2;
23013 				else if(selector==13) quit = 1;
23014 				else{
23015 					setting = selector;
23016 					ok = savedata.keys[player][setting];
23017 					savedata.keys[player][setting] = 0;
23018 #if DOS || SDL || PSP || WII
23019 					keyboard_getlastkey();
23020 #endif
23021 				}
23022 			}
23023 		}
23024 	}
23025 
23026 	if(quit==2){
23027 		apply_controls();
23028 		savesettings();
23029 	}
23030 	else loadsettings();
23031 
23032 
23033 	update(0,0);
23034 	bothnewkeys = 0;
23035 	printf("Done!\n");
23036 }
23037 
23038 
23039 #ifndef DISABLE_MOVIE
movie_options()23040 void movie_options(){
23041 	int quit = 0;
23042 	int selector = 1; // 0
23043 
23044 	bothnewkeys = 0;
23045 
23046 	while(!quit){
23047 		_menutextm(2, 1, 0, "Movie Mode");
23048 		_menutextm((selector==0), 2, 0, "Save Movie");
23049 		_menutextm((selector==1), 3, 0, "Load Movie");
23050 		_menutextm((selector==2), 5, 0, "Back");
23051 		update((level!=NULL),0);
23052 
23053 		if(bothnewkeys & FLAG_ESC) quit = 1;
23054 		if(bothnewkeys & FLAG_MOVEUP){
23055 			--selector;
23056 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23057 		}
23058 		if(bothnewkeys & FLAG_MOVEDOWN){
23059 			++selector;
23060 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23061 		}
23062 		if(selector<0) selector = 2;
23063 		if(selector>2) selector = 0;
23064 		if(bothnewkeys & FLAG_ANYBUTTON){
23065 
23066 			if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
23067 
23068 			switch(selector){
23069 				case 0:
23070 					movie_closefile(); //close first
23071 					movie_openfile(1); // save movie
23072 					quit = 1;
23073 					break;
23074 				case 1:
23075 					selector = 0;
23076 					movie_closefile(); //close first
23077 					movie_openfile(0); // play movie
23078 					quit = 1;
23079 					break;
23080 				default:
23081 					quit = (bothnewkeys & FLAG_ANYBUTTON);
23082 			}
23083 		}
23084 	}
23085 	savesettings();
23086 	bothnewkeys = 0;
23087 }
23088 #endif
23089 
23090 
23091 
input_options()23092 void input_options(){
23093 	int quit = 0;
23094 	int selector = 1; // 0
23095 
23096 	bothnewkeys = 0;
23097 
23098 	while(!quit){
23099 		_menutextm(2, -5, 0, "Control Options");
23100 
23101 #if PSP
23102 		if(savedata.usejoy) _menutext((selector==0), -4, -2, "Analog Pad Enabled");
23103 		else _menutext((selector==0), -4, -2, "Analog Pad Disabled");
23104 #elif WII
23105 		if(savedata.usejoy) _menutext((selector==0), -4, -2, "Nunchuk Analog Enabled");
23106 		else _menutext((selector==0), -4, -2, "Nunchuk Analog Disabled");
23107 #else
23108 		if(savedata.usejoy){
23109 			_menutext((selector==0),  -4, -2, "GamePads Enabled");
23110 			if(!control_getjoyenabled()){
23111 				_menutext((selector==0), 7, -2, " - Device Not Ready");
23112 			}
23113 		}
23114 		else _menutext((selector==0),  -4, -2, "GamePads Disabled");
23115 #endif
23116 
23117 		_menutext((selector==1), -4, -1, "Setup Player 1...");
23118 		_menutext((selector==2), -4, 0, "Setup Player 2...");
23119 		_menutext((selector==3), -4, 1, "Setup Player 3...");
23120 		_menutext((selector==4), -4, 2, "Setup Player 4...");
23121 		_menutextm((selector==5), 6, 0, "Back");
23122 		update((level!=NULL),0);
23123 
23124 		if(bothnewkeys & FLAG_ESC) quit = 1;
23125 		if(bothnewkeys & FLAG_MOVEUP){
23126 			--selector;
23127 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23128 		}
23129 		if(bothnewkeys & FLAG_MOVEDOWN){
23130 			++selector;
23131 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23132 		}
23133 		if(selector<0) selector = 5;
23134 		if(selector>5) selector = 0;
23135 		if(bothnewkeys & (FLAG_MOVELEFT|FLAG_MOVERIGHT|FLAG_ANYBUTTON)){
23136 
23137 			if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
23138 
23139 			switch(selector){
23140 				case 0:
23141 					control_usejoy((savedata.usejoy ^= 1));
23142 					break;
23143 				case 1:
23144 					keyboard_setup(0);
23145 					break;
23146 				case 2:
23147 					keyboard_setup(1);
23148 					break;
23149 				case 3:
23150 					keyboard_setup(2);
23151 					break;
23152 				case 4:
23153 					keyboard_setup(3);
23154 					break;
23155 				default:
23156 					quit = (bothnewkeys & FLAG_ANYBUTTON);
23157 			}
23158 		}
23159 	}
23160 	savesettings();
23161 	bothnewkeys = 0;
23162 }
23163 
23164 
23165 
sound_options()23166 void sound_options(){
23167 
23168 	int quit = 0;
23169 	int selector = 0;
23170 	int dir;
23171 	int col1 = -8;
23172 	int col2 = 6;
23173 
23174 	bothnewkeys = 0;
23175 
23176 	while(!quit){
23177 		_menutextm(2, -5, 0, "Sound Options");
23178 		_menutext((selector==0), col1, -2, "Sound Volume:");
23179 		_menutext((selector==0), col2, -2, "%i", savedata.soundvol);
23180 		_menutext((selector==1), col1, -1, "SFX Volume:");
23181 		_menutext((selector==1), col2, -1, "%i", savedata.effectvol);
23182 		_menutext((selector==2), col1, 0, "Music Volume:");
23183 		_menutext((selector==2), col2, 0, "%i", savedata.musicvol);
23184 		_menutext((selector==3), col1, 1, "BGM:");
23185 		_menutext((selector==3), col2, 1, "%s", (savedata.usemusic ? "Enabled" : "Disabled"));
23186 		_menutext((selector==4), col1, 2, "Show Titles:");
23187 		_menutext((selector==4), col2, 2, "%s", (savedata.showtitles ? "Yes" : "No"));
23188 		_menutext((selector==5), col1, 3, "Advanced Options...");
23189 		_menutextm((selector==6), 6, 0, "Back");
23190 
23191 		update((level!=NULL),0);
23192 
23193 		if(bothnewkeys & FLAG_ESC) quit = 1;
23194 		if(bothnewkeys & FLAG_MOVEUP){
23195 			--selector;
23196 
23197 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23198 		}
23199 		if(bothnewkeys & FLAG_MOVEDOWN){
23200 			++selector;
23201 
23202 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23203 		}
23204 		if(selector<0) selector = 6;
23205 		if(selector>6) selector = 0;
23206 
23207 		if(bothnewkeys & (FLAG_MOVELEFT|FLAG_MOVERIGHT|FLAG_ANYBUTTON)){
23208 			dir = 0;
23209 
23210 			if(bothnewkeys & FLAG_MOVELEFT) dir = -1;
23211 			else if(bothnewkeys & FLAG_MOVERIGHT) dir = 1;
23212 
23213 			if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
23214 
23215 			switch(selector){
23216 				case 0:
23217 					savedata.soundvol += dir;
23218 					if(savedata.soundvol < 0) savedata.soundvol = 0;
23219 					if(savedata.soundvol > 15) savedata.soundvol = 15;
23220 					SB_setvolume(SB_VOICEVOL, savedata.soundvol);
23221 					break;
23222 				case 1:
23223 					savedata.effectvol += 4*dir;
23224 					if(savedata.effectvol < 0) savedata.effectvol = 0;
23225 					if(savedata.effectvol > 512) savedata.effectvol = 512;
23226 					break;
23227 				case 3:
23228 					if(!dir) break;
23229 					if(!savedata.usemusic){
23230 						savedata.usemusic = 1;
23231 						music("data/music/remix", 1, 0);
23232 					}
23233 					else{
23234 						savedata.usemusic = 0;
23235 						sound_close_music();
23236 					}
23237 					break;
23238 				case 2:
23239 					savedata.musicvol += 4*dir;
23240 					if(savedata.musicvol < 0) savedata.musicvol = 0;
23241 					if(savedata.musicvol > 512) savedata.musicvol = 512;
23242 					sound_volume_music(savedata.musicvol, savedata.musicvol);
23243 					break;
23244 				case 4:
23245 					savedata.showtitles = !savedata.showtitles;
23246 					break;
23247 				case 5:
23248 					soundcard_options();
23249 					break;
23250 				default:
23251 					quit = 1;
23252 			}
23253 		}
23254 	}
23255 	savesettings();
23256 	bothnewkeys = 0;
23257 }
23258 
config_settings()23259 void config_settings(){    //  OX. Load from / save to default.cfg. Restore OpenBoR "factory" settings.
23260 	int quit = 0;
23261 	int selector = 0;
23262 	int saved = 0;
23263 	int loaded = 0;
23264 	int restored = 0;
23265 
23266 	bothnewkeys = 0;
23267 
23268 	while(!quit){
23269 		_menutextm(2, -5, 0, "Configuration Settings");
23270 
23271 		if(saved == 1) _menutextm((selector==0), -3, 0, "Save Settings To Default.cfg%s", "  Done!");
23272 		else _menutextm((selector==0), -3, 0, "Save Settings To Default.cfg%s","");
23273 
23274 		if(loaded == 1) _menutextm((selector==1), -2, 0, "Load Settings From Default.cfg%s", "  Done!");
23275 		else  _menutextm((selector==1), -2, 0, "Load Settings From Default.cfg%s", "");
23276 
23277 		if(restored == 1) _menutextm((selector==2), -1, 0, "Restore OpenBoR Defaults%s", "  Done!");
23278 		else _menutextm((selector==2), -1, 0, "Restore OpenBoR Defaults%s", "");
23279 
23280 		_menutextm((selector==3), 6, 0, "Back");
23281 
23282 		update((level!=NULL),0);
23283 
23284 		if(bothnewkeys & FLAG_ESC) quit = 1;
23285 		if(bothnewkeys & FLAG_MOVEUP){
23286 			--selector;
23287 
23288 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23289 		}
23290 		if(bothnewkeys & FLAG_MOVEDOWN){
23291 			++selector;
23292 
23293 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23294 		}
23295 
23296 		if(selector<0) selector = 3;
23297 		if(selector>3) selector = 0;
23298 
23299 		if(bothnewkeys & (FLAG_MOVELEFT|FLAG_MOVERIGHT|FLAG_ANYBUTTON)){
23300 
23301 			if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
23302 
23303 			switch(selector){
23304 				case 0:
23305 					saveasdefault();
23306 					saved = 1;
23307 					break;
23308 
23309 				case 1:
23310 					loadfromdefault();
23311 					//shutdown(2, "\nSettings Loaded From Default.cfg. Restart Required.\n\n");
23312 					init_videomodes(0);
23313 					SB_setvolume(SB_VOICEVOL, savedata.soundvol);
23314 					sound_volume_music(savedata.musicvol, savedata.musicvol);
23315 					loaded = 1;
23316 					break;
23317 				case 2:
23318 					clearsettings();
23319 					//shutdown(2, "\nSettings Loaded From Default.cfg. Restart Required.\n\n");
23320 					init_videomodes(0);
23321 					SB_setvolume(SB_VOICEVOL, savedata.soundvol);
23322 					sound_volume_music(savedata.musicvol, savedata.musicvol);
23323 					restored = 1;
23324 					break;
23325 				default:
23326 					quit = 1;
23327 			}
23328 		}
23329 	}
23330 	savesettings();
23331 	bothnewkeys = 0;
23332 }
23333 
23334 
cheatoptions()23335 void cheatoptions(){    //  LTB 1-13-05 took out sameplayer option
23336 	int quit = 0;
23337 	int selector = 0;
23338 	int dir;
23339 	int col1 = -8;
23340 	int col2 = 6;
23341 
23342 	bothnewkeys = 0;
23343 
23344 	while(!quit){
23345 		_menutextm(2, -5, 0, "Cheat Options");
23346 		_menutext((selector==0), col1, -3, "Brightness:");
23347 		_menutext((selector==0), col2, -3, "%i", savedata.brightness);
23348 		_menutext((selector==1), col1, -2, "Gamma:");
23349 		_menutext((selector==1), col2, -2, "%i", savedata.gamma);
23350 		_menutext((selector==2), col1, -1, "Control Options...");
23351 		_menutext((selector==3), col1, 0, "Sound Options...");
23352 		_menutext((selector==4), col1, 1, "System Options...");
23353 
23354 		if(livescheat)         _menutext((selector==5), col1, 2, "Infinite Lives On");
23355 		else if(!livescheat)   _menutext((selector==5), col1, 2, "Infinite Lives Off");
23356 		if(creditscheat)       _menutext((selector==6), col1, 3, "Infinite Credits On"); // Enemies fall down when you respawn
23357 		else if(!creditscheat) _menutext((selector==6), col1, 3, "Infinite Credits Off");//Enemies don't fall down when you respawn
23358 		if(healthcheat)        _menutext((selector==7), col1, 4, "Infinite Health On"); // Enemies fall down when you respawn
23359 		else if(!healthcheat)  _menutext((selector==7), col1, 4, "Infinite Health Off");//Enemies don't fall down when you respawn
23360 
23361 		_menutextm((selector==8), 6, 0, "Back");
23362 
23363 		update((level!=NULL),0);
23364 
23365 		if(bothnewkeys & FLAG_ESC) quit = 1;
23366 		if(bothnewkeys & FLAG_MOVEUP){
23367 			--selector;
23368 
23369 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23370 		}
23371 		if(bothnewkeys & FLAG_MOVEDOWN){
23372 			++selector;
23373 
23374 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23375 		}
23376 
23377 		if(selector<0) selector = 8;  // 7-1-2005 //13-1-2005 changed to 11
23378 		if(selector>8) selector = 0;//    7-1-2005 6 changed to 10 //13-1-2005 changed to 11
23379 
23380 		if(bothnewkeys & (FLAG_MOVELEFT|FLAG_MOVERIGHT|FLAG_ANYBUTTON)){
23381 			dir = 0;
23382 
23383 			if(bothnewkeys & FLAG_MOVELEFT) dir = -1;
23384 			else if(bothnewkeys & FLAG_MOVERIGHT) dir = 1;
23385 
23386 			if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
23387 
23388 			switch(selector){
23389 				case 0:
23390 					savedata.brightness += 8*dir;
23391 					if(savedata.brightness < -256) savedata.brightness = -256;
23392 					if(savedata.brightness > 256) savedata.brightness = 256;
23393 					vga_vwait();
23394 					palette_set_corrected(pal, savedata.gamma,savedata.gamma,savedata.gamma, savedata.brightness,savedata.brightness,savedata.brightness);
23395 					break;
23396 				case 1:
23397 					savedata.gamma += 8*dir;
23398 					if(savedata.gamma < -256) savedata.gamma = -256;
23399 					if(savedata.gamma > 256) savedata.gamma = 256;
23400 					vga_vwait();
23401 					palette_set_corrected(pal, savedata.gamma,savedata.gamma,savedata.gamma, savedata.brightness,savedata.brightness,savedata.brightness);
23402 					break;
23403 				case 2:
23404 					input_options();
23405 					break;
23406 				case 3:
23407 					sound_options();
23408 					break;
23409 				case 4:
23410 					system_options();
23411 					break;
23412 				case 5:
23413 					if(!livescheat) livescheat = 1;
23414 					else if(livescheat) livescheat = 0;
23415 					break;
23416 				case 6:
23417 					if(!creditscheat) creditscheat = 1;
23418 					else if(creditscheat) creditscheat = 0;
23419 					break;
23420 				case 7:
23421 					if(!healthcheat) healthcheat = 1;
23422 					else if(healthcheat) healthcheat = 0;
23423 					break;
23424 
23425 				default:
23426 					quit = 1;
23427 			}
23428 		}
23429 	}
23430 	savesettings();
23431 	bothnewkeys = 0;
23432 }
23433 
23434 
system_options()23435 void system_options(){
23436 
23437 	int quit = 0;
23438 	int selector = 0;
23439 	int ret = 6;
23440 	int col1 = -8;
23441 	int col2 = 5;
23442 
23443 #if PSP
23444     int dir = 0;
23445 	int batteryPercentage = 0;
23446 	int batteryLifeTime = 0;
23447 	int externalPower = 0;
23448 #endif
23449 
23450 	bothnewkeys = 0;
23451 
23452 	while(!quit){
23453 		_menutextm(2, -6, 0, "System Options");
23454 
23455 		_menutext(0, col1, -4, "Total RAM:");
23456 		_menutext(0, col2, -4, "%s KBytes", commaprint(getSystemRam(KBYTES)));
23457 
23458 		_menutext(0, col1, -3, "Used RAM:");
23459 		_menutext(0, col2, -3, "%s KBytes", commaprint(getUsedRam(KBYTES)));
23460 
23461 		_menutext((selector==0), col1, -2, "Debug Info:");
23462 		_menutext((selector==0), col2, -2, (savedata.debuginfo ? "Enabled" : "Disabled"));
23463 
23464 		_menutext((selector==1), col1, -1, "File Logging:");
23465 		_menutext((selector==1), col2, -1, (savedata.uselog ? "Enabled" : "Disabled"));
23466 
23467 		_menutext((selector==2), col1, 0, "Players: ");
23468 		_menutext((selector==2), col2, 0, "%i by Mod", levelsets[current_set].maxplayers);
23469 
23470 		_menutext((selector==3), col1, 1, "Versus Damage:", 0);
23471 		if(versusdamage == 0) _menutext((selector==3), col2, 1, "Disabled by Mod");
23472 		else if(versusdamage == 1) _menutext((selector==3), col2, 1, "Enabled by Mod");
23473 		else
23474 		{
23475 			if(savedata.mode) _menutext((selector==3), col2, 1, "Disabled");//Mode 1 - Players CAN'T attack each other
23476 			else _menutext((selector==3), col2, 1, "Enabled");//Mode 2 - Players CAN attack each other
23477 		}
23478 
23479 		_menutext((selector==4), col1, 2, "Cheats:");
23480 		_menutext((selector==4), col2, 2, forcecheatsoff?"Disabled by Mod":(cheats?"On":"Off"));
23481 
23482 #ifndef DC
23483 
23484 		_menutext((selector==5), col1, 3, "Config Settings");
23485 
23486 #endif
23487 
23488 #if PSP
23489 		externalPower = scePowerIsPowerOnline();
23490 		_menutext((selector==6), col1, 4, "CPU Speed:");
23491 		_menutext((selector==6), col2, 4, "%d MHz", scePowerGetCpuClockFrequency());
23492 		if(!externalPower){
23493 			batteryPercentage = scePowerGetBatteryLifePercent();
23494 			batteryLifeTime = scePowerGetBatteryLifeTime();
23495 			_menutext(0, col1, 5, "Battery:");
23496 			if(batteryPercentage < 0 || batteryLifeTime < 0) _menutext(0, col2, 5, "Calculating...");
23497 			else _menutext(0, col2, 5, "%d%% - %02d:%02d", batteryPercentage, batteryLifeTime/60,batteryLifeTime-(batteryLifeTime/60*60));
23498 		}
23499 		else{
23500 			_menutext(0, col1, 5, "Charging:");
23501 			_menutext(0, col2, 5, "%d%% AC Power", scePowerGetBatteryLifePercent());
23502 		}
23503 		ret = 7;
23504 #endif
23505 
23506 		_menutextm((selector==ret), 6, 0, "Back");
23507 
23508 		update((level!=NULL),0);
23509 
23510 		if(bothnewkeys & FLAG_ESC) quit = 1;
23511 		if(bothnewkeys & FLAG_MOVEUP){
23512 			--selector;
23513 			sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23514 		}
23515 		if(bothnewkeys & FLAG_MOVEDOWN){
23516 			++selector;
23517 			sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23518 		}
23519 
23520 		if(selector < 0) selector = ret;
23521 		if(selector > ret) selector = 0;
23522 
23523 		if(bothnewkeys & (FLAG_MOVELEFT|FLAG_MOVERIGHT|FLAG_ANYBUTTON)){
23524 
23525 #if PSP
23526 			dir = 0;
23527 			if(bothnewkeys & FLAG_MOVELEFT) dir = -1;
23528 			else if(bothnewkeys & FLAG_MOVERIGHT) dir = 1;
23529 #endif
23530 
23531 			sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
23532 
23533 			switch(selector){
23534 				case 0:
23535 					savedata.debuginfo = !savedata.debuginfo;
23536 					break;
23537 
23538 				case 1:
23539 					savedata.uselog =  !savedata.uselog;
23540 					break;
23541 
23542 				case 2:
23543 
23544 					break;
23545 
23546 				case 3:
23547 					if(versusdamage > 1)
23548 					{
23549 						if(savedata.mode) savedata.mode = 0;
23550 						else              savedata.mode = 1;
23551 					}
23552 					break;
23553 
23554 				case 4:
23555 					cheats = !cheats;
23556 					break;
23557 
23558 #ifndef DC
23559 
23560 				case 5:
23561 					config_settings();
23562 					break;
23563 
23564 #endif
23565 
23566 #ifdef PSP
23567 				case 6:
23568 					savedata.pspcpuspeed += dir;
23569 					if(savedata.pspcpuspeed<0) savedata.pspcpuspeed = 2;
23570 					if(savedata.pspcpuspeed>2) savedata.pspcpuspeed = 0;
23571 					switch(savedata.pspcpuspeed){
23572 				case 0:
23573 					scePowerSetClockFrequency(222, 222, 111);
23574 					break;
23575 				case 1:
23576 					scePowerSetClockFrequency(266, 266, 133);
23577 					break;
23578 				case 2:
23579 					scePowerSetClockFrequency(333, 333, 166);
23580 					break;
23581 					}
23582 					break;
23583 #endif
23584 
23585 				default:
23586 					quit = 1;
23587 					break;
23588 			}
23589 		}
23590 	}
23591 	savesettings();
23592 	bothnewkeys = 0;
23593 }
23594 
23595 
video_options()23596 void video_options(){
23597 	int quit = 0;
23598 	int selector = 0;
23599 	int dir;
23600 	int col1 = -8, col2 = 6;
23601 
23602 	bothnewkeys = 0;
23603 
23604 	while(!quit){
23605 		_menutextm(2, -5, 0, "Video Options");
23606 		_menutext((selector==0), col1, -3, "Brightness:");
23607 		_menutext((selector==0), col2, -3, "%i", savedata.brightness);
23608 		_menutext((selector==1), col1, -2, "Gamma:");
23609 		_menutext((selector==1), col2, -2, "%i", savedata.gamma);
23610 		_menutext((selector==2), col1, -1, "Window Offset:");
23611 		_menutext((selector==2), col2, -1, "%i", savedata.windowpos);
23612 
23613 #if DOS || DC || GP2X || DINGOO
23614 		_menutextm((selector==3), 6, 0, "Back");
23615 		if(selector<0) selector = 3;
23616 		if(selector>3) selector = 0;
23617 #endif
23618 
23619 #if XBOX
23620 		_menutext((selector==3), col1, 0, "Screen Size:");
23621 		_menutext((selector==3), col2, 0, "Guide R/L Thumbsticks");
23622 		_menutext((selector==3), col1, 1, "GFX Filters:");
23623 		_menutext((selector==3), col2, 1, "Press R/L Thumbsticks");
23624 		_menutextm((selector==4), 6, 0, "Back");
23625 		if(selector<0) selector = 4;
23626 		if(selector>4) selector = 0;
23627 #endif
23628 
23629 #if WII
23630 		_menutext((selector==3), col1, 0, "Display Mode:");
23631 		_menutext((selector==3), col2, 0, savedata.fullscreen ? "Stretch to Screen" : "Preserve Aspect Ratio");
23632 		_menutextm((selector==4), 6, 0, "Back");
23633 		if(selector<0) selector = 4;
23634 		if(selector>4) selector = 0;
23635 #endif
23636 
23637 #if SDL
23638 #ifndef GP2X
23639 		_menutext((selector==3), col1, 0, "Display Mode:");
23640 		_menutext((selector==3), col2, 0, "%s", savedata.fullscreen ? "Full" : "Window");
23641 
23642 		_menutext((selector==4), col1, 1, "Video Backend:");
23643 		_menutext((selector==4), col2, 1, "%s", opengl ? "OpenGL" : "SDL");
23644 
23645 		if(opengl)
23646 		{
23647 			_menutext((selector==5), col1, 2, "Screen:");
23648 			if(savedata.fullscreen) _menutext((selector==5), col2, 2, "Automatic");
23649 			else _menutext((selector==5), col2, 2, "%4.2fx - %ix%i", savedata.glscale, (int)(videomodes.hRes*savedata.glscale), (int)(videomodes.vRes*savedata.glscale));
23650 
23651 			_menutext((selector==6), col1, 3, "Filters:");
23652 			_menutext((selector==6), col2, 3, "%s", savedata.glscale!=1.0 ? (savedata.glfilter[savedata.fullscreen] ? "Simple" : "Bilinear") : "Disabled");
23653 		}
23654 		else
23655 		{
23656 			_menutext((selector==5), col1, 2, "Screen:");
23657 			if(savedata.screen[videoMode][0]) _menutext((selector==3), col2, 2, "%ix - %ix%i", savedata.screen[videoMode][0], videomodes.hRes*savedata.screen[videoMode][0], videomodes.vRes*savedata.screen[videoMode][0]);
23658 			else _menutext((selector==5), col2, 2, "Disabled");
23659 
23660 			_menutext((selector==6), col1, 3, "Filters:");
23661 			_menutext((selector==6), col2, 3, "%s", savedata.screen[videoMode][0]==2 ? GfxBlitterNames[(int)savedata.screen[videoMode][1]] : "Disabled");
23662 		}
23663 
23664 		if(savedata.fullscreen)
23665 		{
23666 			_menutext((selector==7), col1, 4, "Fullscreen Type:");
23667 			_menutext((selector==7), col2, 4, "%s", savedata.stretch ? "Stretch to Screen" : "Preserve Aspect Ratio");
23668 		} else if(selector==7) selector = (bothnewkeys & FLAG_MOVEUP) ? 6 : 8;
23669 
23670 		_menutextm((selector==8), 6, 0, "Back");
23671 		if(selector<0) selector = 8;
23672 		if(selector>8) selector = 0;
23673 #endif
23674 #endif
23675 
23676 #if PSP
23677 		_menutext((selector==3), col1, 0, "Screen:");
23678 		_menutext((selector==3), col2, 0, "%s", displayFormat[(int)videomodes.mode].name);
23679 		_menutext((selector==4), col1, 1, "Filters:");
23680 		_menutext((selector==4), col2, 1, "%s", filterName[(int)videomodes.filter]);
23681 		_menutext((selector==5), col1, 2, "Display:");
23682 		_menutext((selector==5), col2, 2, "%s", displayName[displayMode]);
23683 		_menutext((selector>=6 && selector<=9), col1, 3, "Overscan:");
23684 		_menutext((selector>=6 && selector<=9), col2+1.5, 3, ".");
23685 		_menutext((selector>=6 && selector<=9), col2+3.5, 3, ".");
23686 		_menutext((selector>=6 && selector<=9), col2+5.5, 3, ".");
23687 		_menutext((selector==6), col2, 3, "%02d", savedata.overscan[0]);
23688 		_menutext((selector==7), col2+2, 3, "%02d", savedata.overscan[1]);
23689 		_menutext((selector==8), col2+4, 3, "%02d", savedata.overscan[2]);
23690 		_menutext((selector==9), col2+6, 3, "%02d", savedata.overscan[3]);
23691 		_menutextm((selector==10), 6, 0, "Back");
23692 		if(selector<0) selector = 10;
23693 		if(selector>10) selector = 0;
23694 #endif
23695 
23696 		update((level!=NULL),0);
23697 
23698 		if(bothnewkeys & FLAG_ESC) quit = 1;
23699 		if(bothnewkeys & FLAG_MOVEUP){
23700 			--selector;
23701 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23702 		}
23703 		if(bothnewkeys & FLAG_MOVEDOWN){
23704 			++selector;
23705 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23706 		}
23707 		if(bothnewkeys & (FLAG_MOVELEFT|FLAG_MOVERIGHT|FLAG_ANYBUTTON)){
23708 			dir = 0;
23709 
23710 			if(bothnewkeys & FLAG_MOVELEFT) dir = -1;
23711 			else if(bothnewkeys & FLAG_MOVERIGHT) dir = 1;
23712 
23713 			if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
23714 
23715 			switch(selector){
23716 				case 0:
23717 					savedata.brightness += 8*dir;
23718 					if(savedata.brightness < -256) savedata.brightness = -256;
23719 					if(savedata.brightness > 256) savedata.brightness = 256;
23720 					vga_vwait();
23721 					set_color_correction(savedata.gamma, savedata.brightness);
23722 					break;
23723 				case 1:
23724 					savedata.gamma += 8*dir;
23725 					if(savedata.gamma < -256) savedata.gamma = -256;
23726 					if(savedata.gamma > 256) savedata.gamma = 256;
23727 					vga_vwait();
23728 					set_color_correction(savedata.gamma, savedata.brightness);
23729 					break;
23730 				case 2:
23731 					savedata.windowpos += dir;
23732 					if(savedata.windowpos < -2) savedata.windowpos = -2;
23733 					if(savedata.windowpos > 20) savedata.windowpos = 20;
23734 					break;
23735 #if SDL || PSP || XBOX || WII
23736 				case 3:
23737 #if XBOX
23738 					update((level!=NULL),0);
23739 					xbox_resize();
23740 #endif
23741 
23742 #if WII
23743 					//video_fullscreen_flip();
23744 					video_stretch((savedata.stretch ^= 1));
23745 					break;
23746 #endif
23747 
23748 #if PSP
23749 					if(videoMode == 0)
23750 					{   // 320x240
23751 						videomodes.mode += dir;
23752 						if(videomodes.mode > PSP_DISPLAY_FORMATS - 1) videomodes.mode = 0;
23753 						if(videomodes.mode < 0) videomodes.mode = PSP_DISPLAY_FORMATS - 1;
23754 						savedata.screen[videoMode][0] = videomodes.mode;
23755 						video_set_mode(videomodes);
23756 					}
23757 					break;
23758 
23759 				case 4:
23760 					if(videoMode == 0)
23761 					{   // 320x240
23762 						videomodes.filter += dir;
23763 						if(videomodes.filter > PSP_DISPLAY_FILTERS - 1) videomodes.filter = 0;
23764 						if(videomodes.filter < 0) videomodes.filter = PSP_DISPLAY_FILTERS - 1;
23765 						savedata.screen[videoMode][1] = videomodes.filter;
23766 						video_set_mode(videomodes);
23767 					}
23768 					break;
23769 
23770 				case 5:
23771 					displayMode += dir;
23772 					if(displayMode > PSP_DISPLAY_MODES - 1) displayMode = 0;
23773 					if(displayMode < 0) displayMode = PSP_DISPLAY_MODES - 1;
23774 					if(displayMode)
23775 						setGraphicsTVOverScan(savedata.overscan[0], savedata.overscan[1], savedata.overscan[2], savedata.overscan[3]);
23776 					else
23777 						setGraphicsTVOverScan(0, 0, 0, 0);
23778 					savedata.usetv = displayMode;
23779 					disableGraphics();
23780 					initGraphics(savedata.usetv, videomodes.pixel);
23781 					video_set_mode(videomodes);
23782 					break;
23783 				case 6:
23784 				case 7:
23785 				case 8:
23786 				case 9:
23787 					savedata.overscan[selector-8] += dir;
23788 					if(savedata.overscan[selector-8] > 99) savedata.overscan[selector-8] = 0;
23789 					if(savedata.overscan[selector-8] < 0) savedata.overscan[selector-8] = 99;
23790 					if(displayMode)
23791 					{
23792 						setGraphicsTVOverScan(savedata.overscan[0], savedata.overscan[1], savedata.overscan[2], savedata.overscan[3]);
23793 						video_set_mode(videomodes);
23794 					}
23795 					break;
23796 #endif
23797 #endif
23798 
23799 
23800 #if SDL
23801 #ifndef GP2X
23802 					video_fullscreen_flip();
23803 					break;
23804 				case 4:
23805 					savedata.usegl[savedata.fullscreen] ^= 1;
23806 					video_set_mode(videomodes);
23807 					set_color_correction(savedata.gamma, savedata.brightness);
23808 					break;
23809 				case 5:
23810 					if(opengl)
23811 					{
23812 						if(savedata.fullscreen) break;
23813 						savedata.glscale += dir * 0.25;
23814 						if(savedata.glscale < 0.25) savedata.glscale = 0.25;
23815 						if(savedata.glscale > 4.00) savedata.glscale = 4.00;
23816 						video_set_mode(videomodes);
23817 					}
23818 					else
23819 					{
23820 	    				videomodes.mode += dir * 2;
23821 #ifdef WII
23822 					    // Wii with SDL is limited to 640x480
23823 						if(videomodes.mode > 2) videomodes.mode = 0;
23824 					    if(videomodes.mode < 0) videomodes.mode = 2;
23825 #else
23826 						if(videomodes.mode > 4) videomodes.mode = 0;
23827 					    if(videomodes.mode < 0) videomodes.mode = 4;
23828 #endif
23829 					    savedata.screen[videoMode][0] = videomodes.mode;
23830 						video_set_mode(videomodes);
23831 						change_system_palette(current_palette);
23832 					}
23833 					break;
23834 				case 6:
23835 					if(opengl)
23836 					{
23837 						if(savedata.glscale == 1.0) break;
23838 						savedata.glfilter[savedata.fullscreen] += dir;
23839 						if(savedata.glfilter[savedata.fullscreen] < 0) savedata.glfilter[savedata.fullscreen] = 1;
23840 						if(savedata.glfilter[savedata.fullscreen] > 1) savedata.glfilter[savedata.fullscreen] = 0;
23841 					}
23842 					else
23843 					{
23844 						if(videomodes.mode!=2) break;
23845 						videomodes.filter += dir;
23846 						if(videomodes.filter > BLITTER_MAX - 1) videomodes.filter = 0;
23847 					    if(videomodes.filter < 0) videomodes.filter = BLITTER_MAX - 1;
23848 						savedata.screen[videoMode][1] = videomodes.filter;
23849 					}
23850 					break;
23851 				case 7:
23852 					video_stretch((savedata.stretch ^= 1));
23853 					break;
23854 #endif
23855 #endif
23856 				default:
23857 					quit = 1;
23858 			}
23859 		}
23860 	}
23861 	savesettings();
23862 	bothnewkeys = 0;
23863 }
23864 
23865 
options()23866 void options(){
23867 	int quit = 0;
23868 	int selector = 0;
23869 
23870 	bothnewkeys = 0;
23871 
23872 	while(!quit){
23873 		_menutextm(2, -1, 0, "Options");
23874 		_menutextm((selector==0), 1, 0, "Video Options...");
23875 		_menutextm((selector==1), 2, 0, "Sound Options...");
23876 		_menutextm((selector==2), 3, 0, "Control Options...");
23877 		_menutextm((selector==3), 4, 0, "System Options...");
23878 		_menutextm((selector==4), 6, 0, "Back");
23879 
23880 		if(selector<0) selector = 4;
23881 		if(selector>4) selector = 0;
23882 
23883 		update((level!=NULL),0);
23884 
23885 		if(bothnewkeys & FLAG_ESC) quit = 1;
23886 		if(bothnewkeys & FLAG_MOVEUP){
23887 			--selector;
23888 
23889 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23890 		}
23891 		if(bothnewkeys & FLAG_MOVEDOWN){
23892 			++selector;
23893 
23894 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23895 		}
23896 		if(bothnewkeys & (FLAG_MOVELEFT|FLAG_MOVERIGHT|FLAG_ANYBUTTON)){
23897 
23898 			if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
23899 
23900 			switch(selector){
23901 				case 0:
23902 					video_options();
23903 					break;
23904 				case 1:
23905 					sound_options();
23906 					break;
23907 				case 2:
23908 					input_options();
23909 					break;
23910 				case 3:
23911 					system_options();
23912 					break;
23913 				default:
23914 					quit = 1;
23915 			}
23916 		}
23917 	}
23918 	savesettings();
23919 	if(pause==1) pause=2;
23920 	bothnewkeys = 0;
23921 }
23922 
soundcard_options()23923 void soundcard_options(){
23924 	int quit = 0;
23925 	int selector = 0;
23926 	int col1=-8, col2=6;
23927 
23928 	savesettings();
23929 
23930 	bothnewkeys = 0;
23931 
23932 	while(!quit){
23933 		_menutextm(2, -5, 0, "Advanced Sound Options");
23934 		_menutext((selector==0), col1, -2, "Frequency:");
23935 		_menutext((selector==0), col2, -2, "%i", savedata.soundrate);
23936 		_menutext((selector==1), col1, -1, "Bits:");
23937 		_menutext((selector==1), col2, -1, "%i", savedata.soundbits);
23938 		_menutextm((selector==2), 1, 0, "Apply");
23939 		_menutextm((selector==3), 2, 0, "Discard");
23940 		_menutextm((selector==4), 7, 0, "Back");
23941 		update((level!=NULL),0);
23942 
23943 		if(bothnewkeys & FLAG_ESC) quit = 1;
23944 		if(bothnewkeys & FLAG_MOVEUP){
23945 			--selector;
23946 			sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23947 		}
23948 		if(bothnewkeys & FLAG_MOVEDOWN){
23949 			++selector;
23950 			sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23951 		}
23952 		if(selector<0) selector = 4;
23953 		selector %= 5;
23954 		if(bothnewkeys & (FLAG_MOVELEFT|FLAG_MOVERIGHT|FLAG_ANYBUTTON)){
23955 			sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
23956 			switch(selector){
23957 				case 0:
23958 					if(bothnewkeys & FLAG_MOVELEFT) savedata.soundrate >>= 1;
23959 					if(bothnewkeys & FLAG_MOVERIGHT) savedata.soundrate <<= 1;
23960 					if(savedata.soundrate < 11025) savedata.soundrate = 44100;
23961 					if(savedata.soundrate > 44100) savedata.soundrate = 11025;
23962 					break;
23963 				case 1:
23964 					savedata.soundbits = (savedata.soundbits ^ (8+16));
23965 					if(savedata.soundbits!=8 && savedata.soundbits!=16) savedata.soundbits = 8;
23966 					break;
23967 				case 2:
23968 					if(!(bothnewkeys & FLAG_ANYBUTTON)) break;
23969 					// Apply new hardware settings
23970 					sound_stop_playback();
23971 					if(!sound_start_playback(savedata.soundbits, savedata.soundrate)){
23972 						savedata.soundbits = 8;
23973 						savedata.soundrate = 11025;
23974 						sound_start_playback(savedata.soundbits, savedata.soundrate);
23975 					}
23976 					music("data/music/remix", 1, 0);
23977 					savesettings();
23978 					break;
23979 				case 3:
23980 					if(bothnewkeys & FLAG_ANYBUTTON) loadsettings();
23981 					break;
23982 				default:
23983 					quit = (bothnewkeys & FLAG_ANYBUTTON);
23984 			}
23985 		}
23986 	}
23987 	loadsettings();
23988 	bothnewkeys = 0;
23989 }
23990 
23991 #ifdef XBOX
display_logfile()23992 void display_logfile()
23993 {
23994 	int i, j, k;
23995 	stringptr *logfile = NULL;
23996 	char textpad[128] = {""};
23997 	int currentline = 0;
23998 	int filesize = 0;
23999 	int done = 0;
24000 
24001 	logfile = readFromLogFile(OPENBOR_LOG);
24002 	if(logfile != NULL)
24003 	{
24004 		unload_background();
24005 		load_background("menu/logview", 0);
24006 		while(!done)
24007 		{
24008 			font_printf(5,3, 1, 0, "Log Viewer");
24009 			font_printf(259,3, 1, 0, "Quit : Escape");
24010 			filesize = logfile->size;
24011 			if(bothkeys & FLAG_MOVEUP)
24012 			{
24013 				currentline -= 5;
24014 				if(currentline < 0) currentline = 0;
24015 			}
24016 			if(bothkeys & FLAG_MOVEDOWN)
24017 			{
24018 				currentline += 5;
24019 				if(currentline > filesize) currentline = filesize;
24020 			}
24021 			k = 0;
24022 			j = 2;
24023 			for(i=currentline; i<filesize; i++)
24024 			{
24025 				if(logfile->ptr[i] >= 0x20 && logfile->ptr[i] <= 0x7e)
24026 				{
24027 					textpad[k] = logfile->ptr[i];
24028 					k++;
24029 				}
24030 				else if(logfile->ptr[i] == 0x09)
24031 				{
24032 					textpad[k+0] = ' '; textpad[k+1] = ' ';
24033 					textpad[k+2] = ' '; textpad[k+3] = ' ';
24034 					k+=4;
24035 				}
24036 				else
24037 				{
24038 					font_printf(5, j*10, 0, 0, "%s", textpad);
24039 					j++;
24040 					k=0;
24041 					strncpy(textpad, "", 128);
24042 				}
24043 			}
24044 			if(bothkeys & FLAG_ESC) done = 1;
24045 			update((level!=NULL),0);
24046 		}
24047 		free_string(logfile);
24048 		logfile = NULL;
24049 		unload_background();
24050 		load_background("menu/logo", 0);
24051 	}
24052 }
24053 #endif
24054 
24055 // ----------------------------------------------------------------------------
24056 
24057 
openborMain(int argc,char ** argv)24058 void openborMain(int argc, char** argv)
24059 {
24060 	sprite_map = NULL;
24061 	int quit = 0;
24062 	int relback = 1;
24063 	int selector = 0;
24064 	u32 introtime = 0;
24065 	int started = 0;
24066 	char tmpBuff[128] = {""};
24067 	int players[MAX_PLAYERS] = {0,0,0,0};
24068 	int i;
24069 	int argl;
24070 
24071 #if XBOX
24072 	int done = 0;
24073 	char pakname[128] = {""};
24074 	char listing[32] = {""};
24075 	int paks = 0;
24076 	int list = 0;
24077 	int lOffset=0;
24078 	u32 menutime = 0;
24079 #endif
24080 
24081 	printf("OpenBoR %s, Compile Date: " __DATE__ "\n\n", VERSION);
24082 
24083 	if(argc > 1) {
24084 		argl = strlen(argv[1]);
24085 		if(argl > 14 && !memcmp(argv[1], "offscreenkill=", 14))
24086 			DEFAULT_OFFSCREEN_KILL = getValidInt((char*)argv[1] + 14,"","");
24087 		if(argl > 14 && !memcmp(argv[1], "showfilesused=", 14))
24088 			printFileUsageStatistics = getValidInt((char*)argv[1] + 14,"","");
24089 	}
24090 
24091 	modelcmdlist = createModelCommandList();
24092 	modelstxtcmdlist = createModelstxtCommandList();
24093 	levelcmdlist = createLevelCommandList();
24094 	levelordercmdlist = createLevelOrderCommandList();
24095 	createModelList();
24096 
24097 
24098 #ifdef XBOX
24099 	loadsettings();
24100 	paks = findmods();
24101 	if(paks==1) getBasePath(packfile, paklist[0].filename, 1);
24102 	else
24103 	{
24104 		strcpy(packfile, "d:\\Paks\\menu.pak");
24105 		guistartup();
24106 		load_background("menu/logo", 0);
24107 		while(!done)
24108 		{
24109 			if(paks < 1) font_printf(10,24, 1, 0, "No Mods In Paks Folder!");
24110 			if(bothnewkeys & FLAG_ESC)
24111 			{
24112 				disablelog = 1;
24113 				shutdown(1, "");
24114 			}
24115 
24116 			for(list=0; list<paks; list++)
24117 			{
24118 				strncpy(pakname, paklist[list+lOffset].filename,128-strlen(paklist[list+lOffset].filename));
24119 				if(list<18)
24120 				{
24121 					strncpy(listing, "", 32);
24122 					strncpy(listing, pakname, 31);
24123 					font_printf(10,24+(11*list), selector==list, 0, "%s", listing);
24124 				}
24125 			}
24126 			if(bothkeys & FLAG_MOVEUP && time >= menutime)
24127 			{
24128 				--selector;
24129 
24130 				menutime = time + GAME_SPEED/8;
24131 			}
24132 			if(bothkeys & FLAG_MOVEDOWN && time >= menutime)
24133 			{
24134 				++selector;
24135 				menutime = time + GAME_SPEED/8;
24136 			}
24137 #ifndef DC
24138 			if(bothkeys & FLAG_SPECIAL) display_logfile();
24139 #endif
24140 			if(selector>paks-1) selector=paks-1;
24141 			if(selector>17)
24142 			{
24143 				if((selector+lOffset)<paks) lOffset++;
24144 				selector=17;
24145 			}
24146 			if(selector<0)
24147 			{
24148 				selector=0;
24149 				if(lOffset>0) lOffset--;
24150 			}
24151 			if((bothnewkeys&(FLAG_START)) && paks > 1)
24152 			{
24153 				strncpy(pakname, paklist[selector+lOffset].filename,128-strlen(paklist[selector+lOffset].filename));
24154 				getBasePath(packfile, pakname, 1);
24155 				done = 1;
24156 			}
24157 
24158 			font_printf(5,3, 2, 0, "OpenBoR %s", VERSION);
24159 			font_printf(265,3, 2, 0, __DATE__);
24160 			font_printf(197,155, 2, 0, "www.LavaLit.com");
24161 			font_printf(190,165, 2, 0, "www.SenileTeam.com");
24162 			font_printf(5,229, 2, 0, "Start : Load");
24163 			font_printf(259,229, 2, 0, "Quit : Escape");
24164 
24165 			if(done) font_printf(215,175, 2, 0, "Loading...");
24166 			update(0,0);
24167 		}
24168 
24169 		if(paks != 1)
24170 		{
24171 			// unload whats been allocated.
24172 			selector = 0;
24173 			unload_background();
24174 			freescreen(vscreen);
24175 			unload_all_fonts();
24176 			borTimerExit();
24177 			control_exit();
24178 		}
24179 	}
24180 #endif
24181 
24182 	// Load necessary components.
24183 	printf("Game Selected: %s\n\n", packfile);
24184 	loadsettings();
24185 	startup();
24186 
24187 	if(skiptoset<0)
24188 	{
24189 
24190 		// New alternative background path for PSP
24191 		if(custBkgrds != NULL)
24192 		{
24193 			strcpy(tmpBuff,custBkgrds);
24194 			strncat(tmpBuff,"logo", 4);
24195 			load_background(tmpBuff, 0);
24196 		}
24197 		else {
24198 			printf("use cached bg\n");
24199 			load_cached_background("data/bgs/logo", 0);
24200 		}
24201 
24202 		while(time<GAME_SPEED*6 && !(bothnewkeys&(FLAG_ANYBUTTON|FLAG_ESC))) update(0,0);
24203 
24204 		music("data/music/remix", 1, 0);
24205 
24206 		// New alternative scene path for PSP
24207 		if(custScenes != NULL)
24208 		{
24209 			strncpy(tmpBuff,custScenes, 128);
24210 			strncat(tmpBuff,"logo.txt", 8);
24211 			playscene(tmpBuff);
24212 		}
24213 		else playscene("data/scenes/logo.txt");
24214 	}
24215 	clearscreen(background);
24216 
24217 	while(!quit)
24218 	{
24219 		if(skiptoset<0)
24220 		{
24221 			if(time >= introtime)
24222 			{
24223 				// New alternative scene path for PSP
24224 				if(custScenes != NULL)
24225 				{
24226 					strncpy(tmpBuff,custScenes, 128);
24227 					strncat(tmpBuff,"intro.txt", 9);
24228 					playscene(tmpBuff);
24229 				}
24230 				else playscene("data/scenes/intro.txt");
24231 				update(0,0);
24232 				introtime = time + GAME_SPEED * 20;
24233 				relback = 1;
24234 				started = 0;
24235 			}
24236 
24237 			if(bothnewkeys & FLAG_ESC) quit = 1;
24238 		}
24239 		else
24240 		{
24241 			started = 1;
24242 			relback = 0;
24243 		}
24244 
24245 		if(!started)
24246 		{
24247 			if((time%GAME_SPEED) < (GAME_SPEED/2)) _menutextm(0, 0, 0, "PRESS START");
24248 			if(bothnewkeys&(FLAG_ANYBUTTON))
24249 			{
24250 				started = 1;
24251 				relback = 1;
24252 			}
24253 		}
24254 		else if(skiptoset>=0)
24255 		{
24256 			loadGameFile();
24257 			playgame(players, skiptoset, useSave);
24258 		}
24259 		else
24260 		{
24261 			_menutextm((selector==0), 2, 0, "Start Game");
24262 			_menutextm((selector==1), 3, 0, "Options");
24263 			_menutextm((selector==2), 4, 0, "How To Play");
24264 			_menutextm((selector==3), 5, 0, "Hall Of Fame");
24265 			_menutextm((selector==4), 6, 0, "Quit");
24266 			if(selector<0) selector = 4;
24267 			if(selector>4) selector = 0;
24268 
24269 			if(bothnewkeys) introtime = time + GAME_SPEED * 20;
24270 
24271 			if(bothnewkeys & FLAG_MOVEUP)
24272 			{
24273 				--selector;
24274 				if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
24275 			}
24276 			if(bothnewkeys & FLAG_MOVEDOWN)
24277 			{
24278 				++selector;
24279 				if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
24280 			}
24281 			if(bothnewkeys&(FLAG_ANYBUTTON))
24282 			{
24283 				if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
24284 				switch(selector)
24285 				{
24286 				case 0:
24287 					for(i=0; i<MAX_PLAYERS; i++) players[i] = player[i].newkeys & (FLAG_ANYBUTTON);
24288 					relback = choose_mode(players);
24289 					if(relback) started = 0;
24290 					break;
24291 				case 1:
24292 					if(!cheats) options();
24293 					else
24294 					{
24295 						if(!forcecheatsoff) cheatoptions();
24296 						else options();
24297 					}
24298 					break;
24299 				case 2: {
24300 					int previousLoop = musicloop;
24301 					char previousMusic[sizeof(currentmusic)];
24302 					strncpy(previousMusic, currentmusic, sizeof(previousMusic)-1);
24303 
24304 					if(custScenes != NULL)
24305 					{
24306 						strncpy(tmpBuff,custScenes, 128);
24307 						strncat(tmpBuff,"howto.txt", 9);
24308 						playscene(tmpBuff);
24309 					}
24310 					else playscene("data/scenes/howto.txt");
24311 					if(stricmp(previousMusic, currentmusic) != 0)
24312 						music(previousMusic, previousLoop, 0);
24313 					relback = 1;
24314 					break;
24315 				}
24316 				case 3:
24317 					hallfame(0);
24318 					relback = 1;
24319 					break;
24320 				default:
24321 					quit = 1;
24322 					break;
24323 				}
24324 				introtime = time + GAME_SPEED * 20;
24325 			}
24326 		}
24327 		if(relback)
24328 		{
24329 			if(started)
24330 			{
24331 				menuScreen  = 1;
24332 				titleScreen = 0;
24333 				if(custBkgrds != NULL)
24334 				{
24335 					strncpy(tmpBuff,custBkgrds, 128);
24336 					strncat(tmpBuff,"titleb", 6);
24337 					load_background(tmpBuff, 0);
24338 				}
24339 				else load_cached_background("data/bgs/titleb", 0);
24340 			}
24341 			else
24342 			{
24343 				menuScreen  = 0;
24344 				titleScreen = 1;
24345 				if(custBkgrds != NULL)
24346 				{
24347 					strncpy(tmpBuff,custBkgrds, 128);
24348 					strncat(tmpBuff,"title", 5);
24349 					load_background(tmpBuff, 0);
24350 				}
24351 				else load_cached_background("data/bgs/title", 0);
24352 			}
24353 
24354 			if(!sound_query_music(NULL,NULL)) music("data/music/remix", 1, 0);
24355 			relback = 0;
24356 		}
24357 		update(0,0);
24358 	}
24359 	shutdown(0, DEFAULT_SHUTDOWN_MESSAGE);
24360 }
24361 
24362 #undef GET_ARG
24363 #undef GET_ARG_LEN
24364 #undef GET_ARGP
24365 #undef GET_ARGP_LEN
24366 #undef GET_INT_ARG
24367 #undef GET_FLOAT_ARG
24368 #undef GET_INT_ARGP
24369 #undef GET_FLOAT_ARGP
24370