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 static const char* E_OUT_OF_MEMORY = "Error: Could not allocate sufficient memory.\n";
28 static int DEFAULT_OFFSCREEN_KILL = 3000;
29 
30 #define MIN_INT (int)0x80000000
31 #define MAX_INT	(int)0x7fffffff
32 
33 /////////////////////////////////////////////////////////////////////////////
34 //  Global Variables                                                        //
35 /////////////////////////////////////////////////////////////////////////////
36 
37 s_level_entry*      levelorder[MAX_DIFFICULTIES][MAX_LEVELS];
38 s_level*            level               = NULL;
39 s_screen*           vscreen             = NULL;
40 s_screen*           background          = NULL;
41 s_screen*			zoombuffer			= NULL;
42 s_screen*           bgbuffer            = NULL;
43 int					zoom_center_x		= 0;
44 int					zoom_center_y		= 0;
45 int					zoom_scale_x		= 0;
46 int					zoom_scale_y		= 0;
47 int					zoom_z				= MIN_INT;
48 char                bgbuffer_updated    = 0;
49 s_videomodes        videomodes;
50 int sprite_map_max_items = 0;
51 int cache_map_max_items = 0;
52 
53 
54 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.
55 List* modelcmdlist = NULL;
56 List* modelstxtcmdlist = NULL;
57 List* levelcmdlist = NULL;
58 List* levelordercmdlist = NULL;
59 
60 
61 //see types.h
62 const s_drawmethod plainmethod = {
63 	NULL, // table
64 	NULL, //fp
65 	0,    // fillcolor
66 	1,    //flag
67 	-1,   // alpha
68 	-1,   // remap
69 	0,    //flipx
70 	0,    //flipy
71 	0,    //transbg
72 	0,    //fliprotate
73 	0,    //rotate
74 	256,  //scalex
75 	256,  //scaley
76 	0,    //shiftx
77 	0,    //centerx  //currently used only by gfxshadow, do not touch it
78 	0,    //centery
79 	{{.beginsize=0.0}, {.endsize=0.0}, 0, {.wavespeed=0}, 0} //water
80 };
81 
82 
83 // unknockdown attack
84 const s_attack emptyattack = {
85 	0,  // force
86    -1,  // sound
87    -1,  // flash
88    -1,  // blockflash
89    -1,  // blocksound
90 	0,  // counter
91    {0,
92 	0,
93 	0,
94 	0,
95 	0}, // coods
96 	0,  // nopain/noreflect
97 	0,
98 	0,  // noflash
99 	0,  // noblock
100 	0,  // grab
101 	0,  // dir
102 	0,  // blast
103 	0,  // freeze
104 	0,  // steal
105 	0,  // map
106 	0,  // seal
107 	0,  // freezetime
108 	0,  // maptime
109 	0,  // sealtime
110 	0,  // dot
111 	0,  // dot index
112 	0,  // dot_time
113 	0,  // dot_force
114 	0,  // dot_rate
115 	{0,	0,	0}, // dropv
116 	0,  // otg
117 	0,  // jugglecost
118 	0,  // Guardcost
119 	0,  // drop
120 	0,  // type
121 	0,  // damage on landing
122 	0,  // grabdist
123 	0,  // pause
124 };
125 
126 char                *custScenes = NULL;
127 char                *custBkgrds = NULL;
128 char                *custLevels = NULL;
129 char                *custModels = NULL;
130 char                rush_names[2][MAX_NAME_LEN];
131 char                branch_name[MAX_NAME_LEN+1];    // Used for branches
132 char                set_names[MAX_DIFFICULTIES][MAX_NAME_LEN+1];
133 unsigned char       pal[MAX_PAL_SIZE] = {""};
134 int                 blendfx[MAX_BLENDINGS] = {0,1,0,0,0,0};
135 char                blendfx_is_set = 0;
136 int                 fontmonospace[8] = {0,0,0,0,0,0,0,0};
137 
138 // move all blending effects here
139 unsigned char*      blendings[MAX_BLENDINGS] = {NULL, NULL, NULL, NULL, NULL, NULL} ;
140 // function pointers to create the tables
141 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};
142 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};
143 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};
144 
145 int                 current_set = 0;
146 int                 current_level = 0;
147 int                 current_stage = 1;
148 int					new_game = 0;
149 
150 float               bgtravelled;
151 int                 traveltime;
152 int                 texttime;
153 float               advancex;
154 float               advancey;
155 
156 float               scrolldx;                       // advancex changed previous loop
157 float               scrolldy;                       // advancey .....................
158 float               scrollminz;                     // Limit level z-scroll
159 float               scrollmaxz;
160 float               blockade;                       // Limit x scroll back
161 float               lasthitx;						//Last hit X location.
162 float               lasthitz;						//Last hit Z location.
163 float               lasthita;						//Last hit A location.
164 int                 lasthitt;                       //Last hit type.
165 int                 lasthitc;                       //Last hit confirm (i.e. if engine hit code will be used).
166 
167 int					combodelay = GAME_SPEED/2;		// avoid annoying 112112... infinite combo
168 
169 // used by gfx shadow
170 int                 light[2] = {0, 0};
171 int                 shadowcolor = 0;
172 int                 shadowalpha = BLEND_MULTIPLY+1;
173 
174 u64 totalram = 0;
175 u64 usedram = 0;
176 u64 freeram = 0;
177 u32 interval = 0;
178 extern unsigned long seed;
179 
180 int                 SAMPLE_GO			= -1;
181 int                 SAMPLE_BEAT			= -1;
182 int                 SAMPLE_BLOCK		= -1;
183 int                 SAMPLE_INDIRECT		= -1;
184 int                 SAMPLE_GET			= -1;
185 int                 SAMPLE_GET2			= -1;
186 int                 SAMPLE_FALL			= -1;
187 int                 SAMPLE_JUMP			= -1;
188 int                 SAMPLE_PUNCH		= -1;
189 int                 SAMPLE_1UP			= -1;
190 int                 SAMPLE_TIMEOVER		= -1;
191 int                 SAMPLE_BEEP			= -1;
192 int                 SAMPLE_BEEP2		= -1;
193 int                 SAMPLE_BIKE			= -1;
194 
195 int                 max_downs           = MAX_DOWNS;
196 int                 max_ups             = MAX_UPS;
197 int                 max_backwalks       = MAX_BACKWALKS;
198 int                 max_walks           = MAX_WALKS;
199 int                 max_idles           = MAX_IDLES;
200 int                 max_attack_types    = MAX_ATKS;
201 int                 max_freespecials    = MAX_SPECIALS;
202 int                 max_follows         = MAX_FOLLOWS;
203 int                 max_attacks         = MAX_ATTACKS;
204 int                 max_animations      = MAX_ANIS;
205 
206 // -------dynamic animation indexes-------
207 int*                animdowns           = NULL;
208 int*                animups             = NULL;
209 int*                animbackwalks       = NULL;
210 int*                animwalks           = NULL;
211 int*                animidles           = NULL;
212 int*                animpains           = NULL;
213 int*                animdies            = NULL;
214 int*                animfalls           = NULL;
215 int*                animrises           = NULL;
216 int*                animriseattacks     = NULL;
217 int*                animblkpains        = NULL;
218 int*                animattacks         = NULL;
219 int*                animfollows         = NULL;
220 int*                animspecials        = NULL;
221 
222 // system default values
223 int                 downs[MAX_DOWNS]        = {ANI_DOWN};
224 int                 ups[MAX_UPS]            = {ANI_UP};
225 int                 backwalks[MAX_BACKWALKS]= {ANI_BACKWALK};
226 int                 walks[MAX_WALKS]        = {ANI_WALK};
227 int                 idles[MAX_IDLES]        = {ANI_IDLE};
228 
229 int                 falls[MAX_ATKS] = {
230 						ANI_FALL,  ANI_FALL2, ANI_FALL3, ANI_FALL4,
231 						ANI_FALL,  ANI_BURN,  ANI_FALL,  ANI_SHOCK,
232 						ANI_FALL,  ANI_FALL5, ANI_FALL6, ANI_FALL7,
233 						ANI_FALL8, ANI_FALL9, ANI_FALL10
234 					};
235 
236 int                 rises[MAX_ATKS] = {
237 						ANI_RISE,  ANI_RISE2, ANI_RISE3, ANI_RISE4,
238 						ANI_RISE,  ANI_RISEB,  ANI_RISE,  ANI_RISES,
239 						ANI_RISE,  ANI_RISE5, ANI_RISE6, ANI_RISE7,
240 						ANI_RISE8, ANI_RISE9, ANI_RISE10
241 					};
242 
243 int                 riseattacks[MAX_ATKS] = {
244 						ANI_RISEATTACK,  ANI_RISEATTACK2, ANI_RISEATTACK3, ANI_RISEATTACK4,
245 						ANI_RISEATTACK,  ANI_RISEATTACKB,  ANI_RISEATTACK,  ANI_RISEATTACKS,
246 						ANI_RISEATTACK,  ANI_RISEATTACK5, ANI_RISEATTACK6, ANI_RISEATTACK7,
247 						ANI_RISEATTACK8, ANI_RISEATTACK9, ANI_RISEATTACK10
248 					};
249 
250 int                 pains[MAX_ATKS] = {
251 						ANI_PAIN,  ANI_PAIN2,    ANI_PAIN3, ANI_PAIN4,
252 						ANI_PAIN,  ANI_BURNPAIN, ANI_PAIN,  ANI_SHOCKPAIN,
253 						ANI_PAIN,  ANI_PAIN5,    ANI_PAIN6, ANI_PAIN7,
254 						ANI_PAIN8, ANI_PAIN9,    ANI_PAIN10
255 					};
256 
257 int                 deaths[MAX_ATKS] = {
258 						ANI_DIE,   ANI_DIE2,     ANI_DIE3,  ANI_DIE4,
259 						ANI_DIE,   ANI_BURNDIE,  ANI_DIE,   ANI_SHOCKDIE,
260 						ANI_DIE,   ANI_DIE5,     ANI_DIE6,  ANI_DIE7,
261 						ANI_DIE8,  ANI_DIE9,     ANI_DIE10
262 					};
263 
264 int                 blkpains[MAX_ATKS] = {
265 						ANI_BLOCKPAIN,  ANI_BLOCKPAIN2,    ANI_BLOCKPAIN3, ANI_BLOCKPAIN4,
266 						ANI_BLOCKPAIN,  ANI_BLOCKPAINB, ANI_BLOCKPAIN,  ANI_BLOCKPAINS,
267 						ANI_BLOCKPAIN,  ANI_BLOCKPAIN5,    ANI_BLOCKPAIN6, ANI_BLOCKPAIN7,
268 						ANI_BLOCKPAIN8, ANI_BLOCKPAIN9,    ANI_BLOCKPAIN10
269 					};
270 
271 int                 normal_attacks[MAX_ATTACKS] = {
272 						ANI_ATTACK1, ANI_ATTACK2, ANI_ATTACK3, ANI_ATTACK4
273 					};
274 
275 int                 grab_attacks[5][2] = {
276 						{ANI_GRABATTACK, ANI_GRABATTACK2},
277 						{ANI_GRABFORWARD, ANI_GRABFORWARD2},
278 						{ANI_GRABUP, ANI_GRABUP2},
279 						{ANI_GRABDOWN, ANI_GRABDOWN2},
280 						{ANI_GRABBACKWARD, ANI_GRABBACKWARD2}
281 					};
282 
283 int                 freespecials[MAX_SPECIALS] = {
284 						ANI_FREESPECIAL,   ANI_FREESPECIAL2,  ANI_FREESPECIAL3,
285 						ANI_FREESPECIAL4,  ANI_FREESPECIAL5,  ANI_FREESPECIAL6,
286 						ANI_FREESPECIAL7,  ANI_FREESPECIAL8
287 					};
288 
289 int                 follows[MAX_FOLLOWS] = {
290 						ANI_FOLLOW1, ANI_FOLLOW2, ANI_FOLLOW3, ANI_FOLLOW4
291 					};
292 
293 #ifndef DISABLE_MOVIE
294 #define DISABLE_MOVIE
295 #endif
296 
297 //movie log stuffs
298 #ifndef DISABLE_MOVIE
299 #define MOVIEBUF_LEN 2048
300 int movielog = 0;
301 int movieplay = 0;
302 int moviebufptr = 0;
303 int movielen = 0;
304 int movieloglen = 0;
305 FILE* moviefile = NULL;
306 u32 (*moviebuffer)[5][2] = NULL; //keyflags, newkeyflags;
307 #endif
308 
309 // background cache to speed up in-game menus
310 #if WII
311 s_screen*           bg_cache[MAX_CACHED_BACKGROUNDS] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
312 unsigned char		bg_palette_cache[MAX_CACHED_BACKGROUNDS][MAX_PAL_SIZE];
313 #endif
314 
315 int                 maxplayers[MAX_DIFFICULTIES] = {2,2,2,2,2,2,2,2,2,2};
316 int                 ctrlmaxplayers[MAX_DIFFICULTIES] = {0,0,0,0,0,0,0,0,0,0};
317 unsigned int        num_levels[MAX_DIFFICULTIES];
318 unsigned int        ifcomplete[MAX_DIFFICULTIES];
319 unsigned int        num_difficulties;
320 unsigned int        noshowhof[MAX_DIFFICULTIES];
321 unsigned int        difflives[MAX_DIFFICULTIES];				// What too easy?  change the # of lives players get
322 unsigned int        custfade[MAX_DIFFICULTIES];
323 unsigned int        diffcreds[MAX_DIFFICULTIES];				// What still to easy - lets see how they do without continues!
324 unsigned int        diffoverlap[MAX_DIFFICULTIES];				// Music overlap
325 unsigned int        typemp[MAX_DIFFICULTIES];
326 unsigned int        continuescore[MAX_DIFFICULTIES];             //what to do with score if continue is used.
327 char*               (*skipselect)[MAX_DIFFICULTIES][MAX_PLAYERS] = NULL;              // skips select screen and automatically gives players models specified
328 int                 cansave_flag[MAX_DIFFICULTIES];             // 0, no save, 1 save level position 2 save all: lives/credits/hp/mp/also player
329 
330 int                 cameratype          = 0;
331 
332 u32                 go_time             = 0;
333 u32                 time                = 0;
334 u32                 newtime             = 0;
335 unsigned char       slowmotion[3]       = {0,2,0};              // [0] = enable/disable; [1] = duration; [2] = counter;
336 int                 disablelog          = 0;
337 int                 currentspawnplayer  = 0;
338 int                 PLAYER_MIN_Z        = 160;
339 int                 PLAYER_MAX_Z        = 232;
340 int                 BGHEIGHT            = 160;
341 int                 MAX_WALL_HEIGHT     = 1000;					// Max wall height that an entity can be spawned on
342 int                 saveslot            = 0;
343 int                 current_palette     = 0;
344 int                 fade                = 24;
345 int                 credits             = 0;
346 int                 gosound             = 0;					// Used to prevent go sound playing too frequently,
347 int                 musicoverlap        = 0;
348 int                 colorbars           = 0;
349 int                 current_spawn       = 0;
350 int                 level_completed     = 0;
351 int                 nojoin              = 0;					// dont allow new hero to join in, use "Please Wait" instead of "Select Hero"
352 int                 groupmin            = 0;
353 int					groupmax            = 0;
354 int                 selectScreen        = 0;					// Flag to determine if at select screen (used for setting animations)
355 int					titleScreen			= 0;
356 int					menuScreen			= 0;
357 int					hallOfFame			= 0;
358 int					gameOver			= 0;
359 int					showComplete		= 0;
360 char*				currentScene		= NULL;
361 int                 tospeedup           = 0;          			// If set will speed the level back up after a boss hits the ground
362 int                 reached[4]          = {0,0,0,0};			// Used with TYPE_ENDLEVEL to determine which players have reached the point //4player
363 int                 noslowfx			= 0;           			// Flag to determine if sound speed when hitting opponent slows or not
364 int                 equalairpause 		= 0;         			// If set to 1, there will be no extra pausetime for players who hit multiple enemies in midair
365 int                 hiscorebg			= 0;					// If set to 1, will look for a background image to display at the highscore screen
366 int                 completebg			= 0;           			// If set to 1, will look for a background image to display at the showcomplete screen
367 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
368 int					loadingmusic        = 0;
369 int                 unlockbg            = 0;         			// If set to 1, will look for a different background image after defeating the game
370 int                 pause               = 0;
371 int                 nopause             = 0;                    // OX. If set to 1 , pausing the game will be disabled.
372 int                 noscreenshot        = 0;                    // OX. If set to 1 , taking screenshots is disabled.
373 int                 endgame             = 0;
374 int                 forcecheatsoff      = 0;
375 int                 cheats              = 0;
376 int                 livescheat          = 0;
377 int                 keyscriptrate       = 0;
378 int                 creditscheat        = 0;
379 int                 healthcheat         = 0;
380 int                 showtimeover        = 0;
381 int                 sameplayer          = 0;            		// 7-1-2005  flag to determine if players can use the same character
382 int                 PLAYER_LIVES        = 3;					// 7-1-2005  default setting for Lives
383 int                 CONTINUES           = 5;					// 7-1-2005  default setting for continues
384 int                 colourselect		= 0;					// 6-2-2005 Colour select is optional
385 int                 autoland			= 0;					// Default set to no autoland and landing is valid with u j combo
386 int                 ajspecial			= 0;					// Flag to determine if holding down attack and pressing jump executes special
387 int                 nolost				= 0;					// variable to control if drop weapon when grab a enemy by tails
388 int                 nocost				= 0;					// If set, special will not cost life unless an enemy is hit
389 int                 mpstrict			= 0;					// If current system will check all animation's energy cost when set new animations
390 int                 magic_type			= 0;					// use for restore mp by time by tails
391 entity*             textbox				= NULL;
392 entity*             smartbomber			= NULL;
393 entity*				stalker				= NULL;					// an enemy (usually) tries to go behind the player
394 entity*				firstplayer			= NULL;
395 int					stalking			= 0;
396 int					nextplan			= 0;
397 int                 plife[4][2]         = {{0,0},{0,0},{0,0},{0,0}};// Used for customizable player lifebar
398 int                 plifeX[4][3]        = {{0,0,-1},{0,0,-1},{0,0,-1},{0,0,-1}};// Used for customizable player lifebar 'x'
399 int                 plifeN[4][3]        = {{0,0,-1},{0,0,-1},{0,0,-1},{0,0,-1}};// Used for customizable player lifebar number of lives
400 int                 picon[4][2]         = {{0,0},{0,0},{0,0},{0,0}};// Used for customizable player icon
401 int                 piconw[4][2]        = {{0,0},{0,0},{0,0},{0,0}};// Used for customizable player weapon icons
402 int                 mpicon[4][2]        = {{0,0},{0,0},{0,0},{0,0}};// Used for customizable magicbar player icon
403 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
404 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
405 int                 pshoot[4][3]        = {{0,0,-1},{0,0,-1},{0,0,-1},{0,0,-1}};// Used for customizable player shootnum
406 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
407 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
408 int                 mpcolourtable[11]   = {0,0,0,0,0,0,0,0,0,0,0};
409 int                 hpcolourtable[11]   = {0,0,0,0,0,0,0,0,0,0,0};
410 int                 ldcolourtable[11]   = {0,0,0,0,0,0,0,0,0,0,0};
411 char                musicname[128]      = {""};
412 float               musicfade[2]        = {0,0};
413 int                 musicloop           = 0;
414 u32                 musicoffset         = 0;
415 int					alwaysupdate		= 0; //execute update/updated scripts whenever it has a chance
416 
417 s_barstatus         loadingbarstatus =
418 {
419 	0,                          //int          offsetx:16;
420 	0,                          //int          offsety:16;
421 	0,                          //int          sizex:16;
422 	10,                          //int          sizey:16;
423 	percentagebar,                   //bartype      type:8;
424 	horizontalbar,              //barorient    orientation:8;
425 	0,                          //int          noborder:8;
426 	0,                          //int          direction:8;
427 	0,                          //int          barlayer;
428 	0,                          //int          backlayer;
429 	0,                          //int          borderlayer;
430 	0,                          //int          shadowlayer;
431 	&ldcolourtable
432 };
433 s_barstatus         lbarstatus =                                // Used for customizable lifebar size
434 {
435 	0,                          //int          offsetx:16;
436 	0,                          //int          offsety:16;
437 	0,                          //int          sizex:16;
438 	0,                          //int          sizey:16;
439 	valuebar,                   //bartype      type:8;
440 	horizontalbar,              //barorient    orientation:8;
441 	0,                          //int          noborder:8;
442 	0,                          //int          direction:8;
443 	0,                          //int          barlayer;
444 	0,                          //int          backlayer;
445 	0,                          //int          borderlayer;
446 	0,                          //int          shadowlayer;
447 	&hpcolourtable
448 };
449 s_barstatus         olbarstatus =                               // Used for customizable opponent lifebar size
450 {
451 	0,                          //int          offsetx:16;
452 	0,                          //int          offsety:16;
453 	0,                          //int          sizex:16;
454 	0,                          //int          sizey:16;
455 	valuebar,                   //bartype      type:8;
456 	horizontalbar,              //barorient    orientation:8;
457 	0,                          //int          noborder:8;
458 	0,                          //int          direction:8;
459 	0,                          //int          barlayer;
460 	0,                          //int          backlayer;
461 	0,                          //int          borderlayer;
462 	0,                          //int          shadowlayer;
463 	&hpcolourtable
464 };
465 int                 timeloc[6]			= {0,0,0,0,0,-1};		// Used for customizable timeclock location/size
466 int                 timeicon			= -1;
467 short               timeicon_offsets[2] = {0,0};
468 char                timeicon_path[128]  = {""};
469 int                 bgicon   			= -1;
470 short               bgicon_offsets[3]	= {0,0,0};
471 char                bgicon_path[128]    = {""};
472 int                 olicon    			= -1;
473 short               olicon_offsets[3]	= {0,0,0};
474 char                olicon_path[128]    = {""};
475 int                 elife[4][2]         = {{0,0},{0,0},{0,0},{0,0}};// Used for customizable enemy lifebar
476 int                 ename[4][3]         = {{0,0,-1},{0,0,-1},{0,0,-1},{0,0,-1}};// Used for customizable enemy name
477 int                 eicon[4][2]         = {{0,0},{0,0},{0,0},{0,0}};// Used for customizable enemy icon
478 int                 scomplete[6]		= {0,0,0,0,0,0};		// Used for customizable Stage # Complete
479 int                 cbonus[10]          = {0,0,0,0,0,0,0,0,0,0};// Used for customizable clear bonus
480 int                 lbonus[10]          = {0,0,0,0,0,0,0,0,0,0};// Used for customizable life bonus
481 int                 rbonus[10]          = {0,0,0,0,0,0,0,0,0,0};// Used for customizable rush bonus
482 int                 tscore[10]          = {0,0,0,0,0,0,0,0,0,0};// Used for customizable total score
483 int                 scbonuses[4]        = {10000, 1000, 100, 0};//Stage complete bonus multipliers
484 int                 showrushbonus       = 0;
485 int                 noshare				= 0;					// Used for when you want to keep p1 & p2 credits separate
486 int                 nodropen			= 0;					// Drop or not when spawning is now a modder option
487 int					nodropspawn			= 0;					// don't spawn from the sky if the modder doesn't set it
488 int                 gfx_x_offset		= 0;                    //2011_04_03, DC: Enable X offset adjustment by modders.
489 int                 gfx_y_offset		= 0;
490 int                 gfx_y_offset_adj    = 0;                    //2011_04_03, DC: Enable Y offset adjustment by modders.
491 int                 timeleft			= 0;
492 int                 oldtime             = 0;                    // One second back from time left.
493 int                 holez				= 0;					// Used for setting spawn points
494 int                 allow_secret_chars	= 0;
495 unsigned int        lifescore			= 50000;				// Number of points needed to earn a 1-up
496 unsigned int        credscore			= 0;					// Number of points needed to earn a credit
497 int                 mpblock				= 0;					// Take chip damage from health or MP first?
498 int                 blockratio			= 0;					// Take half-damage while blocking?
499 int                 nochipdeath			= 0;					// Prevents entities from dying due to chip damage (damage while blocking)
500 int                 noaircancel         = 0;					// Now, you can make jumping attacks uncancellable!
501 int                 nomaxrushreset[5]   = {0,0,0,0,0};
502 s_barstatus         mpbarstatus =                               // Used for customizable lifebar size
503 {
504 	0,                          //int          offsetx:16;
505 	0,                          //int          offsety:16;
506 	0,                          //int          sizex:16;
507 	0,                          //int          sizey:16;
508 	valuebar,                   //bartype      type:8;
509 	horizontalbar,              //barorient    orientation:8;
510 	0,                          //int          noborder:8;
511 	0,                          //int          direction:8;
512 	0,                          //int          barlayer;
513 	0,                          //int          backlayer;
514 	0,                          //int          borderlayer;
515 	0,                          //int          shadowlayer;
516 	&mpcolourtable
517 };
518 int			        mpbartext[4]		= {-1,0,0,0};			// Array for adjusting MP status text (font, Xpos, Ypos, Display type).
519 int			        lbartext[4]			= {-1,0,0,0};			// Array for adjusting HP status text (font, Xpos, Ypos, Display type).
520 int                 pmp[4][2]			= {{0,0},{0,0},{0,0},{0,0}};// Used for customizable player mpbar
521 int                 spdirection[4]		= {1,0,1,0};			// Used for Select Player Direction for select player screen
522 int                 bonus				= 0;					// Used for unlocking Bonus difficulties
523 int                 versusdamage		= 2;					// Used for setting mode. (ability to hit other players)
524 int                 same[MAX_DIFFICULTIES];						// ltb 1-13-05   sameplayer
525 int                 z_coords[3]			= {0,0,0};				// Used for setting customizable walkable area
526 int                 rush[6]				= {0,2,3,3,3,3};
527 int                 color_black			= 0;
528 int                 color_red			= 0;
529 int                 color_orange		= 0;
530 int                 color_yellow		= 0;
531 int                 color_white			= 0;
532 int                 color_blue			= 0;
533 int                 color_green			= 0;
534 int                 color_pink			= 0;
535 int                 color_purple		= 0;
536 int                 color_magic			= 0;
537 int                 color_magic2		= 0;
538 int                 lifebarfgalpha      = 0;
539 int                 lifebarbgalpha      = 2;
540 int                 shadowsprites[6]	= {-1,-1,-1,-1,-1,-1};
541 int                 gosprite			= -1;
542 int                 golsprite			= -1;
543 int                 holesprite			= -1;
544 int                 videoMode			= 0;
545 int                 scoreformat			= 0;					// If set fill score values with 6 Zeros
546 
547 // Funny neon lights
548 unsigned char       neontable[MAX_PAL_SIZE];
549 unsigned int        neon_time			= 0;
550 
551 s_panel             panels[MAX_PANELS];
552 unsigned int        panels_loaded		= 0;
553 int                 panel_width			= 0;
554 int                 panel_height		= 0;
555 
556 s_sprite*           frontpanels[MAX_PANELS];
557 unsigned int        frontpanels_loaded	= 0;
558 
559 unsigned int        sprites_loaded		= 0;
560 unsigned int        anims_loaded		= 0;
561 
562 unsigned int        models_loaded		= 0;
563 unsigned int        models_cached		= 0;
564 
565 entity*             ent_list[MAX_ENTS];
566 entity*             self;
567 int                 ent_count			= 0;					// log count of entites
568 int                 ent_max				= 0;
569 
570 s_player            player[4];
571 u32                 bothkeys, bothnewkeys;
572 
573 s_playercontrols    playercontrols1;
574 s_playercontrols    playercontrols2;
575 s_playercontrols    playercontrols3;
576 s_playercontrols    playercontrols4;
577 s_playercontrols*   playercontrolpointers[] = {&playercontrols1, &playercontrols2, &playercontrols3, &playercontrols4};
578 
579 
580 //global script
581 Script level_script;    //execute when level start
582 Script endlevel_script; //execute when level finished
583 Script update_script;   //execute when ingame update
584 Script updated_script;  //execute when ingame update finished
585 Script loading_script;	// in loading screen
586 Script key_script_all;  //keyscript for all players
587 Script timetick_script; //time tick script.
588 
589 //player script
590 Script score_script[4];     //execute when add score, 4 players
591 Script key_script[4];       //key listeners, lol
592 Script join_script[4];      //player join scripts
593 Script respawn_script[4];   //player respawn scripts
594 Script pdie_script[4];      //player death scripts
595 
596 extern Script* pcurrentscript;//used by local script functions
597 //-------------------------methods-------------------------------
598 
setDrawMethod(s_anim * a,ptrdiff_t index,s_drawmethod * m)599 void setDrawMethod(s_anim* a, ptrdiff_t index, s_drawmethod* m) {
600 	assert(index >= 0);
601 	assert(a != NULL);
602 	assert(m != NULL);
603 	assert(index < a->numframes);
604 	a->drawmethods[index] = m;
605 }
606 
getDrawMethod(s_anim * a,ptrdiff_t index)607 s_drawmethod* getDrawMethod(s_anim* a, ptrdiff_t index) {
608 	assert(index >= 0);
609 	assert(a != NULL);
610 	assert(index < a->numframes);
611 	return a->drawmethods[index];
612 }
613 
isLoadingScreenTypeBg(loadingScreenType what)614 int isLoadingScreenTypeBg(loadingScreenType what) {
615 	return (what & LSTYPE_BACKGROUND) == LSTYPE_BACKGROUND;
616 }
617 
isLoadingScreenTypeBar(loadingScreenType what)618 int isLoadingScreenTypeBar(loadingScreenType what) {
619 	return (what & LSTYPE_BAR) == LSTYPE_BAR;
620 }
621 
fill_s_loadingbar(s_loadingbar * s,char set,short bx,short by,short bsize,short tx,short ty,char tf,int ms)622 char* fill_s_loadingbar(s_loadingbar* s, char set, short bx, short by, short bsize, short tx, short ty, char tf, int ms) {
623 	switch (set) {
624 		case 1: s->set = (LSTYPE_BACKGROUND | LSTYPE_BAR); break;
625 		case 2: s->set = LSTYPE_BACKGROUND; break;
626 		case 3: s->set = LSTYPE_BAR; break;
627 		case 0: s->set = LSTYPE_NONE; break;
628 		default:
629 			s->set = LSTYPE_NONE;
630 			printf("invalid loadingbg type %d!\n", set);
631 	}
632 	s->tf = tf;
633 	s->bx = bx;
634 	s->by = by;
635 	s->bsize = bsize;
636 	s->tx = tx;
637 	s->ty = ty;
638 	s->refreshMs = (ms ? ms : 100);
639 	return NULL;
640 }
641 
642 
643 // returns: 1 - succeeded 0 - failed
buffer_pakfile(char * filename,char ** pbuffer,size_t * psize)644 int buffer_pakfile(char* filename, char** pbuffer, size_t* psize)
645 {
646 	int handle;
647 	*psize = 0;
648 	*pbuffer = NULL;
649 	// Read file
650 #ifdef VERBOSE
651 	printf("pakfile requested: %s.\n", filename); //ASDF
652 #endif
653 
654 	if((handle=openpackfile(filename,packfile)) < 0) {
655 #ifdef VERBOSE
656 		printf("couldnt get handle!\n");
657 #endif
658 		return 0;
659 	}
660 	*psize = seekpackfile(handle,0,SEEK_END);
661 	seekpackfile(handle,0,SEEK_SET);
662 
663 	*pbuffer = (char*)malloc(*psize+1);
664 	if(*pbuffer == NULL){
665 		*psize = 0;
666 		closepackfile(handle);
667 		shutdown(1, "Can't create buffer for packfile '%s'", filename);
668 		return 0;
669 	}
670 	if(readpackfile(handle, *pbuffer, *psize) != *psize){
671 		if(*pbuffer != NULL){
672 			free(*pbuffer);
673 			*pbuffer = NULL;
674 			*psize = 0;
675 		}
676 		closepackfile(handle);
677 		shutdown(1, "Can't read from packfile '%s'", filename);
678 		return 0;
679 	}
680 	(*pbuffer)[*psize] = 0;        // Terminate string (important!)
681 	closepackfile(handle);
682 	return 1;
683 }
684 
685 //this method is used by script engine, we move it here
686 // it will get a system property, put it in the ScriptVariant
687 // if failed return 0, otherwise return 1
getsyspropertybyindex(ScriptVariant * var,int index)688 int getsyspropertybyindex(ScriptVariant* var, int index)
689 {
690 	enum nameenum
691 	{
692 		_e_branchname,
693 		_e_count_enemies,
694 		_e_count_entities,
695 		_e_count_npcs,
696 		_e_count_players,
697 		_e_current_level,
698 		_e_current_palette,
699 		_e_current_scene,
700 		_e_current_set,
701 		_e_current_stage,
702 		_e_effectvol,
703 		_e_elapsed_time,
704 		_e_ent_max,
705 		_e_game_paused,
706 		_e_game_speed,
707 		_e_gfx_x_offset,
708 		_e_gfx_y_offset,
709 		_e_gfx_y_offset_adj,
710 		_e_hResolution,
711 		_e_in_gameoverscreen,
712 		_e_in_halloffamescreen,
713 		_e_in_level,
714 		_e_in_menuscreen,
715 		_e_in_selectscreen,
716 		_e_in_showcomplete,
717 		_e_in_titlescreen,
718 		_e_lasthita,
719 		_e_lasthitc,
720 		_e_lasthitt,
721 		_e_lasthitx,
722 		_e_lasthitz,
723 		_e_levelheight,
724 		_e_levelwidth,
725 		_e_lightx,
726 		_e_lightz,
727 		_e_maxentityvars,
728 		_e_maxglobalvars,
729 		_e_maxindexedvars,
730 		_e_maxplayers,
731 		_e_maxscriptvars,
732 		_e_models_cached,
733 		_e_models_loaded,
734 		_e_musicvol,
735 		_e_numpalettes,
736 		_e_pause,
737 		_e_pixelformat,
738 		_e_player,
739 		_e_player1,
740 		_e_player2,
741 		_e_player3,
742 		_e_player4,
743 		_e_player_max_z,
744 		_e_player_min_z,
745 		_e_shadowalpha,
746 		_e_shadowcolor,
747 		_e_slowmotion,
748 		_e_slowmotion_duration,
749 		_e_soundvol,
750 		_e_totalram,
751 		_e_freeram,
752 		_e_usedram,
753 		_e_vResolution,
754 		_e_xpos,
755 		_e_ypos,
756 		_e_the_end,
757 	};
758 
759 	if(!var) return 0;
760 
761 	switch(index)
762 	{
763 	case _e_count_enemies:
764 		ScriptVariant_ChangeType(var, VT_INTEGER);
765 		var->lVal = (LONG)count_ents(TYPE_ENEMY);
766 		break;
767 	case _e_count_players:
768 		ScriptVariant_ChangeType(var, VT_INTEGER);
769 		var->lVal = (LONG)count_ents(TYPE_PLAYER);
770 		break;
771 	case _e_count_npcs:
772 		ScriptVariant_ChangeType(var, VT_INTEGER);
773 		var->lVal = (LONG)count_ents(TYPE_NPC);
774 		break;
775 	case _e_count_entities:
776 		ScriptVariant_ChangeType(var, VT_INTEGER);
777 		var->lVal = (LONG)ent_count;
778 		break;
779 	case _e_ent_max:
780 		ScriptVariant_ChangeType(var, VT_INTEGER);
781 		var->lVal = (LONG)ent_max;
782 		break;
783 	case _e_in_level:
784 		ScriptVariant_ChangeType(var, VT_INTEGER);
785 		var->lVal = (LONG)(level != NULL);
786 		break;
787 	case _e_in_gameoverscreen:
788 		ScriptVariant_ChangeType(var, VT_INTEGER);
789 		var->lVal = (LONG)(gameOver);
790 		break;
791 	case _e_in_menuscreen:
792 		ScriptVariant_ChangeType(var, VT_INTEGER);
793 		if(selectScreen || titleScreen || hallOfFame || gameOver || showComplete || currentScene || level)
794 			var->lVal = (LONG)0;
795 		else var->lVal = (LONG)(menuScreen);
796 		break;
797 	case _e_in_showcomplete:
798 		ScriptVariant_ChangeType(var, VT_INTEGER);
799 		var->lVal = (LONG)(showComplete);
800 		break;
801 	case _e_in_titlescreen:
802 		ScriptVariant_ChangeType(var, VT_INTEGER);
803 		var->lVal = (LONG)(titleScreen);
804 		break;
805 	case _e_in_halloffamescreen:
806 		ScriptVariant_ChangeType(var, VT_INTEGER);
807 		var->lVal = (LONG)(hallOfFame);
808 		break;
809 	case _e_effectvol:
810 		ScriptVariant_ChangeType(var, VT_INTEGER);
811 		var->lVal = (LONG)savedata.effectvol;
812 		break;
813 	case _e_elapsed_time:
814 		ScriptVariant_ChangeType(var, VT_INTEGER);
815 		var->lVal = (LONG)time;
816 		break;
817 	case _e_game_speed:
818 		if(!level) return 0;
819 		ScriptVariant_ChangeType(var, VT_INTEGER);
820 		var->lVal = (LONG)GAME_SPEED;
821 		break;
822 	case _e_pause:
823 		ScriptVariant_ChangeType(var, VT_INTEGER);
824 		var->lVal = (LONG)pause;
825 		break;
826     case _e_gfx_x_offset:
827 		if(!level) return 0;
828 		ScriptVariant_ChangeType(var, VT_INTEGER);
829 		var->lVal = (LONG)gfx_x_offset;
830 		break;
831 	case _e_gfx_y_offset:
832 		if(!level) return 0;
833 		ScriptVariant_ChangeType(var, VT_INTEGER);
834 		var->lVal = (LONG)gfx_y_offset;
835 		break;
836     case _e_gfx_y_offset_adj:
837 		if(!level) return 0;
838 		ScriptVariant_ChangeType(var, VT_INTEGER);
839 		var->lVal = (LONG)gfx_y_offset_adj;
840 		break;
841 	case _e_in_selectscreen:
842 		ScriptVariant_ChangeType(var, VT_INTEGER);
843 		var->lVal = (LONG)(selectScreen);
844 		break;
845 	case _e_lasthita:
846 		ScriptVariant_ChangeType(var, VT_DECIMAL);
847 		var->dblVal = (DOUBLE)(lasthita);
848 		break;
849 	case _e_lasthitc:
850 		ScriptVariant_ChangeType(var, VT_INTEGER);
851 		var->lVal = (LONG)(lasthitc);
852 		break;
853 	case _e_lasthitt:
854 		ScriptVariant_ChangeType(var, VT_INTEGER);
855 		var->lVal = (LONG)(lasthitt);
856 		break;
857 	case _e_lasthitx:
858 		ScriptVariant_ChangeType(var, VT_DECIMAL);
859 		var->dblVal = (DOUBLE)(lasthitx);
860 		break;
861 	case _e_lasthitz:
862 		ScriptVariant_ChangeType(var, VT_DECIMAL);
863 		var->dblVal = (DOUBLE)(lasthitz);
864 		break;
865 	case _e_xpos:
866 		if(!level) return 0;
867 		ScriptVariant_ChangeType(var, VT_DECIMAL);
868 		var->dblVal = (DOUBLE)advancex;
869 		break;
870 	case _e_ypos:
871 		if(!level) return 0;
872 		ScriptVariant_ChangeType(var, VT_DECIMAL);
873 		var->dblVal = (DOUBLE)advancey;
874 		break;
875 	case _e_hResolution:
876 		ScriptVariant_ChangeType(var, VT_INTEGER);
877 		var->lVal = (LONG)videomodes.hRes;
878 		break;
879 	case _e_vResolution:
880 		ScriptVariant_ChangeType(var, VT_INTEGER);
881 		var->lVal = (LONG)videomodes.vRes;
882 		break;
883 	case _e_current_scene:
884 		if(currentScene){
885 			ScriptVariant_ChangeType(var, VT_STR);
886 			strcpy(StrCache_Get(var->strVal), currentScene);
887 		}else ScriptVariant_Clear(var);
888 		break;
889 	case _e_current_set:
890 		ScriptVariant_ChangeType(var, VT_INTEGER);
891 		var->lVal = (LONG)(current_set);
892 		break;
893 	case _e_current_level:
894 		ScriptVariant_ChangeType(var, VT_INTEGER);
895 		var->lVal = (LONG)(current_level);
896 		break;
897 	case _e_current_palette:
898 		ScriptVariant_ChangeType(var, VT_INTEGER);
899 		var->lVal = (LONG)(current_palette);
900 		break;
901 	case _e_current_stage:
902 		ScriptVariant_ChangeType(var, VT_INTEGER);
903 		var->lVal = (LONG)(current_stage);
904 		break;
905 	case _e_levelwidth:
906 		if(!level) return 0;
907 		ScriptVariant_ChangeType(var, VT_INTEGER);
908 		var->lVal = (LONG)(level->width);
909 		break;
910 	case _e_levelheight:
911 		if(!level) return 0;
912 		ScriptVariant_ChangeType(var, VT_INTEGER);
913 		var->lVal = (LONG)(panel_height);
914 		break;
915 	case _e_branchname:
916 		ScriptVariant_ChangeType(var, VT_STR);
917 		strcpy(StrCache_Get(var->strVal), branch_name);
918 		break;
919 	case _e_maxentityvars:
920 		ScriptVariant_ChangeType(var, VT_INTEGER);
921 		var->lVal = (LONG)max_entity_vars;
922 		break;
923 	case _e_maxglobalvars:
924 		ScriptVariant_ChangeType(var, VT_INTEGER);
925 		var->lVal = (LONG)max_global_vars;
926 		break;
927 	case _e_maxindexedvars:
928 		ScriptVariant_ChangeType(var, VT_INTEGER);
929 		var->lVal = (LONG)max_indexed_vars;
930 		break;
931 	case _e_maxplayers:
932 		ScriptVariant_ChangeType(var, VT_INTEGER);
933 		var->lVal = (LONG)maxplayers[current_set];
934 		break;
935 	case _e_maxscriptvars:
936 		ScriptVariant_ChangeType(var, VT_INTEGER);
937 		var->lVal = (LONG)max_script_vars;
938 		break;
939 	case _e_models_cached:
940 		ScriptVariant_ChangeType(var, VT_INTEGER);
941 		var->lVal = (LONG)models_cached;
942 		break;
943 	case _e_models_loaded:
944 		ScriptVariant_ChangeType(var, VT_INTEGER);
945 		var->lVal = (LONG)models_loaded;
946 		break;
947 	case _e_musicvol:
948 		ScriptVariant_ChangeType(var, VT_INTEGER);
949 		var->lVal = (LONG)savedata.musicvol;
950 		break;
951 	case _e_numpalettes:
952 		ScriptVariant_ChangeType(var, VT_INTEGER);
953 		var->lVal = (LONG)(level->numpalettes);
954 		break;
955 	case _e_pixelformat:
956 		ScriptVariant_ChangeType(var, VT_INTEGER);
957 		var->lVal = (LONG)pixelformat;
958 		break;
959 	case _e_player:
960 	case _e_player1:
961 		ScriptVariant_ChangeType(var, VT_PTR);
962 		var->ptrVal = (VOID*)player;
963 		break;
964 	case _e_player2:
965 		ScriptVariant_ChangeType(var, VT_PTR);
966 		var->ptrVal = (VOID*)(player+1);
967 		break;
968 	case _e_player3:
969 		ScriptVariant_ChangeType(var, VT_PTR);
970 		var->ptrVal = (VOID*)(player+2);
971 		break;
972 	case _e_player4:
973 		ScriptVariant_ChangeType(var, VT_PTR);
974 		var->ptrVal = (VOID*)(player+3);
975 		break;
976 	case _e_player_max_z:
977 		ScriptVariant_ChangeType(var, VT_INTEGER);
978 		var->lVal = (LONG)(PLAYER_MAX_Z);
979 		break;
980 	case _e_player_min_z:
981 		ScriptVariant_ChangeType(var, VT_INTEGER);
982 		var->lVal = (LONG)(PLAYER_MIN_Z);
983 		break;
984 	case _e_lightx:
985 		ScriptVariant_ChangeType(var, VT_INTEGER);
986 		var->lVal = (LONG)(light[0]);
987 		break;
988 	case _e_lightz:
989 		ScriptVariant_ChangeType(var, VT_INTEGER);
990 		var->lVal = (LONG)(light[1]);
991 		break;
992 	case _e_shadowalpha:
993 		ScriptVariant_ChangeType(var, VT_INTEGER);
994 		var->lVal = (LONG)shadowalpha;
995 		break;
996 	case _e_shadowcolor:
997 		ScriptVariant_ChangeType(var, VT_INTEGER);
998 		var->lVal = (LONG)shadowcolor;
999 		break;
1000 	case _e_slowmotion:
1001 		ScriptVariant_ChangeType(var, VT_INTEGER);
1002 		var->lVal = (LONG)slowmotion[0];
1003 		break;
1004 	case _e_slowmotion_duration:
1005 		ScriptVariant_ChangeType(var, VT_INTEGER);
1006 		var->lVal = (LONG)slowmotion[1];
1007 		break;
1008 	case _e_soundvol:
1009 		ScriptVariant_ChangeType(var, VT_INTEGER);
1010 		var->lVal = (LONG)savedata.soundvol;
1011 		break;
1012 	case _e_game_paused:
1013 		ScriptVariant_ChangeType(var, VT_INTEGER);
1014 		var->lVal = (LONG)pause;
1015 		break;
1016 	case _e_totalram:
1017 		 ScriptVariant_ChangeType(var, VT_INTEGER);
1018 		 var->lVal = (LONG)getSystemRam(KBYTES);
1019 		break;
1020 	case _e_freeram:
1021 		ScriptVariant_ChangeType(var, VT_INTEGER);
1022 		var->lVal = (LONG)getFreeRam(KBYTES);
1023 		break;
1024 	case _e_usedram:
1025 		 ScriptVariant_ChangeType(var, VT_INTEGER);
1026 		 var->lVal = (LONG)getUsedRam(KBYTES);
1027 		break;
1028 	default:
1029 		// We use indices now, but players/modders don't need to be exposed
1030 		// to that implementation detail, so we write "name" and not "index".
1031 		printf("Unknown system property name.\n");
1032 		return 0;
1033 	}
1034 	return 1;
1035 }
1036 
1037 // change a system variant, used by script
changesyspropertybyindex(int index,ScriptVariant * value)1038 int changesyspropertybyindex(int index, ScriptVariant* value)
1039 {
1040 	//char* tempstr = NULL;
1041 	LONG ltemp;
1042 	//DOUBLE dbltemp;
1043 
1044 	// This enum is replicated in mapstrings_changesystemvariant in
1045 	// openborscript.c. If you change one, you must change the other as well!!!!
1046 	enum changesystemvariant_enum
1047 	{
1048 		_csv_blockade,
1049 		_csv_elapsed_time,
1050 		_csv_gfx_x_offset,
1051 		_csv_gfx_y_offset,
1052 		_csv_gfx_y_offset_adj,
1053 		_csv_lasthita,
1054 		_csv_lasthitc,
1055 		_csv_lasthitt,
1056 		_csv_lasthitx,
1057 		_csv_lasthitz,
1058 		_csv_levelpos,
1059 		_csv_scrollmaxz,
1060 		_csv_scrollminz,
1061 		_csv_slowmotion,
1062 		_csv_slowmotion_duration,
1063 		_csv_smartbomber,
1064 		_csv_textbox,
1065 		_csv_xpos,
1066 		_csv_ypos,
1067 		_csv_the_end,
1068 	 };
1069 
1070 	switch(index)
1071 	{
1072 	case _csv_elapsed_time:
1073 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1074 			time = (int)ltemp;
1075 		break;
1076     case _csv_gfx_x_offset:
1077 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1078 			gfx_x_offset = (int)ltemp;
1079 		break;
1080     case _csv_gfx_y_offset:
1081 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1082 			gfx_y_offset = (int)ltemp;
1083 		break;
1084     case _csv_gfx_y_offset_adj:
1085 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1086 			gfx_y_offset_adj = (int)ltemp;
1087 		break;
1088 	case _csv_levelpos:
1089 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1090 			level->pos = (int)ltemp;
1091 		break;
1092 	case _csv_xpos:
1093 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1094 			advancex = (float)ltemp;
1095 		break;
1096 	case _csv_ypos:
1097 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1098 			advancey = (float)ltemp;
1099 		break;
1100 	case _csv_scrollminz:
1101 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1102 			scrollminz = (float)ltemp;
1103 		break;
1104 	case _csv_scrollmaxz:
1105 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1106 			scrollmaxz = (float)ltemp;
1107 		break;
1108 	case _csv_blockade:
1109 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1110 			blockade = (float)ltemp;
1111 		break;
1112 	case _csv_slowmotion:
1113 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1114 			slowmotion[0] = (unsigned char)ltemp;
1115 		break;
1116 	case _csv_slowmotion_duration:
1117 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1118 			slowmotion[1] = (unsigned char)ltemp;
1119 		break;
1120 	case _csv_lasthitx:
1121 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1122 			lasthitx = (float)ltemp;
1123 		break;
1124 	case _csv_lasthita:
1125 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1126 			lasthita = (float)ltemp;
1127 		break;
1128 	 case _csv_lasthitc:
1129 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1130 			lasthitc = (int)ltemp;
1131 		break;
1132 	case _csv_lasthitz:
1133 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1134 			lasthitz = (float)ltemp;
1135 		break;
1136 	case _csv_lasthitt:
1137 		if(SUCCEEDED(ScriptVariant_IntegerValue(value, &ltemp)))
1138 			lasthitt = (int)ltemp;
1139 		break;
1140 	case _csv_smartbomber:
1141 		smartbomber = (entity*)value;
1142 		break;
1143 	case _csv_textbox:
1144 		textbox = (entity*)value;
1145 		break;
1146 	default:
1147 		return 0;
1148 	}
1149 
1150 	return 1;
1151 }
1152 
1153 
load_script(Script * script,char * file)1154 int load_script(Script* script, char* file)
1155 {
1156 	size_t size = 0;
1157 	int failed = 0;
1158 	char* buf = NULL;
1159 
1160 	if(buffer_pakfile(file, &buf, &size)!=1) return 0;
1161 
1162 	failed = !Script_AppendText(script, buf, file);
1163 
1164 	if(buf != NULL)
1165 	{
1166 		free(buf);
1167 		buf = NULL;
1168 	}
1169 
1170 	// text loaded but parsing failed, shutdown
1171 	if(failed) shutdown(1, "Failed to parse script file: '%s'!\n", file);
1172 	return !failed;
1173 }
1174 
1175 // this method is used by load_scripts, don't call it
init_scripts()1176 void init_scripts()
1177 {
1178 	int i;
1179 	Script_Global_Init();
1180 	Script_Init(&update_script,     "update",   1);
1181 	Script_Init(&updated_script,    "updated",  1);
1182 	Script_Init(&level_script,      "level",    1);
1183 	Script_Init(&endlevel_script,   "endlevel", 1);
1184 	Script_Init(&key_script_all,    "keyall",   1);
1185 	Script_Init(&timetick_script,   "timetick", 1);
1186 	Script_Init(&loading_script,    "loading",  1);
1187 	for(i=0; i<4; i++) Script_Init(&score_script[i],    "score",    1);
1188 	for(i=0; i<4; i++) Script_Init(&key_script[i],      "key",      1);
1189 	for(i=0; i<4; i++) Script_Init(&join_script[i],     "join",     1);
1190 	for(i=0; i<4; i++) Script_Init(&respawn_script[i],  "respawn",  1);
1191 	for(i=0; i<4; i++) Script_Init(&pdie_script[i],     "die",      1);
1192 }
1193 
1194 // This method is called once when the engine starts, do not use it multiple times
1195 // It should be calld after load_script_setting
load_scripts()1196 void load_scripts()
1197 {
1198 	int i;
1199 	init_scripts();
1200 	//Script_Clear's second parameter set to 2, because the script fails to load,
1201 	//and will never have another chance to be loaded, so just clear the variable list in it
1202 	if(!load_script(&update_script,     "data/scripts/update.c"))   Script_Clear(&update_script,        2);
1203 	if(!load_script(&updated_script,    "data/scripts/updated.c"))  Script_Clear(&updated_script,       2);
1204 	if(!load_script(&level_script,      "data/scripts/level.c"))    Script_Clear(&level_script,         2);
1205 	if(!load_script(&endlevel_script,   "data/scripts/endlevel.c")) Script_Clear(&endlevel_script,      2);
1206 	if(!load_script(&key_script_all,    "data/scripts/keyall.c"))   Script_Clear(&key_script_all,       2);
1207 	if(!load_script(&timetick_script,   "data/scripts/timetick.c")) Script_Clear(&timetick_script,      2);
1208 	if(!load_script(&loading_script,    "data/scripts/loading.c"))  Script_Clear(&loading_script,       2);
1209 	if(!load_script(&score_script[0],   "data/scripts/score1.c"))   Script_Clear(&score_script[0],      2);
1210 	if(!load_script(&score_script[1],   "data/scripts/score2.c"))   Script_Clear(&score_script[1],      2);
1211 	if(!load_script(&score_script[2],   "data/scripts/score3.c"))   Script_Clear(&score_script[2],      2);
1212 	if(!load_script(&score_script[3],   "data/scripts/score4.c"))   Script_Clear(&score_script[3],      2);
1213 	if(!load_script(&key_script[0],     "data/scripts/key1.c"))     Script_Clear(&key_script[0],        2);
1214 	if(!load_script(&key_script[1],     "data/scripts/key2.c"))     Script_Clear(&key_script[1],        2);
1215 	if(!load_script(&key_script[2],     "data/scripts/key3.c"))     Script_Clear(&key_script[2],        2);
1216 	if(!load_script(&key_script[3],     "data/scripts/key4.c"))     Script_Clear(&key_script[3],        2);
1217 	if(!load_script(&join_script[0],    "data/scripts/join1.c"))    Script_Clear(&join_script[0],       2);
1218 	if(!load_script(&join_script[1],    "data/scripts/join2.c"))    Script_Clear(&join_script[1],       2);
1219 	if(!load_script(&join_script[2],    "data/scripts/join3.c"))    Script_Clear(&join_script[2],       2);
1220 	if(!load_script(&join_script[3],    "data/scripts/join4.c"))    Script_Clear(&join_script[3],       2);
1221 	if(!load_script(&respawn_script[0], "data/scripts/respawn1.c")) Script_Clear(&respawn_script[0],    2);
1222 	if(!load_script(&respawn_script[1], "data/scripts/respawn2.c")) Script_Clear(&respawn_script[1],    2);
1223 	if(!load_script(&respawn_script[2], "data/scripts/respawn3.c")) Script_Clear(&respawn_script[2],    2);
1224 	if(!load_script(&respawn_script[3], "data/scripts/respawn4.c")) Script_Clear(&respawn_script[3],    2);
1225 	if(!load_script(&pdie_script[0],    "data/scripts/die1.c"))     Script_Clear(&pdie_script[0],       2);
1226 	if(!load_script(&pdie_script[1],    "data/scripts/die2.c"))     Script_Clear(&pdie_script[1],       2);
1227 	if(!load_script(&pdie_script[2],    "data/scripts/die3.c"))     Script_Clear(&pdie_script[2],       2);
1228 	if(!load_script(&pdie_script[3],    "data/scripts/die4.c"))     Script_Clear(&pdie_script[3],       2);
1229 	Script_Compile(&update_script);
1230 	Script_Compile(&updated_script);
1231 	Script_Compile(&level_script);
1232 	Script_Compile(&endlevel_script);
1233 	Script_Compile(&key_script_all);
1234 	Script_Compile(&timetick_script);
1235 	Script_Compile(&loading_script);
1236 	for(i=0; i<4; i++) Script_Compile(&score_script[i]);
1237 	for(i=0; i<4; i++) Script_Compile(&key_script[i]);
1238 	for(i=0; i<4; i++) Script_Compile(&join_script[i]);
1239 	for(i=0; i<4; i++) Script_Compile(&respawn_script[i]);
1240 	for(i=0; i<4; i++) Script_Compile(&pdie_script[i]);
1241 }
1242 
1243 // This method is called once when the engine is shutting down, do not use it multiple times
clear_scripts()1244 void clear_scripts()
1245 {
1246 	int i;
1247 	//Script_Clear's second parameter set to 2, because the script fails to load,
1248 	//and will never have another chance to be loaded, so just clear the variable list in it
1249 	Script_Clear(&update_script,    2);
1250 	Script_Clear(&updated_script,   2);
1251 	Script_Clear(&level_script,     2);
1252 	Script_Clear(&endlevel_script,  2);
1253 	Script_Clear(&key_script_all,   2);
1254 	Script_Clear(&timetick_script,  2);
1255 	for(i=0; i<4; i++)
1256 		Script_Clear(&score_script[i],      2);
1257 	for(i=0; i<4; i++)
1258 		Script_Clear(&key_script[i],        2);
1259 	for(i=0; i<4; i++)
1260 		Script_Clear(&join_script[i],       2);
1261 	for(i=0; i<4; i++)
1262 		Script_Clear(&respawn_script[i],    2);
1263 	for(i=0; i<4; i++)
1264 		Script_Clear(&pdie_script[i],       2);
1265 	Script_Global_Clear();
1266 }
1267 
alloc_all_scripts(s_scripts * s)1268 void alloc_all_scripts(s_scripts* s) {
1269 	static const size_t scripts_membercount = sizeof(s_scripts) / sizeof(Script*);
1270 	size_t i;
1271 
1272 	for (i = 0; i < scripts_membercount; i++) {
1273 		(((Script**) s)[i]) = alloc_script();
1274 	}
1275 }
1276 
clear_all_scripts(s_scripts * s,int method)1277 void clear_all_scripts(s_scripts* s, int method) {
1278 	static const size_t scripts_membercount = sizeof(s_scripts) / sizeof(Script*);
1279 	size_t i;
1280 	Script** ps = (Script**) s;
1281 
1282 	for (i = 0; i < scripts_membercount; i++) {
1283 		Script_Clear(ps[i],   method);
1284 	}
1285 }
1286 
free_all_scripts(s_scripts * s)1287 void free_all_scripts(s_scripts* s) {
1288 	static const size_t scripts_membercount = sizeof(s_scripts) / sizeof(Script*);
1289 	size_t i;
1290 	Script** ps = (Script**) s;
1291 
1292 	for (i = 0; i < scripts_membercount; i++) {
1293 		if (ps[i]) {
1294 			free(ps[i]);
1295 			ps[i] = NULL;
1296 		}
1297 	}
1298 }
1299 
copy_all_scripts(s_scripts * src,s_scripts * dest,int method)1300 void copy_all_scripts(s_scripts* src, s_scripts* dest, int method) {
1301 	static const size_t scripts_membercount = sizeof(s_scripts) / sizeof(Script*);
1302 	size_t i;
1303 	Script** ps = (Script**) src;
1304 	Script** pd = (Script**) dest;
1305 
1306 	for (i = 0; i < scripts_membercount; i++) {
1307 			Script_Copy(pd[i], ps[i], method);
1308 	}
1309 }
1310 
execute_animation_script(entity * ent)1311 void execute_animation_script(entity* ent)
1312 {
1313 	ScriptVariant tempvar;
1314 	Script* ptempscript = pcurrentscript;
1315 	if(Script_IsInitialized(ent->scripts.animation_script))
1316 	{
1317 		ScriptVariant_Init(&tempvar);
1318 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1319 		tempvar.ptrVal = (VOID*)ent;
1320 		Script_Set_Local_Variant("self",    &tempvar);
1321 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1322 		tempvar.lVal = (LONG)ent->animnum;
1323 		Script_Set_Local_Variant("animnum", &tempvar);
1324 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1325 		tempvar.lVal = (LONG)ent->animpos;
1326 		Script_Set_Local_Variant("frame",   &tempvar);
1327 		Script_Execute(ent->scripts.animation_script);
1328 		//clear to save variant space
1329 		ScriptVariant_Clear(&tempvar);
1330 		Script_Set_Local_Variant("self",    &tempvar);
1331 		Script_Set_Local_Variant("animnum", &tempvar);
1332 		Script_Set_Local_Variant("frame",   &tempvar);
1333 	}
1334 	pcurrentscript = ptempscript;
1335 }
1336 
execute_takedamage_script(entity * ent,entity * other,int force,int drop,int type,int noblock,int guardcost,int jugglecost,int pauseadd)1337 void execute_takedamage_script(entity* ent, entity* other, int force, int drop, int type, int noblock, int guardcost, int jugglecost, int pauseadd)
1338 {
1339 	ScriptVariant tempvar;
1340 	Script* ptempscript = pcurrentscript;
1341 	if(Script_IsInitialized(ent->scripts.takedamage_script))
1342 	{
1343 		ScriptVariant_Init(&tempvar);
1344 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1345 		tempvar.ptrVal = (VOID*)ent;
1346 		Script_Set_Local_Variant("self",        &tempvar);
1347 		tempvar.ptrVal = (VOID*)other;
1348 		Script_Set_Local_Variant("attacker",    &tempvar);
1349 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1350 		tempvar.lVal = (LONG)force;
1351 		Script_Set_Local_Variant("damage",      &tempvar);
1352 		tempvar.lVal = (LONG)drop;
1353 		Script_Set_Local_Variant("drop",        &tempvar);
1354 		tempvar.lVal = (LONG)type;
1355 		Script_Set_Local_Variant("attacktype",  &tempvar);
1356 		tempvar.lVal = (LONG)noblock;
1357 		Script_Set_Local_Variant("noblock",     &tempvar);
1358 		tempvar.lVal = (LONG)guardcost;
1359 		Script_Set_Local_Variant("guardcost",   &tempvar);
1360 		tempvar.lVal = (LONG)jugglecost;
1361 		Script_Set_Local_Variant("jugglecost",  &tempvar);
1362 		tempvar.lVal = (LONG)pauseadd;
1363 		Script_Set_Local_Variant("pauseadd",    &tempvar);
1364 		Script_Execute(ent->scripts.takedamage_script);
1365 		//clear to save variant space
1366 		ScriptVariant_Clear(&tempvar);
1367 		Script_Set_Local_Variant("self",        &tempvar);
1368 		Script_Set_Local_Variant("attacker",    &tempvar);
1369 		Script_Set_Local_Variant("damage",      &tempvar);
1370 		Script_Set_Local_Variant("drop",        &tempvar);
1371 		Script_Set_Local_Variant("attacktype",  &tempvar);
1372 		Script_Set_Local_Variant("noblock",     &tempvar);
1373 		Script_Set_Local_Variant("guardcost",   &tempvar);
1374 		Script_Set_Local_Variant("jugglecost",  &tempvar);
1375 		Script_Set_Local_Variant("pauseadd",    &tempvar);
1376 	}
1377 	pcurrentscript = ptempscript;
1378 }
1379 
execute_onpain_script(entity * ent,int iType,int iReset)1380 void execute_onpain_script(entity* ent, int iType, int iReset)
1381 {
1382 	ScriptVariant tempvar;
1383 	Script* ptempscript = pcurrentscript;
1384 	if(Script_IsInitialized(ent->scripts.onpain_script))
1385 	{
1386 		ScriptVariant_Init(&tempvar);
1387 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1388 		tempvar.ptrVal = (VOID*)ent;
1389 		Script_Set_Local_Variant("self",        &tempvar);
1390 		tempvar.lVal = (LONG)iType;
1391 		Script_Set_Local_Variant("attacktype",   &tempvar);
1392 		tempvar.lVal = (LONG)iReset;
1393 		Script_Set_Local_Variant("reset",       &tempvar);
1394 		Script_Execute(ent->scripts.onpain_script);
1395 		//clear to save variant space
1396 		ScriptVariant_Clear(&tempvar);
1397 		Script_Set_Local_Variant("self",        &tempvar);
1398 		Script_Set_Local_Variant("type",        &tempvar);
1399 		Script_Set_Local_Variant("reset",       &tempvar);
1400 	}
1401 	pcurrentscript = ptempscript;
1402 }
1403 
execute_onfall_script(entity * ent,entity * other,int force,int drop,int type,int noblock,int guardcost,int jugglecost,int pauseadd)1404 void execute_onfall_script(entity* ent, entity* other, int force, int drop, int type, int noblock, int guardcost, int jugglecost, int pauseadd)
1405 {
1406 	ScriptVariant tempvar;
1407 	Script* ptempscript = pcurrentscript;
1408 	if(Script_IsInitialized(ent->scripts.onfall_script))
1409 	{
1410 		ScriptVariant_Init(&tempvar);
1411 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1412 		tempvar.ptrVal = (VOID*)ent;
1413 		Script_Set_Local_Variant("self",        &tempvar);
1414 		tempvar.ptrVal = (VOID*)other;
1415 		Script_Set_Local_Variant("attacker",    &tempvar);
1416 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1417 		tempvar.lVal = (LONG)force;
1418 		Script_Set_Local_Variant("damage",      &tempvar);
1419 		tempvar.lVal = (LONG)drop;
1420 		Script_Set_Local_Variant("drop",        &tempvar);
1421 		tempvar.lVal = (LONG)type;
1422 		Script_Set_Local_Variant("attacktype",  &tempvar);
1423 		tempvar.lVal = (LONG)noblock;
1424 		Script_Set_Local_Variant("noblock",     &tempvar);
1425 		tempvar.lVal = (LONG)guardcost;
1426 		Script_Set_Local_Variant("guardcost",   &tempvar);
1427 		tempvar.lVal = (LONG)jugglecost;
1428 		Script_Set_Local_Variant("jugglecost",  &tempvar);
1429 		tempvar.lVal = (LONG)pauseadd;
1430 		Script_Set_Local_Variant("pauseadd",    &tempvar);
1431 		Script_Execute(ent->scripts.onfall_script);
1432 		//clear to save variant space
1433 		ScriptVariant_Clear(&tempvar);
1434 		Script_Set_Local_Variant("self",        &tempvar);
1435 		Script_Set_Local_Variant("attacker",    &tempvar);
1436 		Script_Set_Local_Variant("damage",      &tempvar);
1437 		Script_Set_Local_Variant("drop",        &tempvar);
1438 		Script_Set_Local_Variant("attacktype",  &tempvar);
1439 		Script_Set_Local_Variant("noblock",     &tempvar);
1440 		Script_Set_Local_Variant("guardcost",   &tempvar);
1441 		Script_Set_Local_Variant("jugglecost",  &tempvar);
1442 		Script_Set_Local_Variant("pauseadd",    &tempvar);
1443 	}
1444 	pcurrentscript = ptempscript;
1445 }
1446 
execute_onblocks_script(entity * ent)1447 void execute_onblocks_script(entity* ent)
1448 {
1449 	ScriptVariant tempvar;
1450 	Script* ptempscript = pcurrentscript;
1451 	if(Script_IsInitialized(ent->scripts.onblocks_script))
1452 	{
1453 		ScriptVariant_Init(&tempvar);
1454 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1455 		tempvar.ptrVal = (VOID*)ent;
1456 		Script_Set_Local_Variant("self", &tempvar);
1457 		Script_Execute(ent->scripts.onblocks_script);
1458 
1459 		//clear to save variant space
1460 		ScriptVariant_Clear(&tempvar);
1461 		Script_Set_Local_Variant("self", &tempvar);
1462 	}
1463 	pcurrentscript = ptempscript;
1464 }
1465 
execute_onblockw_script(entity * ent,int plane,float height)1466 void execute_onblockw_script(entity* ent, int plane, float height)
1467 {
1468 	ScriptVariant tempvar;
1469 	Script* ptempscript = pcurrentscript;
1470 	if(Script_IsInitialized(ent->scripts.onblockw_script))
1471 	{
1472 		ScriptVariant_Init(&tempvar);
1473 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1474 		tempvar.ptrVal = (VOID*)ent;
1475 		Script_Set_Local_Variant("self", &tempvar);
1476 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1477 		tempvar.lVal = (LONG)plane;
1478 		Script_Set_Local_Variant("plane",      &tempvar);
1479 		ScriptVariant_ChangeType(&tempvar, VT_DECIMAL);
1480 		tempvar.dblVal = (DOUBLE)height;
1481 		Script_Set_Local_Variant("height",      &tempvar);
1482 		Script_Execute(ent->scripts.onblockw_script);
1483 
1484 		//clear to save variant space
1485 		ScriptVariant_Clear(&tempvar);
1486 		Script_Set_Local_Variant("self", &tempvar);
1487 		ScriptVariant_Clear(&tempvar);
1488 		Script_Set_Local_Variant("plane", &tempvar);
1489 		ScriptVariant_Clear(&tempvar);
1490 		Script_Set_Local_Variant("height", &tempvar);
1491 	}
1492 	pcurrentscript = ptempscript;
1493 }
1494 
execute_onblocko_script(entity * ent,entity * other)1495 void execute_onblocko_script(entity* ent, entity* other)
1496 {
1497 	ScriptVariant tempvar;
1498 	Script* ptempscript = pcurrentscript;
1499 	if(Script_IsInitialized(ent->scripts.onblocko_script))
1500 	{
1501 		ScriptVariant_Init(&tempvar);
1502 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1503 		tempvar.ptrVal = (VOID*)ent;
1504 		Script_Set_Local_Variant("self",        &tempvar);
1505 		tempvar.ptrVal = (VOID*)other;
1506 		Script_Set_Local_Variant("obstacle",    &tempvar);
1507 		Script_Execute(ent->scripts.onblocko_script);
1508 
1509 		//clear to save variant space
1510 		ScriptVariant_Clear(&tempvar);
1511 		Script_Set_Local_Variant("self",        &tempvar);
1512 		Script_Set_Local_Variant("obstacle",    &tempvar);
1513 	}
1514 	pcurrentscript = ptempscript;
1515 }
1516 
execute_onblockz_script(entity * ent)1517 void execute_onblockz_script(entity* ent)
1518 {
1519 	ScriptVariant tempvar;
1520 	Script* ptempscript = pcurrentscript;
1521 	if(Script_IsInitialized(ent->scripts.onblockz_script))
1522 	{
1523 		ScriptVariant_Init(&tempvar);
1524 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1525 		tempvar.ptrVal = (VOID*)ent;
1526 		Script_Set_Local_Variant("self", &tempvar);
1527 		Script_Execute(ent->scripts.onblockz_script);
1528 
1529 		//clear to save variant space
1530 		ScriptVariant_Clear(&tempvar);
1531 		Script_Set_Local_Variant("self", &tempvar);
1532 	}
1533 	pcurrentscript = ptempscript;
1534 }
1535 
execute_onblocka_script(entity * ent,entity * other)1536 void execute_onblocka_script(entity* ent, entity* other)
1537 {
1538 	ScriptVariant tempvar;
1539 	Script* ptempscript = pcurrentscript;
1540 	if(Script_IsInitialized(ent->scripts.onblocka_script))
1541 	{
1542 		ScriptVariant_Init(&tempvar);
1543 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1544 		tempvar.ptrVal = (VOID*)ent;
1545 		Script_Set_Local_Variant("self",        &tempvar);
1546 		tempvar.ptrVal = (VOID*)other;
1547 		Script_Set_Local_Variant("obstacle",    &tempvar);
1548 		Script_Execute(ent->scripts.onblocka_script);
1549 		//clear to save variant space
1550 		ScriptVariant_Clear(&tempvar);
1551 		Script_Set_Local_Variant("self",        &tempvar);
1552 		Script_Set_Local_Variant("obstacle",    &tempvar);
1553 	}
1554 	pcurrentscript = ptempscript;
1555 }
1556 
execute_onmovex_script(entity * ent)1557 void execute_onmovex_script(entity* ent)
1558 {
1559 	ScriptVariant tempvar;
1560 	Script* ptempscript = pcurrentscript;
1561 	if(Script_IsInitialized(ent->scripts.onmovex_script))
1562 	{
1563 		ScriptVariant_Init(&tempvar);
1564 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1565 		tempvar.ptrVal = (VOID*)ent;
1566 		Script_Set_Local_Variant("self", &tempvar);
1567 		Script_Execute(ent->scripts.onmovex_script);
1568 
1569 		//clear to save variant space
1570 		ScriptVariant_Clear(&tempvar);
1571 		Script_Set_Local_Variant("self", &tempvar);
1572 	}
1573 	pcurrentscript = ptempscript;
1574 }
1575 
execute_onmovez_script(entity * ent)1576 void execute_onmovez_script(entity* ent)
1577 {
1578 	ScriptVariant tempvar;
1579 	Script* ptempscript = pcurrentscript;
1580 	if(Script_IsInitialized(ent->scripts.onmovez_script))
1581 	{
1582 		ScriptVariant_Init(&tempvar);
1583 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1584 		tempvar.ptrVal = (VOID*)ent;
1585 		Script_Set_Local_Variant("self", &tempvar);
1586 		Script_Execute(ent->scripts.onmovez_script);
1587 
1588 		//clear to save variant space
1589 		ScriptVariant_Clear(&tempvar);
1590 		Script_Set_Local_Variant("self", &tempvar);
1591 	}
1592 	pcurrentscript = ptempscript;
1593 }
1594 
execute_onmovea_script(entity * ent)1595 void execute_onmovea_script(entity* ent)
1596 {
1597 	ScriptVariant tempvar;
1598 	Script* ptempscript = pcurrentscript;
1599 	if(Script_IsInitialized(ent->scripts.onmovea_script))
1600 	{
1601 		ScriptVariant_Init(&tempvar);
1602 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1603 		tempvar.ptrVal = (VOID*)ent;
1604 		Script_Set_Local_Variant("self", &tempvar);
1605 		Script_Execute(ent->scripts.onmovea_script);
1606 
1607 		//clear to save variant space
1608 		ScriptVariant_Clear(&tempvar);
1609 		Script_Set_Local_Variant("self", &tempvar);
1610 	}
1611 	pcurrentscript = ptempscript;
1612 }
1613 
execute_ondeath_script(entity * ent,entity * other,int force,int drop,int type,int noblock,int guardcost,int jugglecost,int pauseadd)1614 void execute_ondeath_script(entity* ent, entity* other, int force, int drop, int type, int noblock, int guardcost, int jugglecost, int pauseadd)
1615 {
1616 	ScriptVariant tempvar;
1617 	Script* ptempscript = pcurrentscript;
1618 	if(Script_IsInitialized(ent->scripts.ondeath_script))
1619 	{
1620 		ScriptVariant_Init(&tempvar);
1621 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1622 		tempvar.ptrVal = (VOID*)ent;
1623 		Script_Set_Local_Variant("self",        &tempvar);
1624 		tempvar.ptrVal = (VOID*)other;
1625 		Script_Set_Local_Variant("attacker",    &tempvar);
1626 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1627 		tempvar.lVal = (LONG)force;
1628 		Script_Set_Local_Variant("damage",      &tempvar);
1629 		tempvar.lVal = (LONG)drop;
1630 		Script_Set_Local_Variant("drop",        &tempvar);
1631 		tempvar.lVal = (LONG)type;
1632 		Script_Set_Local_Variant("attacktype",  &tempvar);
1633 		tempvar.lVal = (LONG)noblock;
1634 		Script_Set_Local_Variant("noblock",     &tempvar);
1635 		tempvar.lVal = (LONG)guardcost;
1636 		Script_Set_Local_Variant("guardcost",   &tempvar);
1637 		tempvar.lVal = (LONG)jugglecost;
1638 		Script_Set_Local_Variant("jugglecost",  &tempvar);
1639 		tempvar.lVal = (LONG)pauseadd;
1640 		Script_Set_Local_Variant("pauseadd",    &tempvar);
1641 		Script_Execute(ent->scripts.ondeath_script);
1642 		//clear to save variant space
1643 		ScriptVariant_Clear(&tempvar);
1644 		Script_Set_Local_Variant("self",        &tempvar);
1645 		Script_Set_Local_Variant("attacker",    &tempvar);
1646 		Script_Set_Local_Variant("damage",      &tempvar);
1647 		Script_Set_Local_Variant("drop",        &tempvar);
1648 		Script_Set_Local_Variant("attacktype",  &tempvar);
1649 		Script_Set_Local_Variant("noblock",     &tempvar);
1650 		Script_Set_Local_Variant("guardcost",   &tempvar);
1651 		Script_Set_Local_Variant("jugglecost",  &tempvar);
1652 		Script_Set_Local_Variant("pauseadd",    &tempvar);
1653 	}
1654 	pcurrentscript = ptempscript;
1655 }
1656 
execute_onkill_script(entity * ent)1657 void execute_onkill_script(entity* ent)
1658 {
1659 	ScriptVariant tempvar;
1660 	Script* ptempscript = pcurrentscript;
1661 	if(Script_IsInitialized(ent->scripts.onkill_script))
1662 	{
1663 		ScriptVariant_Init(&tempvar);
1664 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1665 		tempvar.ptrVal = (VOID*)ent;
1666 		Script_Set_Local_Variant("self", &tempvar);
1667 		Script_Execute(ent->scripts.onkill_script);
1668 		//clear to save variant space
1669 		ScriptVariant_Clear(&tempvar);
1670 		Script_Set_Local_Variant("self", &tempvar);
1671 	}
1672 	pcurrentscript = ptempscript;
1673 }
1674 
execute_didblock_script(entity * ent,entity * other,int force,int drop,int type,int noblock,int guardcost,int jugglecost,int pauseadd)1675 void execute_didblock_script(entity* ent, entity* other, int force, int drop, int type, int noblock, int guardcost, int jugglecost, int pauseadd)
1676 {
1677 	ScriptVariant tempvar;
1678 	Script* ptempscript = pcurrentscript;
1679 	if(Script_IsInitialized(ent->scripts.didblock_script))
1680 	{
1681 		ScriptVariant_Init(&tempvar);
1682 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1683 		tempvar.ptrVal = (VOID*)ent;
1684 		Script_Set_Local_Variant("self",        &tempvar);
1685 		tempvar.ptrVal = (VOID*)other;
1686 		Script_Set_Local_Variant("attacker",    &tempvar);
1687 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1688 		tempvar.lVal = (LONG)force;
1689 		Script_Set_Local_Variant("damage",      &tempvar);
1690 		tempvar.lVal = (LONG)drop;
1691 		Script_Set_Local_Variant("drop",        &tempvar);
1692 		tempvar.lVal = (LONG)type;
1693 		Script_Set_Local_Variant("attacktype",  &tempvar);
1694 		tempvar.lVal = (LONG)noblock;
1695 		Script_Set_Local_Variant("noblock",     &tempvar);
1696 		tempvar.lVal = (LONG)guardcost;
1697 		Script_Set_Local_Variant("guardcost",   &tempvar);
1698 		tempvar.lVal = (LONG)jugglecost;
1699 		Script_Set_Local_Variant("jugglecost",  &tempvar);
1700 		tempvar.lVal = (LONG)pauseadd;
1701 		Script_Set_Local_Variant("pauseadd",    &tempvar);
1702 		Script_Execute(ent->scripts.didblock_script);
1703 		//clear to save variant space
1704 		ScriptVariant_Clear(&tempvar);
1705 		Script_Set_Local_Variant("self",        &tempvar);
1706 		Script_Set_Local_Variant("attacker",    &tempvar);
1707 		Script_Set_Local_Variant("damage",      &tempvar);
1708 		Script_Set_Local_Variant("drop",        &tempvar);
1709 		Script_Set_Local_Variant("attacktype",  &tempvar);
1710 		Script_Set_Local_Variant("noblock",     &tempvar);
1711 		Script_Set_Local_Variant("guardcost",   &tempvar);
1712 		Script_Set_Local_Variant("jugglecost",  &tempvar);
1713 		Script_Set_Local_Variant("pauseadd",    &tempvar);
1714 	}
1715 	pcurrentscript = ptempscript;
1716 }
1717 
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)1718 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)
1719 {
1720 	ScriptVariant tempvar;
1721 	Script* ptempscript = pcurrentscript;
1722 	if(Script_IsInitialized(ent->scripts.ondoattack_script))
1723 	{
1724 		ScriptVariant_Init(&tempvar);
1725 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1726 		tempvar.ptrVal = (VOID*)ent;
1727 		Script_Set_Local_Variant("self",        &tempvar);
1728 		tempvar.ptrVal = (VOID*)other;
1729 		Script_Set_Local_Variant("other",    &tempvar);
1730 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1731 		tempvar.lVal = (LONG)force;
1732 		Script_Set_Local_Variant("damage",      &tempvar);
1733 		tempvar.lVal = (LONG)drop;
1734 		Script_Set_Local_Variant("drop",        &tempvar);
1735 		tempvar.lVal = (LONG)type;
1736 		Script_Set_Local_Variant("attacktype",  &tempvar);
1737 		tempvar.lVal = (LONG)noblock;
1738 		Script_Set_Local_Variant("noblock",     &tempvar);
1739 		tempvar.lVal = (LONG)guardcost;
1740 		Script_Set_Local_Variant("guardcost",   &tempvar);
1741 		tempvar.lVal = (LONG)jugglecost;
1742 		Script_Set_Local_Variant("jugglecost",  &tempvar);
1743 		tempvar.lVal = (LONG)pauseadd;
1744 		Script_Set_Local_Variant("pauseadd",    &tempvar);
1745 		tempvar.lVal = (LONG)iWhich;
1746 		Script_Set_Local_Variant("which",    &tempvar);
1747 		tempvar.lVal = (LONG)iAtkID;
1748 		Script_Set_Local_Variant("attackid",    &tempvar);
1749 		Script_Execute(ent->scripts.ondoattack_script);
1750 		//clear to save variant space
1751 		ScriptVariant_Clear(&tempvar);
1752 		Script_Set_Local_Variant("self",        &tempvar);
1753 		Script_Set_Local_Variant("other",		&tempvar);
1754 		Script_Set_Local_Variant("damage",      &tempvar);
1755 		Script_Set_Local_Variant("drop",        &tempvar);
1756 		Script_Set_Local_Variant("attacktype",  &tempvar);
1757 		Script_Set_Local_Variant("noblock",     &tempvar);
1758 		Script_Set_Local_Variant("guardcost",   &tempvar);
1759 		Script_Set_Local_Variant("jugglecost",  &tempvar);
1760 		Script_Set_Local_Variant("pauseadd",    &tempvar);
1761 		Script_Set_Local_Variant("which",		&tempvar);
1762 		Script_Set_Local_Variant("attackid",	&tempvar);
1763 	}
1764 	pcurrentscript = ptempscript;
1765 }
1766 
execute_updateentity_script(entity * ent)1767 void execute_updateentity_script(entity* ent)
1768 {
1769 	ScriptVariant tempvar;
1770 	Script* ptempscript = pcurrentscript;
1771 	if(Script_IsInitialized(ent->scripts.update_script))
1772 	{
1773 		ScriptVariant_Init(&tempvar);
1774 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1775 		tempvar.ptrVal = (VOID*)ent;
1776 		Script_Set_Local_Variant("self", &tempvar);
1777 		Script_Execute(ent->scripts.update_script);
1778 		//clear to save variant space
1779 		ScriptVariant_Clear(&tempvar);
1780 		Script_Set_Local_Variant("self", &tempvar);
1781 	}
1782 	pcurrentscript = ptempscript;
1783 }
1784 
execute_think_script(entity * ent)1785 void execute_think_script(entity* ent)
1786 {
1787 	ScriptVariant tempvar;
1788 	Script* ptempscript = pcurrentscript;
1789 	if(Script_IsInitialized(ent->scripts.think_script))
1790 	{
1791 		ScriptVariant_Init(&tempvar);
1792 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1793 		tempvar.ptrVal = (VOID*)ent;
1794 		Script_Set_Local_Variant("self", &tempvar);
1795 		Script_Execute(ent->scripts.think_script);
1796 		//clear to save variant space
1797 		ScriptVariant_Clear(&tempvar);
1798 		Script_Set_Local_Variant("self", &tempvar);
1799 	}
1800 	pcurrentscript = ptempscript;
1801 }
1802 
execute_didhit_script(entity * ent,entity * other,int force,int drop,int type,int noblock,int guardcost,int jugglecost,int pauseadd,int blocked)1803 void execute_didhit_script(entity* ent, entity* other, int force, int drop, int type, int noblock, int guardcost, int jugglecost, int pauseadd, int blocked)
1804 {
1805 	ScriptVariant tempvar;
1806 	Script* ptempscript = pcurrentscript;
1807 	if(Script_IsInitialized(ent->scripts.didhit_script))
1808 	{
1809 		ScriptVariant_Init(&tempvar);
1810 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1811 		tempvar.ptrVal = (VOID*)ent;
1812 		Script_Set_Local_Variant("self",        &tempvar);
1813 		tempvar.ptrVal = (VOID*)other;
1814 		Script_Set_Local_Variant("damagetaker", &tempvar);
1815 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1816 		tempvar.lVal = (LONG)force;
1817 		Script_Set_Local_Variant("damage",      &tempvar);
1818 		tempvar.lVal = (LONG)drop;
1819 		Script_Set_Local_Variant("drop",        &tempvar);
1820 		tempvar.lVal = (LONG)type;
1821 		Script_Set_Local_Variant("attacktype",  &tempvar);
1822 		tempvar.lVal = (LONG)noblock;
1823 		Script_Set_Local_Variant("noblock",     &tempvar);
1824 		tempvar.lVal = (LONG)guardcost;
1825 		Script_Set_Local_Variant("guardcost",   &tempvar);
1826 		tempvar.lVal = (LONG)jugglecost;
1827 		Script_Set_Local_Variant("jugglecost",  &tempvar);
1828 		tempvar.lVal = (LONG)pauseadd;
1829 		Script_Set_Local_Variant("pauseadd",    &tempvar);
1830 		tempvar.lVal = (LONG)blocked;
1831 		Script_Set_Local_Variant("blocked",     &tempvar);
1832 		Script_Execute(ent->scripts.didhit_script);
1833 		//clear to save variant space
1834 		ScriptVariant_Clear(&tempvar);
1835 		Script_Set_Local_Variant("self",        &tempvar);
1836 		Script_Set_Local_Variant("damagetaker", &tempvar);
1837 		Script_Set_Local_Variant("damage",      &tempvar);
1838 		Script_Set_Local_Variant("drop",        &tempvar);
1839 		Script_Set_Local_Variant("attacktype",  &tempvar);
1840 		Script_Set_Local_Variant("noblock",     &tempvar);
1841 		Script_Set_Local_Variant("guardcost",   &tempvar);
1842 		Script_Set_Local_Variant("jugglecost",  &tempvar);
1843 		Script_Set_Local_Variant("pauseadd",    &tempvar);
1844 		Script_Set_Local_Variant("blocked",     &tempvar);
1845 	}
1846 	pcurrentscript = ptempscript;
1847 }
1848 
execute_onspawn_script(entity * ent)1849 void execute_onspawn_script(entity* ent)
1850 {
1851 	ScriptVariant tempvar;
1852 	Script* ptempscript = pcurrentscript;
1853 	if(Script_IsInitialized(ent->scripts.onspawn_script))
1854 	{
1855 		ScriptVariant_Init(&tempvar);
1856 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1857 		tempvar.ptrVal = (VOID*)ent;
1858 		Script_Set_Local_Variant("self", &tempvar);
1859 		Script_Execute(ent->scripts.onspawn_script);
1860 		//clear to save variant space
1861 		ScriptVariant_Clear(&tempvar);
1862 		Script_Set_Local_Variant("self", &tempvar);
1863 	}
1864 	pcurrentscript = ptempscript;
1865 }
1866 
execute_entity_key_script(entity * ent)1867 void execute_entity_key_script(entity* ent)
1868 {
1869 	ScriptVariant tempvar;
1870 	Script* ptempscript ;
1871 	if(!ent) return;
1872 	ptempscript = pcurrentscript;
1873 	if(Script_IsInitialized(ent->scripts.key_script))
1874 	{
1875 		ScriptVariant_Init(&tempvar);
1876 		ScriptVariant_ChangeType(&tempvar, VT_PTR);
1877 		tempvar.ptrVal = (VOID*)ent;
1878 		Script_Set_Local_Variant("self",    &tempvar);
1879 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1880 		tempvar.lVal = (LONG)ent->playerindex;
1881 		Script_Set_Local_Variant("player",  &tempvar);
1882 		Script_Execute(ent->scripts.key_script);
1883 		//clear to save variant space
1884 		ScriptVariant_Clear(&tempvar);
1885 		Script_Set_Local_Variant("self",    &tempvar);
1886 		Script_Set_Local_Variant("player",  &tempvar);
1887 	}
1888 	pcurrentscript = ptempscript;
1889 }
1890 
execute_spawn_script(s_spawn_entry * p,entity * e)1891 void execute_spawn_script(s_spawn_entry* p, entity* e)
1892 {
1893 	s_spawn_script_list_node* tempnode = p->spawn_script_list_head;
1894 	ScriptVariant tempvar;
1895 	Script* ptempscript = pcurrentscript;
1896 	while(tempnode)
1897 	{
1898 		pcurrentscript = tempnode->spawn_script;
1899 		if(e)
1900 		{
1901 			ScriptVariant_Init(&tempvar);
1902 			ScriptVariant_ChangeType(&tempvar, VT_PTR);
1903 			tempvar.ptrVal = (VOID*)e;
1904 			Script_Set_Local_Variant("self", &tempvar);
1905 		}
1906 		Script_Execute(tempnode->spawn_script);
1907 		if(e)
1908 		{
1909 			ScriptVariant_Clear(&tempvar);
1910 			Script_Set_Local_Variant("self", &tempvar);
1911 		}
1912 		tempnode = tempnode->next;
1913 	}
1914 	pcurrentscript = ptempscript;
1915 }
1916 
execute_level_key_script(int player)1917 void execute_level_key_script(int player)
1918 {
1919 	ScriptVariant tempvar;
1920 	Script* ptempscript = pcurrentscript;
1921 	if(Script_IsInitialized(&(level->key_script)))
1922 	{
1923 		ScriptVariant_Init(&tempvar);
1924 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1925 		tempvar.lVal = (LONG)player;
1926 		Script_Set_Local_Variant("player", &tempvar);
1927 		Script_Execute(&(level->key_script));
1928 		//clear to save variant space
1929 		ScriptVariant_Clear(&tempvar);
1930 		Script_Set_Local_Variant("player", &tempvar);
1931 	}
1932 	pcurrentscript = ptempscript;
1933 }
1934 
execute_key_script_all(int player)1935 void execute_key_script_all(int player)
1936 {
1937 	ScriptVariant tempvar;
1938 	Script* ptempscript = pcurrentscript;
1939 	if(Script_IsInitialized(&key_script_all))
1940 	{
1941 		ScriptVariant_Init(&tempvar);
1942 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1943 		tempvar.lVal = (LONG)player;
1944 		Script_Set_Local_Variant("player", &tempvar);
1945 		Script_Execute(&key_script_all);
1946 		//clear to save variant space
1947 		ScriptVariant_Clear(&tempvar);
1948 		Script_Set_Local_Variant("player", &tempvar);
1949 	}
1950 	pcurrentscript = ptempscript;
1951 }
1952 
execute_timetick_script(int time,int gotime)1953 void execute_timetick_script(int time, int gotime)
1954 {
1955 	ScriptVariant tempvar;
1956 	Script* ptempscript = pcurrentscript;
1957 	if(Script_IsInitialized(&timetick_script))
1958 	{
1959 		ScriptVariant_Init(&tempvar);
1960 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1961 		tempvar.lVal = (LONG)time;
1962 		Script_Set_Local_Variant("time",    &tempvar);
1963 		tempvar.lVal = (LONG)gotime;
1964 		Script_Set_Local_Variant("gotime", &tempvar);
1965 		Script_Execute(&timetick_script);
1966 		//clear to save variant space
1967 		ScriptVariant_Clear(&tempvar);
1968 		Script_Set_Local_Variant("time",    &tempvar);
1969 		Script_Set_Local_Variant("gotime",  &tempvar);
1970 	}
1971 	pcurrentscript = ptempscript;
1972 }
1973 
execute_loading_script(int value,int max)1974 void execute_loading_script(int value, int max)
1975 {
1976 	ScriptVariant tempvar;
1977 	Script* ptempscript = pcurrentscript;
1978 	if(Script_IsInitialized(&loading_script))
1979 	{
1980 		ScriptVariant_Init(&tempvar);
1981 		ScriptVariant_ChangeType(&tempvar, VT_INTEGER);
1982 		tempvar.lVal = (LONG)value;
1983 		Script_Set_Local_Variant("value",    &tempvar);
1984 		tempvar.lVal = (LONG)max;
1985 		Script_Set_Local_Variant("max", &tempvar);
1986 		Script_Execute(&loading_script);
1987 		//clear to save variant space
1988 		ScriptVariant_Clear(&tempvar);
1989 		Script_Set_Local_Variant("value",    &tempvar);
1990 		Script_Set_Local_Variant("max",  &tempvar);
1991 	}
1992 	pcurrentscript = ptempscript;
1993 }
1994 
execute_key_script(int index)1995 void execute_key_script(int index)
1996 {
1997 	Script* ptempscript = pcurrentscript;
1998 	if(Script_IsInitialized(&key_script[index]))
1999 	{
2000 		Script_Execute(&key_script[index]);
2001 	}
2002 	pcurrentscript = ptempscript;
2003 }
2004 
execute_join_script(int index)2005 void execute_join_script(int index)
2006 {
2007 	Script* ptempscript = pcurrentscript;
2008 	if(Script_IsInitialized(&join_script[index]))
2009 	{
2010 		Script_Execute(&join_script[index]);
2011 	}
2012 	pcurrentscript = ptempscript;
2013 }
2014 
execute_respawn_script(int index)2015 void execute_respawn_script(int index)
2016 {
2017 	Script* ptempscript = pcurrentscript;
2018 	if(Script_IsInitialized(&respawn_script[index]))
2019 	{
2020 		Script_Execute(&respawn_script[index]);
2021 	}
2022 	pcurrentscript = ptempscript;
2023 }
2024 
execute_pdie_script(int index)2025 void execute_pdie_script(int index)
2026 {
2027 	Script* ptempscript = pcurrentscript;
2028 	if(Script_IsInitialized(&pdie_script[index]))
2029 	{
2030 		Script_Execute(&pdie_script[index]);
2031 	}
2032 	pcurrentscript = ptempscript;
2033 }
2034 
2035 // ------------------------ Save/load -----------------------------
2036 
clearsettings()2037 void clearsettings()
2038 {
2039 	savedata.compatibleversion = COMPATIBLEVERSION;
2040 	savedata.gamma = 0;
2041 	savedata.brightness = 0;
2042 	savedata.usesound = 1;
2043 	savedata.soundrate = 44100;
2044 	savedata.soundbits = 16;
2045 	savedata.soundvol = 15;
2046 	savedata.usemusic = 1;
2047 	savedata.musicvol = 100;
2048 	savedata.effectvol = 120;
2049 	savedata.usejoy = 1;
2050 	savedata.mode = 0;
2051 	savedata.showtitles = 0;
2052 	savedata.windowpos = 0;
2053 	savedata.logo = 0;
2054 	savedata.uselog = 1;
2055 	savedata.debuginfo = 0;
2056 	savedata.fullscreen = 0;
2057 	savedata.stretch = 0;
2058 
2059 #ifdef SDL
2060 	savedata.usegl[0] = 0;
2061 	savedata.usegl[1] = 1;
2062 	savedata.glscale = 1.0;
2063 	savedata.glfilter[0] = 1;
2064 	savedata.glfilter[1] = 0;
2065 #endif
2066 
2067 	savedata.screen[0][0] = 0; savedata.screen[0][1] = 0;
2068 	savedata.screen[1][0] = 0; savedata.screen[1][1] = 0;
2069 	savedata.screen[2][0] = 0; savedata.screen[2][1] = 0;
2070 	savedata.screen[3][0] = 0; savedata.screen[3][1] = 0;
2071 	savedata.screen[4][0] = 0; savedata.screen[4][1] = 0;
2072 	savedata.screen[5][0] = 0; savedata.screen[5][1] = 0;
2073 	savedata.screen[6][0] = 0; savedata.screen[6][1] = 0;
2074 
2075 #ifdef PSP
2076 	savedata.screen[1][0] = 3;
2077 	savedata.pspcpuspeed = 2;
2078 	savedata.overscan[0] = 0;
2079 	savedata.overscan[1] = 0;
2080 	savedata.overscan[2] = 0;
2081 	savedata.overscan[3] = 0;
2082 #endif
2083 
2084 	savedata.keys[0][SDID_MOVEUP]    = CONTROL_DEFAULT1_UP;
2085 	savedata.keys[0][SDID_MOVEDOWN]  = CONTROL_DEFAULT1_DOWN;
2086 	savedata.keys[0][SDID_MOVELEFT]  = CONTROL_DEFAULT1_LEFT;
2087 	savedata.keys[0][SDID_MOVERIGHT] = CONTROL_DEFAULT1_RIGHT;
2088 	savedata.keys[0][SDID_ATTACK]    = CONTROL_DEFAULT1_FIRE1;
2089 	savedata.keys[0][SDID_ATTACK2]   = CONTROL_DEFAULT1_FIRE2;
2090 	savedata.keys[0][SDID_ATTACK3]   = CONTROL_DEFAULT1_FIRE3;
2091 	savedata.keys[0][SDID_ATTACK4]   = CONTROL_DEFAULT1_FIRE4;
2092 	savedata.keys[0][SDID_JUMP]      = CONTROL_DEFAULT1_FIRE5;
2093 	savedata.keys[0][SDID_SPECIAL]   = CONTROL_DEFAULT1_FIRE6;
2094 	savedata.keys[0][SDID_START]     = CONTROL_DEFAULT1_START;
2095 	savedata.keys[0][SDID_SCREENSHOT]= CONTROL_DEFAULT1_SCREENSHOT;
2096 
2097 	savedata.keys[1][SDID_MOVEUP]    = CONTROL_DEFAULT2_UP;
2098 	savedata.keys[1][SDID_MOVEDOWN]  = CONTROL_DEFAULT2_DOWN;
2099 	savedata.keys[1][SDID_MOVELEFT]  = CONTROL_DEFAULT2_LEFT;
2100 	savedata.keys[1][SDID_MOVERIGHT] = CONTROL_DEFAULT2_RIGHT;
2101 	savedata.keys[1][SDID_ATTACK]    = CONTROL_DEFAULT2_FIRE1;
2102 	savedata.keys[1][SDID_ATTACK2]   = CONTROL_DEFAULT2_FIRE2;
2103 	savedata.keys[1][SDID_ATTACK3]   = CONTROL_DEFAULT2_FIRE3;
2104 	savedata.keys[1][SDID_ATTACK4]   = CONTROL_DEFAULT2_FIRE4;
2105 	savedata.keys[1][SDID_JUMP]      = CONTROL_DEFAULT2_FIRE5;
2106 	savedata.keys[1][SDID_SPECIAL]   = CONTROL_DEFAULT2_FIRE6;
2107 	savedata.keys[1][SDID_START]     = CONTROL_DEFAULT2_START;
2108 	savedata.keys[1][SDID_SCREENSHOT]= CONTROL_DEFAULT2_SCREENSHOT;
2109 
2110 	savedata.keys[2][SDID_MOVEUP]    = CONTROL_DEFAULT3_UP;
2111 	savedata.keys[2][SDID_MOVEDOWN]  = CONTROL_DEFAULT3_DOWN;
2112 	savedata.keys[2][SDID_MOVELEFT]  = CONTROL_DEFAULT3_LEFT;
2113 	savedata.keys[2][SDID_MOVERIGHT] = CONTROL_DEFAULT3_RIGHT;
2114 	savedata.keys[2][SDID_ATTACK]    = CONTROL_DEFAULT3_FIRE1;
2115 	savedata.keys[2][SDID_ATTACK2]   = CONTROL_DEFAULT3_FIRE2;
2116 	savedata.keys[2][SDID_ATTACK3]   = CONTROL_DEFAULT3_FIRE3;
2117 	savedata.keys[2][SDID_ATTACK4]   = CONTROL_DEFAULT3_FIRE4;
2118 	savedata.keys[2][SDID_JUMP]      = CONTROL_DEFAULT3_FIRE5;
2119 	savedata.keys[2][SDID_SPECIAL]   = CONTROL_DEFAULT3_FIRE6;
2120 	savedata.keys[2][SDID_START]     = CONTROL_DEFAULT3_START;
2121 	savedata.keys[2][SDID_SCREENSHOT]= CONTROL_DEFAULT3_SCREENSHOT;
2122 
2123 	savedata.keys[3][SDID_MOVEUP]    = CONTROL_DEFAULT4_UP;
2124 	savedata.keys[3][SDID_MOVEDOWN]  = CONTROL_DEFAULT4_DOWN;
2125 	savedata.keys[3][SDID_MOVELEFT]  = CONTROL_DEFAULT4_LEFT;
2126 	savedata.keys[3][SDID_MOVERIGHT] = CONTROL_DEFAULT4_RIGHT;
2127 	savedata.keys[3][SDID_ATTACK]    = CONTROL_DEFAULT4_FIRE1;
2128 	savedata.keys[3][SDID_ATTACK2]   = CONTROL_DEFAULT4_FIRE2;
2129 	savedata.keys[3][SDID_ATTACK3]   = CONTROL_DEFAULT4_FIRE3;
2130 	savedata.keys[3][SDID_ATTACK4]   = CONTROL_DEFAULT4_FIRE4;
2131 	savedata.keys[3][SDID_JUMP]      = CONTROL_DEFAULT4_FIRE5;
2132 	savedata.keys[3][SDID_SPECIAL]   = CONTROL_DEFAULT4_FIRE6;
2133 	savedata.keys[3][SDID_START]     = CONTROL_DEFAULT4_START;
2134 	savedata.keys[3][SDID_SCREENSHOT]= CONTROL_DEFAULT4_SCREENSHOT;
2135 }
2136 
2137 
savesettings()2138 void savesettings(){
2139 #ifndef DC
2140 	int disCcWarns;
2141 	FILE *handle = NULL;
2142 	char path[128] = {""};
2143 	char tmpname[128] = {""};
2144 	getBasePath(path, "Saves", 0);
2145 	getPakName(tmpname, 4);
2146 	strcat(path, tmpname);
2147 	handle = fopen(path, "wb");
2148 	if(handle==NULL) return;
2149 	disCcWarns = fwrite(&savedata, 1, sizeof(s_savedata), handle);
2150 	fclose(handle);
2151 #endif
2152 }
2153 
saveasdefault()2154 void saveasdefault(){
2155 #ifndef DC
2156 	int disCcWarns;
2157 	FILE *handle = NULL;
2158 	char path[128] = {""};
2159 	getBasePath(path, "Saves", 0);
2160 	strncat(path, "default.cfg", 128);
2161 	handle = fopen(path, "wb");
2162 	if(handle==NULL) return;
2163 	disCcWarns = fwrite(&savedata, 1, sizeof(s_savedata), handle);
2164 	fclose(handle);
2165 #endif
2166 }
2167 
2168 
loadsettings()2169 void loadsettings(){
2170 #ifndef DC
2171 	int disCcWarns;
2172 	FILE *handle = NULL;
2173 	char path[128] = {""};
2174 	char tmpname[128] = {""};
2175 	getBasePath(path, "Saves", 0);
2176 	getPakName(tmpname, 4);
2177 	strcat(path, tmpname);
2178 	if(!(fileExists(path)))
2179 	{
2180 		loadfromdefault();
2181 		return;
2182 	}
2183 	clearsettings();
2184 	handle = fopen(path, "rb");
2185 	if(handle == NULL) return;
2186 	disCcWarns = fread(&savedata, 1, sizeof(s_savedata), handle);
2187 	fclose(handle);
2188 	if(savedata.compatibleversion != COMPATIBLEVERSION) clearsettings();
2189 #else
2190 	clearsettings();
2191 #endif
2192 }
2193 
loadfromdefault()2194 void loadfromdefault(){
2195 #ifndef DC
2196 	int disCcWarns;
2197 	FILE *handle = NULL;
2198 	char path[128] = {""};
2199 	getBasePath(path, "Saves", 0);
2200 	strncat(path, "default.cfg", 128);
2201 	clearsettings();
2202 	handle = fopen(path, "rb");
2203 	if(handle == NULL) return;
2204 	disCcWarns = fread(&savedata, 1, sizeof(s_savedata), handle);
2205 	fclose(handle);
2206 	if(savedata.compatibleversion != COMPATIBLEVERSION) clearsettings();
2207 #else
2208 	clearsettings();
2209 #endif
2210 }
2211 
2212 
2213 
2214 
clearSavedGame()2215 void clearSavedGame(){
2216 	int i;
2217 
2218 	for(i=0; i<MAX_DIFFICULTIES; i++){
2219 		memset(savelevel+i, 0, sizeof(s_savelevel));
2220 		savelevel[i].compatibleversion = CV_SAVED_GAME;
2221 	}
2222 }
2223 
2224 
2225 
clearHighScore()2226 void clearHighScore(){
2227 	savescore.compatibleversion = CV_HIGH_SCORE;
2228 	savescore.highsc[0] = 0;    // Resets all the highscores to 0
2229 	savescore.highsc[1] = 0;
2230 	savescore.highsc[2] = 0;
2231 	savescore.highsc[3] = 0;
2232 	savescore.highsc[4] = 0;
2233 	savescore.highsc[5] = 0;
2234 	savescore.highsc[6] = 0;
2235 	savescore.highsc[7] = 0;
2236 	savescore.highsc[8] = 0;
2237 	savescore.highsc[9] = 0;
2238 	strcpy(savescore.hscoren[0], "None");    // Resets all the highscore names to "None"
2239 	strcpy(savescore.hscoren[1], "None");
2240 	strcpy(savescore.hscoren[2], "None");
2241 	strcpy(savescore.hscoren[3], "None");
2242 	strcpy(savescore.hscoren[4], "None");
2243 	strcpy(savescore.hscoren[5], "None");
2244 	strcpy(savescore.hscoren[6], "None");
2245 	strcpy(savescore.hscoren[7], "None");
2246 	strcpy(savescore.hscoren[8], "None");
2247 	strcpy(savescore.hscoren[9], "None");
2248 }
2249 
2250 
2251 
saveGameFile()2252 void saveGameFile(){
2253 #ifndef DC
2254 	int disCcWarns;
2255 	FILE *handle = NULL;
2256 	char path[256] = {""};
2257 	char tmpname[256] = {""};
2258 	getBasePath(path, "Saves", 0);
2259 	getPakName(tmpname, 0);
2260 	strcat(path, tmpname);
2261 	//if(!savelevel[saveslot].level) return;
2262 	handle = fopen(path, "wb");
2263 	if(handle == NULL) return;
2264 	disCcWarns = fwrite(&savelevel, sizeof(s_savelevel), MAX_DIFFICULTIES, handle);
2265 	fclose(handle);
2266 #endif
2267 }
2268 
2269 
loadGameFile()2270 int loadGameFile(){
2271 #ifndef DC
2272 	int disCcWarns;
2273 	FILE *handle = NULL;
2274 	int i;
2275 	char path[256] = {""};
2276 	char tmpname[256] = {""};
2277 	getBasePath(path, "Saves", 0);
2278 	getPakName(tmpname, 0);
2279 	strcat(path,tmpname);
2280 	handle = fopen(path, "rb");
2281 	if(handle == NULL) return 0;
2282 	disCcWarns = fread(&savelevel, sizeof(s_savelevel), MAX_DIFFICULTIES, handle);
2283 	fclose(handle);
2284 	for(i=0; i<MAX_DIFFICULTIES; i++) if(savelevel[i].compatibleversion != CV_SAVED_GAME) clearSavedGame();
2285 	return 1;
2286 #else
2287 	clearSavedGame();
2288 	return 0;
2289 #endif
2290 }
2291 
2292 
saveHighScoreFile()2293 void saveHighScoreFile(){
2294 #ifndef DC
2295 	int disCcWarns;
2296 	FILE *handle = NULL;
2297 	char path[256] = {""};
2298 	char tmpname[256] = {""};
2299 	getBasePath(path, "Saves", 0);
2300 	getPakName(tmpname, 1);
2301 	strcat(path, tmpname);
2302 	handle = fopen(path, "wb");
2303 	if(handle == NULL) return;
2304 	disCcWarns = fwrite(&savescore, 1, sizeof(s_savescore), handle);
2305 	fclose(handle);
2306 #endif
2307 }
2308 
2309 
loadHighScoreFile()2310 void loadHighScoreFile(){
2311 #ifndef DC
2312 	int disCcWarns;
2313 	FILE *handle = NULL;
2314 	char path[256] = {""};
2315 	char tmpname[256] = {""};
2316 	getBasePath(path, "Saves", 0);
2317 	getPakName(tmpname, 1);
2318 	strcat(path,tmpname);
2319 	clearHighScore();
2320 	handle = fopen(path, "rb");
2321 	if(handle == NULL) return;
2322 	disCcWarns = fread(&savescore, 1, sizeof(s_savescore), handle);
2323 	fclose(handle);
2324 	if(savescore.compatibleversion != CV_HIGH_SCORE) clearHighScore();
2325 #else
2326 	clearHighScore();
2327 #endif
2328 }
2329 
2330 
2331 #ifndef DC
vardump(ScriptVariant * var,char buffer[])2332 static void vardump(ScriptVariant *var, char buffer[])
2333 {
2334 	char* tmpstr;
2335 	int l, t, c;
2336 	buffer[0] = 0;
2337 	switch(var->vt)
2338 	{
2339 
2340 	case VT_STR:
2341 		strcpy(buffer, "\"");
2342 		tmpstr = StrCache_Get(var->strVal);
2343 		l = strlen(tmpstr);
2344 		for(c=0; c<l; c++){
2345 			if(tmpstr[c]=='\n'){
2346 				strcat(buffer, "\\n");
2347 			}else if(tmpstr[c]=='\r'){
2348 				strcat(buffer, "\\r");
2349 			}else if(tmpstr[c]=='\\'){
2350 				strcat(buffer, "\\\\");
2351 			}else{
2352 				t = strlen(buffer);
2353 				buffer[t] = tmpstr[c];
2354 				buffer[t+1] = 0;
2355 			}
2356 		}
2357 		strcat(buffer, "\"");
2358 		break;
2359 	case VT_DECIMAL:
2360 		sprintf(buffer, "%lf", (double)var->dblVal);
2361 		break;
2362 	case VT_INTEGER:
2363 		sprintf(buffer, "%ld", (long)var->lVal);
2364 		break;
2365 	default:
2366 		strcpy(buffer, "NULL()");
2367 		break;
2368 	}
2369 }
2370 
2371 #endif
2372 
2373 
saveScriptFile()2374 void saveScriptFile()
2375 {
2376 #ifndef DC
2377 	#define _writestr(v) fwrite(v, strlen(v), 1, handle);
2378 	#define _writetmp  _writestr(tmpvalue)
2379 	#define _writeconst(s) strcpy(tmpvalue,s);_writetmp
2380 	FILE *handle = NULL;
2381 	int i, l;
2382 	char path[256] = {""};
2383 	char tmpvalue[256] = {""};
2384 	//named list
2385 	//if(max_global_vars<=0) return ;
2386 	getBasePath(path, "Saves", 0);
2387 	getPakName(tmpvalue, 2);//.scr
2388 	strcat(path, tmpvalue);
2389 	l = strlen(path); //s00, s01, s02 etc
2390 	path[l-2] = '0'+(current_set/10);
2391 	path[l-1] = '0'+(current_set%10);
2392 	handle = fopen(path, "wb");
2393 	if(handle == NULL) return;
2394 
2395 	_writeconst("void main() {\n");
2396 	for(i=0; i<=max_global_var_index; i++)
2397 	{
2398 		if(!global_var_list[i]->owner &&
2399 			global_var_list[i]->key[0] &&
2400 			global_var_list[i]->value.vt!=VT_EMPTY &&
2401 			global_var_list[i]->value.vt!=VT_PTR){
2402 			_writeconst("\tsetglobalvar(\"")
2403 			_writestr(global_var_list[i]->key)
2404 			_writeconst("\",")
2405 			vardump(&(global_var_list[i]->value), tmpvalue);
2406 			_writetmp
2407 			_writeconst(");\n")
2408 		}
2409 	}
2410 	// indexed list
2411 	for(i=0; i<max_indexed_vars; i++) {
2412 		if(indexed_var_list[i].vt != VT_PTR && indexed_var_list[i].vt!=VT_EMPTY){
2413 			_writeconst("\tsetindexedvar(")
2414 			sprintf(tmpvalue, "%d", i);
2415 			_writetmp
2416 			_writeconst(",")
2417 			vardump(indexed_var_list+i, tmpvalue);
2418 			_writetmp
2419 			_writeconst(");\n")
2420 		}
2421 
2422 	}
2423 	_writeconst("}\n");
2424 
2425 	fclose(handle);
2426 	#undef _writestr
2427 	#undef _writetmp
2428 	#undef _writeconst
2429 #endif
2430 }
2431 
2432 
loadScriptFile()2433 void loadScriptFile(){
2434 #ifndef DC
2435 	Script script;
2436 	Script* ptempscript = pcurrentscript;
2437 
2438 	ptrdiff_t l;
2439 
2440 	char path[256] = {""};
2441 	char tmpname[256] = {""};
2442 	//named list
2443 	//if(max_global_vars<=0) return ;
2444 	getBasePath(path, "Saves", 0);
2445 	getPakName(tmpname, 2);//.scr
2446 	strcat(path,tmpname);
2447 	l = strlen(path); //s00, s01, s02 etc
2448 	path[l-2] = '0'+(current_set/10);
2449 	path[l-1] = '0'+(current_set%10);
2450 
2451 	Script_Init(&script, "loadScriptFile", 1);
2452 	if(!load_script(&script, path))   Script_Clear(&script, 2);
2453 	Script_Compile(&script);
2454 	if(Script_IsInitialized(&script))
2455 		Script_Execute(&script);
2456 	pcurrentscript = ptempscript;
2457 	Script_Clear(&script, 2);
2458 #endif
2459 }
2460 
2461 // ----------------------- Sound ------------------------------
2462 
music(char * filename,int loop,long offset)2463 int music(char *filename, int loop, long offset)
2464 {
2465 	char t[64];
2466 	char a[64];
2467 	int res = 1;
2468 	if(!savedata.usemusic) return 0;
2469 	if(!sound_open_music(filename, packfile, savedata.musicvol, loop, offset)) {
2470 		printf("\nCan't play music file '%s'\n", filename);
2471 		res = 0;
2472 	}
2473 	if(savedata.showtitles && sound_query_music(a,t))
2474 	{
2475 		if(a[0] && t[0]) debug_printf("Playing \"%s\" by %s", t, a);
2476 		else if(a[0]) debug_printf("Playing unknown song by %s", a);
2477 		else if(t[0]) debug_printf("Playing \"%s\" by unknown artist", t);
2478 		else debug_printf("");
2479 	}
2480 	return res;
2481 }
2482 
check_music()2483 void check_music(){
2484 	if(musicfade[1] > 0)
2485 	{
2486 		musicfade[1] -= musicfade[0];
2487 		sound_volume_music((int)musicfade[1], (int)musicfade[1]);
2488 	}
2489 	else if(musicname[0])
2490 	{
2491 		sound_volume_music(savedata.musicvol, savedata.musicvol);
2492 		music(musicname, musicloop, musicoffset);
2493 		musicname[0] = 0;
2494 	}
2495 }
2496 
2497 // ----------------------- General ------------------------------
2498 // atof and atoi return a valid number, if only the first char is one.
2499 // so we only check that.
isNumeric(char * text)2500 int isNumeric(char* text) {
2501 	char* p = text;
2502 	assert(p);
2503 	if(!*p) return 0;
2504 	switch(*p) {
2505 		case '-': case '+':
2506 			p++;
2507 			break;
2508 		default:
2509 			break;
2510 	}
2511 	switch (*p) {
2512 		case '0': case '1': case '2': case '3': case '4':
2513 		case '5': case '6': case '7': case '8': case '9':
2514 			return 1;
2515 		default:
2516 			return 0;
2517 	}
2518 	return 1;
2519 }
2520 
2521 
getValidInt(char * text,char * file,char * cmd)2522 int getValidInt(char* text, char* file, char* cmd)  {
2523 	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";
2524 	if(!text || !*text) return 0;
2525 	if(isNumeric(text)) {
2526 		return atoi(text);
2527 	} else {
2528 		printf(WARN_NUMBER_EXPECTED, file, cmd, text);
2529 		return 0;
2530 	}
2531 
2532 }
2533 
getValidFloat(char * text,char * file,char * cmd)2534 float getValidFloat(char* text, char* file, char* cmd)  {
2535 	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";
2536 	if(!text || !*text) return 0.0f;
2537 	if(isNumeric(text)) {
2538 		if(text[strlen(text)-1]=='%')
2539 			return atof(text)/100.0f;
2540 		return atof(text);
2541 	} else {
2542 		printf(WARN_NUMBER_EXPECTED, file, cmd, text);
2543 		return 0.0f;
2544 	}
2545 }
2546 
ParseArgs(ArgList * list,char * input,char * output)2547 size_t ParseArgs(ArgList* list, char* input, char* output) {
2548 	assert(list);
2549 	assert(input);
2550 	assert(output);
2551 	//static const char diff = 'a' - 'A';
2552 
2553 	size_t pos = 0;
2554 	size_t wordstart = 0;
2555 	size_t item = 0;
2556 	int done = 0;
2557 	int space = 0;
2558 	//int makelower = 0;
2559 
2560 	while(pos < MAX_ARG_LEN-1 && item < 18) {
2561 		switch(input[pos]) {
2562 			case '\r': case '\n': case '#': case '\0':
2563 				done = 1;
2564 			case ' ': case '\t':
2565 				output[pos] = '\0';
2566 				if(!space && wordstart != pos) {
2567 					list->args[item] = output + wordstart;
2568 					list->arglen[item] = pos - wordstart;
2569 					item++;
2570 				}
2571 				space = 1;
2572 				break; /*
2573 			case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I':
2574 			case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
2575 			case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
2576 				makelower = 1; */
2577 
2578 			default:
2579 				if(space)
2580 					wordstart = pos;
2581 				/*output[pos] = makelower ? input[pos] + diff : input[pos];*/
2582 				output[pos] = input[pos];
2583 				space = 0;
2584 				//makelower = 0;
2585 		}
2586 		if(done)
2587 			break;
2588 		pos++;
2589 	}
2590 	list->count = item;
2591 	return item;
2592 }
2593 
findarg(char * command,int which)2594 char *findarg(char *command, int which){
2595 	static const char comment_mark[4] = {"#"};
2596 	int d;
2597 	int argc;
2598 	int inarg;
2599 	int argstart;
2600 	static char arg[MAX_ARG_LEN];
2601 
2602 
2603 	// Copy the command line, replacing spaces by zeroes,
2604 	// finally returning a pointer to the requested arg.
2605 	d = 0;
2606 	inarg = 0;
2607 	argstart = 0;
2608 	argc = -1;
2609 
2610 	while(d<MAX_ARG_LEN-1 && command[d]){
2611 		// Zero out whitespace
2612 		if(command[d]==' ' || command[d]=='\t'){
2613 			arg[d] = 0;
2614 			inarg = 0;
2615 			if(argc == which) return arg + argstart;
2616 		}
2617 		else if(command[d]==0 || command[d]=='\n' || command[d]=='\r' ||
2618 			strncmp(command+d, comment_mark, strlen(comment_mark))==0){
2619 				// End of line
2620 				arg[d] = 0;
2621 				if(argc == which) return arg + argstart;
2622 				return arg + d;
2623 			}
2624 		else{
2625 			if(!inarg){
2626 				// if(argc==-1 && command[d]=='#') return arg;
2627 				inarg = 1;
2628 				argstart = d;
2629 				argc++;
2630 			}
2631 			arg[d] = command[d];
2632 		}
2633 		++d;
2634 	}
2635 
2636 	return arg;
2637 }
2638 
2639 
2640 
2641 
diff(float a,float b)2642 float diff(float a, float b){
2643 	if(a<b) return b-a;
2644 	return a-b;
2645 }
2646 
2647 
2648 
inair(entity * e)2649 int inair(entity *e)
2650 {
2651 	return (diff(e->a, e->base) >= 0.1);
2652 }
2653 
2654 
2655 
randf(float max)2656 float randf(float max){
2657 	float f;
2658 	if(max==0) return 0;
2659 	f = (float)(rand32()%1000);
2660 	f /= (1000/max);
2661 	return f;
2662 }
2663 
2664 
2665 
2666 // ----------------------- Loaders ------------------------------
2667 
2668 
2669 // Creates a remapping table from two images
load_colourmap(s_model * model,char * image1,char * image2)2670 int load_colourmap(s_model * model, char *image1, char *image2)
2671 {
2672 	int i, j, k;
2673 	unsigned char *map = NULL;
2674 	s_bitmap *bitmap1 = NULL;
2675 	s_bitmap *bitmap2 = NULL;
2676 
2677 	// Can't use same image twice!
2678 	if(stricmp(image1,image2)==0) return 0;
2679 
2680 	// Find an empty slot... ;)
2681 	for(k=0; k<MAX_COLOUR_MAPS && model->colourmap[k]; k++);
2682 	if(k>=MAX_COLOUR_MAPS) return -1;
2683 
2684 	if((map = malloc(MAX_PAL_SIZE/4)) == NULL)
2685 	{
2686 		return -2;
2687 	}
2688 	if((bitmap1 = loadbitmap(image1, packfile, PIXEL_8)) == NULL)
2689 	{
2690 		free(map);
2691 		map = NULL;
2692 		return -3;
2693 	}
2694 	if((bitmap2 = loadbitmap(image2, packfile, PIXEL_8)) == NULL)
2695 	{
2696 		freebitmap(bitmap1);
2697 		free(map);
2698 		map = NULL;
2699 		return -4;
2700 	}
2701 
2702 	// Create the colour map
2703 	for(i=0;i<MAX_PAL_SIZE/4;i++) map[i] = i;
2704 	for(j=0; j<bitmap1->height && j<bitmap2->height; j++)
2705 	{
2706 		for(i=0; i<bitmap1->width && i<bitmap2->width; i++)
2707 		{
2708 			map[(unsigned)(bitmap1->data[j*bitmap1->width+i])] = bitmap2->data[j*bitmap2->width+i];
2709 		}
2710 	}
2711 
2712 	freebitmap(bitmap1);
2713 	freebitmap(bitmap2);
2714 
2715 	model->colourmap[k] = map;
2716 	model->maps_loaded = k + 1;
2717 	return 1;
2718 }
2719 
2720 //PIXEL_x8
2721 // This function is used to enable remap command in 24bit mode
2722 // So old mods can still run under 16/24/32bit color system
2723 // This function should be called when all colourmaps are loaded, e.g.,
2724 // at the end of load_cached_model
2725 // map flag is used to determine whether a colourmap is a real colourmap
convert_map_to_palette(s_model * model,unsigned char mapflag[])2726 int convert_map_to_palette(s_model* model, unsigned char mapflag[])
2727 {
2728 	int i, c;
2729 	unsigned char *newmap, *oldmap;
2730 	unsigned char *p1, *p2;
2731 	unsigned pb = pixelbytes[(int)screenformat];
2732 	if(model->palette==NULL) return 0;
2733 	for(c=0; c<model->maps_loaded; c++)
2734 	{
2735 		if(mapflag[c]==0) continue;
2736 		if((newmap = malloc(PAL_BYTES)) == NULL)
2737 		{
2738 			shutdown(1, "Error convert_map_to_palette for model: %s\n", model->name);
2739 		}
2740 		// Create new colour map
2741 		memcpy(newmap, model->palette, PAL_BYTES);
2742 		oldmap = model->colourmap[c];
2743 		for(i=0; i<MAX_PAL_SIZE/4; i++)
2744 		{
2745 			if(oldmap[i]==i) continue;
2746 			p1 = newmap + i*pb;
2747 			p2 = model->palette + oldmap[i]*pb;
2748 			memcpy(p1, p2, pb);
2749 		}
2750 		model->colourmap[c] = newmap;
2751 		free(oldmap); oldmap = NULL;
2752 	}
2753 	return 1;
2754 }
2755 
_load_palette16(unsigned char * palette,char * filename)2756 static int _load_palette16(unsigned char* palette, char* filename)
2757 {
2758 	int handle, i;
2759 	unsigned char tp[3];
2760 	handle = openpackfile(filename, packfile);
2761 	if(handle <0) return 0;
2762 	memset(palette, 0, MAX_PAL_SIZE/2);
2763 	for(i=0; i<MAX_PAL_SIZE/4; i++)
2764 	{
2765 		if(readpackfile(handle, tp, 3) != 3)
2766 		{
2767 			closepackfile(handle);
2768 			return 0;
2769 		}
2770 		((unsigned short*)palette)[i] = colour16(tp[0], tp[1], tp[2]);
2771 	}
2772 	closepackfile(handle);
2773 	*(unsigned short*)palette = 0;
2774 
2775 	return 1;
2776 }
2777 
2778 
_load_palette32(unsigned char * palette,char * filename)2779 static int _load_palette32(unsigned char* palette, char* filename)
2780 {
2781 	int handle, i;
2782 	unsigned* dp;
2783 	unsigned char tpal[3];
2784 	handle = openpackfile(filename, packfile);
2785 	if(handle <0) return 0;
2786 	memset(palette, 0, MAX_PAL_SIZE);
2787 	dp = (unsigned*)palette;
2788 	for(i=0; i<MAX_PAL_SIZE/4; i++)
2789 	{
2790 		if(readpackfile(handle, tpal, 3) != 3)
2791 		{
2792 			closepackfile(handle);
2793 			return 0;
2794 		}
2795 		dp[i] = colour32(tpal[0],tpal[1],tpal[2]);
2796 
2797 	}
2798 	closepackfile(handle);
2799 	dp[0] = 0;
2800 
2801 	return 1;
2802 }
2803 
2804 //load a 256 colors' palette
load_palette(unsigned char * palette,char * filename)2805 int load_palette(unsigned char* palette, char* filename)
2806 {
2807 	int handle;
2808 	if(screenformat==PIXEL_32)
2809 		return _load_palette32(palette, filename);
2810 	else if(screenformat==PIXEL_16)
2811 		return _load_palette16(palette, filename);
2812 
2813 	handle = openpackfile(filename, packfile);
2814 	if(handle <0) return 0;
2815 	if(readpackfile(handle, palette, 768) != 768){
2816 		closepackfile(handle);
2817 		return 0;
2818 	}
2819 	closepackfile(handle);
2820 	palette[0] = palette[1] = palette[2] = 0;
2821 
2822 	return 1;
2823 }
2824 
2825 // create blending tables for the palette
create_blending_tables(unsigned char * palette,unsigned char * tables[],int usemap[])2826 int create_blending_tables(unsigned char* palette, unsigned char* tables[], int usemap[])
2827 {
2828 	int i;
2829 	if(pixelformat!=PIXEL_8) return 1;
2830 	if(!palette || !tables) return 0;
2831 
2832 	memset(tables, 0, MAX_BLENDINGS*sizeof(unsigned char*));
2833 	for(i=0; i<MAX_BLENDINGS; i++)
2834 	{
2835 		if(!usemap || usemap[i])
2836 		{
2837 			tables[i] = (blending_table_functions[i])(palette);
2838 			if(!tables[i]) return 0;
2839 		}
2840 	}
2841 
2842 	return 1;
2843 }
2844 
create_blend_tables_x8(unsigned char * tables[])2845 void create_blend_tables_x8(unsigned char* tables[]){
2846 	int i;
2847 	for(i=0; i<MAX_BLENDINGS; i++){
2848 		switch(screenformat){
2849 		case PIXEL_16:
2850 			tables[i] = (blending_table_functions16[i])();
2851 			break;
2852 		case PIXEL_32:
2853 			tables[i] = (blending_table_functions32[i])();
2854 			break;
2855 		}
2856 	}
2857 
2858 }
2859 
2860 
2861 //change system palette by index
change_system_palette(int palindex)2862 void change_system_palette(int palindex)
2863 {
2864 	if(palindex < 0) palindex = 0;
2865 	//if(current_palette == palindex ) return;
2866 
2867 
2868 	if(!level || palindex == 0 || palindex > level->numpalettes)
2869 	{
2870 		current_palette = 0;
2871 		if(screenformat==PIXEL_8)
2872 		{
2873 			palette_set_corrected(pal, savedata.gamma,savedata.gamma,savedata.gamma, savedata.brightness,savedata.brightness,savedata.brightness);
2874 			set_blendtables(blendings); // set global blending tables
2875 		}
2876 	}
2877 	else if(level)
2878 	{
2879 		current_palette = palindex;
2880 		if(screenformat==PIXEL_8)
2881 		{
2882 			palette_set_corrected(level->palettes[palindex-1], savedata.gamma,savedata.gamma,savedata.gamma, savedata.brightness,savedata.brightness,savedata.brightness);
2883 			set_blendtables(level->blendings[palindex-1]);
2884 		}
2885 	}
2886 }
2887 
2888 // Load colour 0-127 from data/pal.act
standard_palette(int immediate)2889 void standard_palette(int immediate){
2890 	unsigned char* pp[MAX_PAL_SIZE] = {0};
2891 	if(load_palette((unsigned char*)pp, "data/pal.act"))
2892 	{
2893 		memcpy(pal, pp, (PAL_BYTES)/2);
2894 	}
2895 	if(immediate)
2896 	{
2897 	   change_system_palette(0);
2898 	}
2899 }
2900 
2901 
unload_background()2902 void unload_background(){
2903 	int i;
2904 	if (background)	clearscreen(background);
2905 	for(i=0; i<MAX_BLENDINGS; i++)
2906 	{
2907 		if(blendings[i]) free(blendings[i]);
2908 		blendings[i] = NULL;
2909 	}
2910 }
2911 
2912 
_makecolour(int r,int g,int b)2913 int _makecolour(int r, int g, int b)
2914 {
2915 	switch(screenformat)
2916 	{
2917 	case PIXEL_8:
2918 		return palette_find(pal, r, g, b);
2919 	case PIXEL_16:
2920 		 return colour16(r,g,b);
2921 	case PIXEL_32:
2922 		return colour32(r,g,b);
2923 	}
2924 	return 0;
2925 }
2926 
2927 // parses a color string in the format "R_G_B" or as a raw integer
parsecolor(const char * string)2928 int parsecolor(const char* string)
2929 {
2930 	int r, g, b;
2931 	if(strchr(string, '_') != strrchr(string, '_'))
2932 	{ // 2 underscores; color is in "R_G_B" format
2933 		r = atoi(string);
2934 		g = atoi(strchr(string, '_')+1);
2935 		b = atoi(strrchr(string, '_')+1);
2936 		return _makecolour(r,g,b);
2937 	} else return atoi(string); // raw integer
2938 }
2939 
2940 // ltb 1-17-05   new function for lifebar colors
lifebar_colors()2941 void lifebar_colors()
2942 {
2943 	char * filename = "data/lifebar.txt";
2944 	char *buf;
2945 	size_t size;
2946 	int pos;
2947 	ArgList arglist;
2948 	char argbuf[MAX_ARG_LEN+1] = "";
2949 
2950 
2951 	char * command;
2952 
2953 	if(buffer_pakfile(filename, &buf, &size)!=1)
2954 	{
2955 		color_black = 0;
2956 		color_red = 0;
2957 		color_orange = 0;
2958 		color_yellow = 0;
2959 		color_white = 0;
2960 		color_blue = 0;
2961 		color_green = 0;
2962 		color_pink = 0;
2963 		color_purple = 0;
2964 		color_magic = 0;
2965 		color_magic2 = 0;
2966 		shadowcolor = 0;
2967 		shadowalpha = BLEND_MULTIPLY+1;
2968 		return;
2969 	}
2970 
2971 	pos = 0;
2972 	colorbars=1;
2973 	while(pos<size){
2974 	    ParseArgs(&arglist,buf+pos,argbuf);
2975 		command = GET_ARG(0);
2976 		if(command && command[0])
2977 		{
2978 			if(stricmp(command, "blackbox")==0)
2979 				color_black = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
2980 			else if(stricmp(command, "whitebox")==0)
2981 				color_white = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
2982 			else if(stricmp(command, "color300")==0)
2983 				color_orange = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
2984 			else if(stricmp(command, "color25")==0)
2985 				color_red = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
2986 			else if(stricmp(command, "color50")==0)
2987 				color_yellow = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
2988 			else if(stricmp(command, "color100")==0)
2989 				color_green = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
2990 			else if(stricmp(command, "color200")==0)
2991 				color_blue = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
2992 			else if(stricmp(command, "color400")==0)
2993 				color_pink = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
2994 			else if(stricmp(command, "color500")==0)
2995 				color_purple = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
2996 			//magic bars color declarations by tails
2997 			else if(stricmp(command, "colormagic")==0)
2998 				color_magic = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
2999 			else if(stricmp(command, "colormagic2")==0)
3000 				color_magic2 = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
3001 			//end of magic bars color declarations by tails
3002 			else if(stricmp(command, "shadowcolor")==0)
3003 				shadowcolor = _makecolour(GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3));
3004 			else if(stricmp(command, "shadowalpha")==0) //gfxshadow alpha
3005 				shadowalpha = GET_INT_ARG(1);
3006 			else
3007 				if(command && command[0])
3008 					printf("Warning: Unknown command in lifebar.txt: '%s'.\n", command);
3009 		}
3010 
3011 		// Go to next line
3012 	pos += getNewLineStart(buf + pos);
3013 	}
3014 	if(buf != NULL){
3015 		free(buf);
3016 		buf = NULL;
3017 	}
3018 }
3019 // ltb 1-17-05 end new lifebar colors
3020 
3021 
init_colourtable()3022 void init_colourtable()
3023 {
3024 	mpcolourtable[0]  = color_magic2;
3025 	mpcolourtable[1]  = color_magic;
3026 	mpcolourtable[2]  = color_magic;
3027 	mpcolourtable[3]  = color_magic;
3028 	mpcolourtable[4]  = color_magic2;
3029 	mpcolourtable[5]  = color_magic;
3030 	mpcolourtable[6]  = color_magic2;
3031 	mpcolourtable[7]  = color_magic;
3032 	mpcolourtable[8]  = color_magic2;
3033 	mpcolourtable[9]  = color_magic;
3034 	mpcolourtable[10] = color_magic2;
3035 
3036 	hpcolourtable[0]  = color_purple;
3037 	hpcolourtable[1]  = color_red;
3038 	hpcolourtable[2]  = color_yellow;
3039 	hpcolourtable[3]  = color_green;
3040 	hpcolourtable[4]  = color_blue;
3041 	hpcolourtable[5]  = color_orange;
3042 	hpcolourtable[6]  = color_pink;
3043 	hpcolourtable[7]  = color_purple;
3044 	hpcolourtable[8]  = color_black;
3045 	hpcolourtable[9]  = color_white;
3046 	hpcolourtable[10] = color_white;
3047 
3048 	memcpy(ldcolourtable, hpcolourtable, 11*sizeof(int));
3049 }
3050 
load_background(char * filename,int createtables)3051 void load_background(char *filename, int createtables)
3052 {
3053 	//if(pixelformat!=PIXEL_8) createtables = 0;
3054 	unload_background();
3055 
3056 	if(pixelformat==PIXEL_8)
3057 	{
3058 		if(!loadscreen(filename, packfile, pal, PIXEL_8, &background))
3059 		{
3060 			shutdown(1, "Error loading background (PIXEL_8) file '%s'", filename);
3061 		}
3062 	}
3063 	else if(pixelformat==PIXEL_x8)
3064 	{
3065 		if(!loadscreen(filename, packfile, NULL, PIXEL_x8, &background))
3066 		{
3067 			shutdown(1, "Error loading background (PIXEL_x8) file '%s'", filename);
3068 		}
3069 		memcpy(pal, background->palette, PAL_BYTES);
3070 	}
3071 	else
3072 	{
3073 		shutdown(1, "Error loading background, Unknown Pixel Format!\n");
3074 	}
3075 
3076 	if(createtables)
3077 	{
3078 		standard_palette(0);
3079 		if(!create_blending_tables(pal, blendings, blendfx))
3080 			shutdown(1, "Failed to create colour conversion tables! (Out of memory?)");
3081 	}
3082 
3083 	lifebar_colors();
3084 	if(!color_black)  color_black = _makecolour(0,0,0);           // black boxes 500-600HP
3085 	if(!color_red)    color_red = _makecolour(255,0,0);           // 1% - 25% Full Health
3086 	if(!color_orange) color_orange = _makecolour(255,150,0);      // 200-300HP
3087 	if(!color_yellow) color_yellow = _makecolour(0xF8,0xB8,0x40); // 26%-50% Full health
3088 	if(!color_white)  color_white = _makecolour(255,255,255);     // white boxes 600+ HP
3089 	if(!color_blue)   color_blue = _makecolour(0,0,255);          // 100-200 HP
3090 	if(!color_green)  color_green = _makecolour(0,255,0);         // 51% - 100% full health
3091 	if(!color_pink)   color_pink = _makecolour(255,0,255);        // 300-400HP
3092 	if(!color_purple) color_purple = _makecolour(128,48,208);     // transbox 400-500HP
3093 	if(!color_magic)  color_magic = _makecolour(98,180,255);      // 1st magic bar color by tails
3094 	if(!color_magic2) color_magic2 = _makecolour(24,48,143);      // 2sec magic bar color by tails
3095 	if(!shadowcolor)  shadowcolor =  _makecolour(64,64,64);
3096 	init_colourtable();
3097 
3098 	video_clearscreen();
3099 	pal[0] = pal[1] = pal[2] = 0;
3100 	//palette_set_corrected(pal, savedata.gamma,savedata.gamma,savedata.gamma, savedata.brightness,savedata.brightness,savedata.brightness);
3101 	change_system_palette(0);
3102 }
3103 
load_cached_background(char * filename,int createtables)3104 void load_cached_background(char *filename, int createtables)
3105 {
3106 #if !WII
3107 	load_background(filename, createtables);
3108 #else
3109 	int index = -1;
3110 	unload_background();
3111 
3112 	if(strcmp(filename, "data/bgs/logo")==0)
3113 		index = 0;
3114 	else if(strcmp(filename, "data/bgs/title")==0)
3115 		index = 1;
3116 	else if(strcmp(filename, "data/bgs/titleb")==0)
3117 		index = 2;
3118 	else if(strcmp(filename, "data/bgs/loading")==0)
3119 		index = 3;
3120 	else if(strcmp(filename, "data/bgs/loading2")==0)
3121 		index = 4;
3122 	else if(strcmp(filename, "data/bgs/hiscore")==0)
3123 		index = 5;
3124 	else if(strcmp(filename, "data/bgs/complete")==0)
3125 		index = 6;
3126 	else if(strcmp(filename, "data/bgs/unlockbg")==0)
3127 		index = 7;
3128 	else if(strcmp(filename, "data/bgs/select")==0)
3129 		index = 8;
3130 
3131 	if((index==-1) || (bg_cache[index]==NULL))
3132 		shutdown(1, "Error: can't load cached background '%s'", filename);
3133 
3134 	if(background) freescreen(&background);
3135 	background = allocscreen(videomodes.hRes, videomodes.vRes, pixelformat);
3136 	copyscreen(background, bg_cache[index]);
3137 
3138 	if(pixelformat==PIXEL_8)
3139 		memcpy(pal, bg_palette_cache[index], PAL_BYTES);
3140 	else if(pixelformat==PIXEL_x8)
3141 	{
3142 		memcpy(background->palette, bg_cache[index]->palette, PAL_BYTES);
3143 		memcpy(pal, background->palette, PAL_BYTES);
3144 	}
3145 
3146 
3147 	if(createtables)
3148 	{
3149 		standard_palette(0);
3150 		if(!create_blending_tables(pal, blendings, blendfx))
3151 			shutdown(1, "Failed to create colour conversion tables! (Out of memory?)");
3152 	}
3153 
3154 	video_clearscreen();
3155 	pal[0] = pal[1] = pal[2] = 0;
3156 	//palette_set_corrected(pal, savedata.gamma,savedata.gamma,savedata.gamma, savedata.brightness,savedata.brightness,savedata.brightness);
3157 	change_system_palette(0);
3158 #endif
3159 }
3160 
3161 #if WII
cache_background(char * filename)3162 void cache_background(char *filename)
3163 {
3164 	s_screen *bg = allocscreen(videomodes.hRes, videomodes.vRes, pixelformat);
3165 	int index = -1;
3166 
3167 	if(pixelformat==PIXEL_8)
3168 	{
3169 		if(!loadscreen(filename, packfile, pal, pixelformat, &bg))
3170 		{
3171 			freescreen(&bg);
3172 			bg = NULL;
3173 		}
3174 	}
3175 	else if(pixelformat==PIXEL_x8)
3176 	{
3177 		if(!loadscreen(filename, packfile, NULL, pixelformat, &bg))
3178 		{
3179 			freescreen(&bg);
3180 			bg = NULL;
3181 		}
3182 	}
3183 	else
3184 	{
3185 		shutdown(1, "Error caching background, Unknown Pixel Format!\n");
3186 	}
3187 
3188 	if(strcmp(filename, "data/bgs/logo")==0)
3189 		index = 0;
3190 	else if(strcmp(filename, "data/bgs/title")==0)
3191 		index = 1;
3192 	else if(strcmp(filename, "data/bgs/titleb")==0)
3193 		index = 2;
3194 	else if(strcmp(filename, "data/bgs/loading")==0)
3195 		index = 3;
3196 	else if(strcmp(filename, "data/bgs/loading2")==0)
3197 		index = 4;
3198 	else if(strcmp(filename, "data/bgs/hiscore")==0)
3199 		index = 5;
3200 	else if(strcmp(filename, "data/bgs/complete")==0)
3201 		index = 6;
3202 	else if(strcmp(filename, "data/bgs/unlockbg")==0)
3203 		index = 7;
3204 	else if(strcmp(filename, "data/bgs/select")==0)
3205 		index = 8;
3206 	else shutdown(1, "Error: unknown cached background '%s'", filename);
3207 
3208 	bg_cache[index] = bg;
3209 
3210 	if(pixelformat==PIXEL_8)
3211 		memcpy(bg_palette_cache[index], pal, PAL_BYTES);
3212 
3213 	change_system_palette(0);
3214 }
3215 
cache_all_backgrounds()3216 void cache_all_backgrounds()
3217 {
3218 	cache_background("data/bgs/logo");
3219 	cache_background("data/bgs/title");
3220 	cache_background("data/bgs/titleb");
3221 	cache_background("data/bgs/loading2");
3222 	cache_background("data/bgs/hiscore");
3223 	cache_background("data/bgs/complete");
3224 	cache_background("data/bgs/unlockbg");
3225 	cache_background("data/bgs/select");
3226 }
3227 #endif
3228 
load_bglayer(char * filename,int index)3229 void load_bglayer(char *filename, int index)
3230 {
3231 	if(!level) return;
3232 
3233 	if(filename){
3234 
3235 		if ((level->bglayers[index].drawmethod.alpha>0 || level->bglayers[index].drawmethod.transbg) && !level->bglayers[index].drawmethod.water.watermode)
3236 		{
3237 		// assume sprites are faster than screen when transparency or alpha are specified
3238 			level->bglayers[index].sprite = loadsprite2(filename, &(level->bglayers[index].width),&(level->bglayers[index].height));
3239 			level->bglayers[index].type = bg_sprite;
3240 		}
3241 		else
3242 		{
3243 		// use screen for water effect for now, it should be faster than sprite
3244 		// otherwise, a screen should be fine, especially in 8bit mode, it is super fast,
3245 		//            or, at least it is not slower than a sprite
3246 			if(loadscreen(filename, packfile, NULL, pixelformat, &level->bglayers[index].screen))
3247 			{
3248 				level->bglayers[index].height = level->bglayers[index].screen->height;
3249 				level->bglayers[index].width = level->bglayers[index].screen->width;
3250 				level->bglayers[index].type = bg_screen;
3251 			}
3252 		}
3253 	}
3254 
3255 	if(level->bglayers[index].handle ==NULL) shutdown(1, "Error loading file '%s'", filename);
3256 	else{
3257 		if(level->bglayers[index].xrepeat<0) {
3258 			level->bglayers[index].xoffset = -level->bglayers[index].width*20000;
3259 			level->bglayers[index].xrepeat = 40000;
3260 		}
3261 		if(level->bglayers[index].zrepeat<0) {
3262 			level->bglayers[index].zoffset = -level->bglayers[index].height*20000;
3263 			level->bglayers[index].zrepeat = 40000;
3264 		}
3265 		//printf("bglayer width=%d height=%d xoffset=%d zoffset=%d xrepeat=%d zrepeat%d\n", level->bglayers[index].width, level->bglayers[index].height, level->bglayers[index].xoffset, level->bglayers[index].zoffset, level->bglayers[index].xrepeat, level->bglayers[index].zrepeat);
3266 	}
3267 
3268 }
3269 
load_fglayer(char * filename,int index)3270 void load_fglayer(char *filename, int index)
3271 {
3272 	if(!level) return;
3273 
3274 	if((level->fglayers[index].drawmethod.alpha>0 || level->fglayers[index].drawmethod.transbg) && !level->fglayers[index].drawmethod.water.watermode)
3275 	{
3276 	// assume sprites are faster than screen when transparency or alpha are specified
3277 		level->fglayers[index].sprite = loadsprite2(filename, &(level->fglayers[index].width),&(level->fglayers[index].height));
3278 		level->fglayers[index].type = fg_sprite;
3279 	}
3280 	else
3281 	{
3282 	// otherwise, a screen should be fine, especially in 8bit mode, it is super fast,
3283 	//            or, at least it is not slower than a sprite
3284 		if(loadscreen(filename, packfile, NULL, pixelformat, &level->fglayers[index].screen))
3285 		{
3286 			level->fglayers[index].height = level->fglayers[index].screen->height;
3287 			level->fglayers[index].width = level->fglayers[index].screen->width;
3288 			level->fglayers[index].type = fg_screen;
3289 		}
3290 	}
3291 
3292 	if(level->fglayers[index].handle ==NULL) shutdown(1, "Error loading file '%s'", filename);
3293 
3294 	if(level->fglayers[index].xrepeat<0) {
3295 		level->fglayers[index].xoffset = -level->fglayers[index].width*20000;
3296 		level->fglayers[index].xrepeat = 40000;
3297 	}
3298 	if(level->fglayers[index].zrepeat<0) {
3299 		level->fglayers[index].zoffset = -level->fglayers[index].height*20000;
3300 		level->fglayers[index].zrepeat = 40000;
3301 	}
3302 
3303 }
3304 
freepanels()3305 void freepanels(){
3306 	int i;
3307 	for(i=0; i<MAX_PANELS; i++){
3308 		if(panels[i].sprite_normal != NULL){
3309 			free(panels[i].sprite_normal);
3310 			panels[i].sprite_normal = NULL;
3311 		}
3312 		if(panels[i].sprite_neon != NULL){
3313 			free(panels[i].sprite_neon);
3314 			panels[i].sprite_neon = NULL;
3315 		}
3316 		if(panels[i].sprite_screen != NULL){
3317 			free(panels[i].sprite_screen);
3318 			panels[i].sprite_screen = NULL;
3319 		}
3320 		if(frontpanels[i] != NULL){
3321 			free(frontpanels[i]);
3322 			frontpanels[i] = NULL;
3323 		}
3324 	}
3325 	panels_loaded = 0;
3326 	frontpanels_loaded = 0;
3327 	panel_width = 0;
3328 	panel_height = 0;
3329 }
3330 
loadsprite2(char * filename,int * width,int * height)3331 s_sprite* loadsprite2(char *filename, int* width, int* height)
3332 {
3333 	size_t size;
3334 	s_bitmap *bitmap = NULL;
3335 	s_sprite *sprite = NULL;
3336 	int clipl, clipr, clipt, clipb;
3337 
3338 	bitmap = loadbitmap(filename, packfile, pixelformat);
3339 	if(!bitmap) return NULL;
3340 	if(width) *width = bitmap->width;
3341 	if(height) *height = bitmap->height;
3342 	clipbitmap(bitmap, &clipl, &clipr, &clipt, &clipb);
3343 	size = fakey_encodesprite(bitmap);
3344 	sprite = (s_sprite*)malloc(size);
3345 	if(!sprite){
3346 		freebitmap(bitmap);
3347 		return NULL;
3348 	}
3349 	encodesprite(-clipl, -clipt, bitmap, sprite);
3350 	freebitmap(bitmap);
3351 
3352 	return sprite;
3353 }
3354 
3355 
3356 
loadpanel2(char * filename)3357 s_sprite * loadpanel2(char *filename){
3358 	s_sprite *sprite;
3359 	int w, h;
3360 
3361 	if(NULL==(sprite=loadsprite2(filename, &w, &h)))
3362 		return NULL;
3363 
3364 	if(w > panel_width) panel_width = w;
3365 	if(h > panel_height) panel_height = h;
3366 
3367 	return sprite;
3368 }
3369 
3370 
3371 
loadpanel(char * filename_normal,char * filename_neon,char * filename_screen)3372 int loadpanel(char *filename_normal, char *filename_neon, char *filename_screen){
3373 
3374 	int i = 0;
3375 
3376 	if(panels_loaded >= MAX_PANELS) return 0;
3377 
3378 	if(stricmp(filename_normal,"none")!=0 && *filename_normal){
3379 		panels[panels_loaded].sprite_normal = loadpanel2(filename_normal);
3380 		if(panels[panels_loaded].sprite_normal == NULL) return 0;
3381 		i++;
3382 	}
3383 	if(stricmp(filename_neon,"none")!=0 && *filename_neon){
3384 		panels[panels_loaded].sprite_neon = loadpanel2(filename_neon);
3385 		if(panels[panels_loaded].sprite_neon == NULL) return 0;
3386 		if(panels[panels_loaded].sprite_neon->palette) // under 24bit mode, copy the palette
3387 			memcpy(neontable, panels[panels_loaded].sprite_neon->palette, PAL_BYTES);
3388 		i++;
3389 	}
3390 	if(stricmp(filename_screen,"none")!=0 && *filename_screen){
3391 		panels[panels_loaded].sprite_screen = loadpanel2(filename_screen);
3392 		if(panels[panels_loaded].sprite_screen == NULL) return 0;
3393 		else if(blendfx_is_set==0) blendfx[BLEND_SCREEN] = 1;
3394 		i++;
3395 	}
3396 	if(i<1) return 0;    // Nothing was loaded!
3397 
3398 	++panels_loaded;
3399 
3400 	return 1;
3401 }
3402 
3403 
3404 
loadfrontpanel(char * filename)3405 int loadfrontpanel(char *filename){
3406 
3407 	size_t size;
3408 	s_bitmap *bitmap = NULL;
3409 	int clipl, clipr, clipt, clipb;
3410 
3411 
3412 	if(frontpanels_loaded >= MAX_PANELS) return 0;
3413 	bitmap = loadbitmap(filename, packfile, pixelformat);
3414 	if(!bitmap) return 0;
3415 
3416 	clipbitmap(bitmap, &clipl, &clipr, &clipt, &clipb);
3417 
3418 	size = fakey_encodesprite(bitmap);
3419 	frontpanels[frontpanels_loaded] = (s_sprite*)malloc(size);
3420 	if(!frontpanels[frontpanels_loaded]){
3421 		freebitmap(bitmap);
3422 		return 0;
3423 	}
3424 	encodesprite(-clipl, -clipt, bitmap, frontpanels[frontpanels_loaded]);
3425 
3426 	freebitmap(bitmap);
3427 	++frontpanels_loaded;
3428 
3429 	return 1;
3430 }
3431 
3432 // Added to conserve memory
resourceCleanUp()3433 void resourceCleanUp(){
3434 	freesprites();
3435 	free_models();
3436 	free_modelcache();
3437 	load_special_sounds();
3438 	load_script_setting();
3439 	load_special_sprites();
3440 	load_levelorder();
3441 	load_models();
3442 }
3443 
freesprites()3444 void freesprites()
3445 {
3446 	unsigned short i;
3447 	s_sprite_list *head;
3448 	for(i=0; i<=sprites_loaded; i++)
3449 	{
3450 		if(sprite_list != NULL)
3451 		{
3452 			free(sprite_list->sprite);
3453 			sprite_list->sprite = NULL;
3454 			free(sprite_list->filename);
3455 			sprite_list->filename = NULL;
3456 			head = sprite_list->next;
3457 			free(sprite_list);
3458 			sprite_list = head;
3459 		}
3460 	}
3461 	if(sprite_map != NULL)
3462 	{
3463 		free(sprite_map);
3464 		sprite_map = NULL;
3465 	}
3466 	sprites_loaded = 0;
3467 }
3468 
3469 // allocate enough members for sprite_map
prepare_sprite_map(size_t size)3470 void prepare_sprite_map(size_t size)
3471 {
3472 	if(sprite_map == NULL || size + 1 > sprite_map_max_items )
3473 	{
3474 #ifdef VERBOSE
3475 		printf("%s %p\n", "prepare_sprite_map was", sprite_map);
3476 #endif
3477 		do {
3478 			sprite_map_max_items += 256;
3479 		}
3480 		while (size + 1 > sprite_map_max_items);
3481 		sprite_map = realloc(sprite_map, sizeof(s_sprite_map) * sprite_map_max_items);
3482 		if(sprite_map == NULL) shutdown(1, "Out Of Memory!  Failed to create a new sprite_map\n");
3483 	}
3484 }
3485 
3486 // Returns sprite index.
3487 // Does not return on error, as it would shut the program down.
3488 // UT:
3489 // bmpformat - In 24bit mode, a sprite can have a 24bit palette(e.g., panel),
3490 //             so add this paramter to let sprite encoding function know.
3491 //             Actually the sprite pixel encoding method is the same, but a
3492 //             24bit palettte sprite should have a palette allocated at the end of
3493 //             pixel data, and the information is carried by the bitmap paramter.
loadsprite(char * filename,int ofsx,int ofsy,int bmpformat)3494 int loadsprite(char *filename, int ofsx, int ofsy, int bmpformat)
3495 {
3496 	ptrdiff_t i, size, len;
3497 	s_bitmap *bitmap = NULL;
3498 	int clipl, clipr, clipt, clipb;
3499 	s_sprite_list *curr = NULL, *head = NULL;
3500 
3501 	for(i=0; i<sprites_loaded; i++) {
3502 		if(sprite_map != NULL) {
3503 			if(stricmp(sprite_map[i].filename, filename) == 0) {
3504 				if(sprite_map[i].ofsx == ofsx && sprite_map[i].ofsy == ofsy) return i;
3505 				else {
3506 					bitmap = loadbitmap(filename, packfile, bmpformat);
3507 					if(bitmap == NULL) shutdown(1, "Unable to load file '%s'\n", filename);
3508 					clipbitmap(bitmap, &clipl, &clipr, &clipt, &clipb);
3509 					prepare_sprite_map(sprites_loaded+1);
3510 					sprite_map[sprites_loaded].filename = sprite_map[i].filename;
3511 					sprite_map[sprites_loaded].sprite = sprite_map[i].sprite;
3512 					sprite_map[sprites_loaded].ofsx = ofsx;
3513 					sprite_map[sprites_loaded].ofsy = ofsy;
3514 					sprite_map[sprites_loaded].centerx = ofsx-clipl;
3515 					sprite_map[sprites_loaded].centery = ofsy-clipt;
3516 					freebitmap(bitmap);
3517 					++sprites_loaded;
3518 					return sprites_loaded-1;
3519 				}
3520 			}
3521 		}
3522 	}
3523 
3524 	bitmap = loadbitmap(filename, packfile, bmpformat);
3525 	if(bitmap == NULL) shutdown(1, "Unable to load file '%s'\n", filename);
3526 
3527 	clipbitmap(bitmap, &clipl, &clipr, &clipt, &clipb);
3528 
3529 	len = strlen(filename);
3530 	size = fakey_encodesprite(bitmap);
3531 	curr = malloc(sizeof(s_sprite_list));
3532 	curr->sprite = malloc(size);
3533 	curr->filename = malloc(len + 1);
3534 	if(curr == NULL || curr->sprite == NULL || curr->filename == NULL){
3535 		freebitmap(bitmap);
3536 		shutdown(1, "loadsprite() Out of memory!\n");
3537 	}
3538 	memcpy(curr->filename, filename,len);
3539 	curr->filename[len] = 0;
3540 	encodesprite(ofsx-clipl, ofsy-clipt, bitmap, curr->sprite);
3541 	if(sprite_list == NULL){
3542 		sprite_list = curr;
3543 		sprite_list->next = NULL;
3544 	}
3545 	else{
3546 		head = sprite_list;
3547 		sprite_list = curr;
3548 		sprite_list->next = head;
3549 	}
3550 	prepare_sprite_map(sprites_loaded+1);
3551 	sprite_map[sprites_loaded].filename = sprite_list->filename;
3552 	sprite_map[sprites_loaded].sprite = sprite_list->sprite;
3553 	sprite_map[sprites_loaded].ofsx = ofsx;
3554 	sprite_map[sprites_loaded].ofsy = ofsy;
3555 	sprite_map[sprites_loaded].centerx = ofsx-clipl;
3556 	sprite_map[sprites_loaded].centery = ofsy-clipt;
3557 	freebitmap(bitmap);
3558 	++sprites_loaded;
3559 	return sprites_loaded-1;
3560 }
3561 
load_special_sprites()3562 void load_special_sprites()
3563 {
3564 	memset(shadowsprites, -1, sizeof(shadowsprites[0])*6);
3565 	golsprite = gosprite = -1;
3566 	if(testpackfile("data/sprites/shadow1.gif", packfile) >=0) shadowsprites[0] = loadsprite("data/sprites/shadow1",9,3,pixelformat);
3567 	if(testpackfile("data/sprites/shadow2.gif", packfile) >=0) shadowsprites[1] = loadsprite("data/sprites/shadow2",14,5,pixelformat);
3568 	if(testpackfile("data/sprites/shadow3.gif", packfile) >=0) shadowsprites[2] = loadsprite("data/sprites/shadow3",19,6,pixelformat);
3569 	if(testpackfile("data/sprites/shadow4.gif", packfile) >=0) shadowsprites[3] = loadsprite("data/sprites/shadow4",24,8,pixelformat);
3570 	if(testpackfile("data/sprites/shadow5.gif", packfile) >=0) shadowsprites[4] = loadsprite("data/sprites/shadow5",29,9,pixelformat);
3571 	if(testpackfile("data/sprites/shadow6.gif", packfile) >=0) shadowsprites[5] = loadsprite("data/sprites/shadow6",34,11,pixelformat);
3572 	if(testpackfile("data/sprites/arrow.gif", packfile) >=0) gosprite  = loadsprite("data/sprites/arrow",35,23,pixelformat);
3573 	if(testpackfile("data/sprites/arrowl.gif", packfile) >=0) golsprite = loadsprite("data/sprites/arrowl",35,23,pixelformat);
3574 	if(timeicon_path[0]) timeicon = loadsprite(timeicon_path,0,0,pixelformat);
3575 	if(bgicon_path[0]) bgicon = loadsprite(bgicon_path,0,0,pixelformat);
3576 	if(olicon_path[0]) olicon = loadsprite(olicon_path,0,0,pixelformat);
3577 }
3578 
unload_all_fonts()3579 void unload_all_fonts()
3580 {
3581 	int i;
3582 	for(i=0; i<8; i++)
3583 	{
3584 		font_unload(i);
3585 	}
3586 }
3587 
load_all_fonts()3588 void load_all_fonts()
3589 {
3590 	if(!font_load(0, "data/sprites/font", packfile, fontmonospace[0])) shutdown(1, "Unable to load font #1!\n");
3591 	if(!font_load(1, "data/sprites/font2", packfile, fontmonospace[1])) shutdown(1, "Unable to load font #2!\n");
3592 	if(!font_load(2, "data/sprites/font3", packfile, fontmonospace[2])) shutdown(1, "Unable to load font #3!\n");
3593 	if(!font_load(3, "data/sprites/font4", packfile, fontmonospace[3])) shutdown(1, "Unable to load font #4!\n");
3594 	if(testpackfile("data/sprites/font5.gif", packfile) >=0) font_load(4, "data/sprites/font5", packfile, fontmonospace[4]);
3595 	if(testpackfile("data/sprites/font6.gif", packfile) >=0) font_load(5, "data/sprites/font6", packfile, fontmonospace[5]);
3596 	if(testpackfile("data/sprites/font7.gif", packfile) >=0) font_load(6, "data/sprites/font7", packfile, fontmonospace[6]);
3597 	if(testpackfile("data/sprites/font8.gif", packfile) >=0) font_load(7, "data/sprites/font8", packfile, fontmonospace[7]);
3598 }
3599 
load_menu_txt()3600 void load_menu_txt()
3601 {
3602 	char * filename = "data/menu.txt";
3603 	int pos;
3604 	char *buf, *command;
3605 	size_t size;
3606 	ArgList arglist;
3607 	char argbuf[MAX_ARG_LEN+1] = "";
3608 
3609 	// Read file
3610 	if(buffer_pakfile(filename, &buf, &size)!=1)
3611 	{
3612 		return;
3613 	}
3614 
3615 	// Now interpret the contents of buf line by line
3616 	pos = 0;
3617 	while(pos<size){
3618 		ParseArgs(&arglist,buf+pos,argbuf);
3619 		command = GET_ARG(0);
3620 		if(command && command[0]){
3621 			if(stricmp(command, "disablekey")==0){
3622 				// here to keep from crashing
3623 			}
3624 			else if(stricmp(command, "renamekey")==0){
3625 				// here to keep from crashing
3626 			}
3627 			else if(stricmp(command, "fontmonospace")==0)
3628 			{
3629 				fontmonospace[0] = GET_INT_ARG(1);
3630 				fontmonospace[1] = GET_INT_ARG(2);
3631 				fontmonospace[2] = GET_INT_ARG(3);
3632 				fontmonospace[3] = GET_INT_ARG(4);
3633 				fontmonospace[4] = GET_INT_ARG(5);
3634 				fontmonospace[5] = GET_INT_ARG(6);
3635 				fontmonospace[6] = GET_INT_ARG(7);
3636 				fontmonospace[7] = GET_INT_ARG(8);
3637 			}
3638 			else
3639 				if(command && command[0])
3640 					printf("Command '%s' not understood in file '%s'!", command, filename);
3641 		}
3642 
3643 		// Go to next line
3644 		pos += getNewLineStart(buf + pos);
3645 	}
3646 
3647 	if(buf != NULL){
3648 		free(buf);
3649 		buf = NULL;
3650 	}
3651 }
3652 
load_special_sounds()3653 int load_special_sounds()
3654 {
3655 	sound_unload_all_samples();
3656 	SAMPLE_GO		= sound_load_sample("data/sounds/go.wav",		packfile,	0);
3657 	SAMPLE_BEAT		= sound_load_sample("data/sounds/beat1.wav",	packfile,	0);
3658 	SAMPLE_BLOCK	= sound_load_sample("data/sounds/block.wav",	packfile,	0);
3659 	SAMPLE_FALL		= sound_load_sample("data/sounds/fall.wav",		packfile,	0);
3660 	SAMPLE_GET		= sound_load_sample("data/sounds/get.wav",		packfile,	0);
3661 	SAMPLE_GET2		= sound_load_sample("data/sounds/money.wav",	packfile,	0);
3662 	SAMPLE_JUMP		= sound_load_sample("data/sounds/jump.wav",		packfile,	0);
3663 	SAMPLE_INDIRECT	= sound_load_sample("data/sounds/indirect.wav",	packfile,	0);
3664 	SAMPLE_PUNCH	= sound_load_sample("data/sounds/punch.wav",	packfile,	0);
3665 	SAMPLE_1UP		= sound_load_sample("data/sounds/1up.wav",		packfile,	0);
3666 	SAMPLE_TIMEOVER = sound_load_sample("data/sounds/timeover.wav", packfile,	0);
3667 	SAMPLE_BEEP		= sound_load_sample("data/sounds/beep.wav",		packfile,	0);
3668 	SAMPLE_BEEP2	= sound_load_sample("data/sounds/beep2.wav",	packfile,	0);
3669 	SAMPLE_BIKE		= sound_load_sample("data/sounds/bike.wav",		packfile,	0);
3670 	if(SAMPLE_GO < 0 || SAMPLE_BEAT < 0 || SAMPLE_BLOCK < 0 ||
3671 	   SAMPLE_FALL < 0 || SAMPLE_GET < 0 || SAMPLE_GET2 < 0 ||
3672 	   SAMPLE_JUMP < 0 || SAMPLE_INDIRECT < 0 || SAMPLE_PUNCH < 0 ||
3673 	   SAMPLE_1UP < 0 || SAMPLE_TIMEOVER < 0 || SAMPLE_BEEP < 0 ||
3674 	   SAMPLE_BEEP2 < 0 || SAMPLE_BIKE < 0) return 0;
3675 	return 1;
3676 }
3677 
3678 // Use by player select menus
nextplayermodel(s_model * current)3679 s_model* nextplayermodel(s_model *current){
3680 	int i;
3681 	int curindex = -1;
3682 	int loops;
3683 	if(current){
3684 		// Find index of current player model
3685 		for(i=0; i<models_cached; i++){
3686 			if(model_cache[i].model == current){
3687 				curindex = i;
3688 				break;
3689 			}
3690 		}
3691 	}
3692 	// Find next player model (first one after current index)
3693 	for(i=curindex+1, loops=0; loops<models_cached; i++, loops++){
3694 		if(i >= models_cached) i = 0;
3695 		if(model_cache[i].model && model_cache[i].model->type==TYPE_PLAYER &&
3696 		  (allow_secret_chars || !model_cache[i].model->secret) && model_cache[i].selectable){
3697 			return model_cache[i].model;
3698 		}
3699 	}
3700 	shutdown(1, "Fatal: can't find any player models!");
3701 	return NULL;
3702 }
3703 
3704 // Use by player select menus
prevplayermodel(s_model * current)3705 s_model* prevplayermodel(s_model *current){
3706 	int i;
3707 	int curindex = -1;
3708 	int loops;
3709 	if(current){
3710 		// Find index of current player model
3711 		for(i=0; i<models_cached; i++){
3712 			if(model_cache[i].model == current){
3713 				curindex = i;
3714 				break;
3715 			}
3716 		}
3717 	}
3718 	// Find next player model (first one after current index)
3719 	for(i=curindex-1, loops=0; loops<models_cached; i--, loops++){
3720 		if(i < 0) i = models_cached-1;
3721 		if(model_cache[i].model && model_cache[i].model->type==TYPE_PLAYER &&
3722 		  (allow_secret_chars || !model_cache[i].model->secret) && model_cache[i].selectable){
3723 			return model_cache[i].model;
3724 		}
3725 	}
3726 	shutdown(1, "Fatal: can't find any player models!");
3727 	return NULL;
3728 }
3729 
3730 // Reset All Player Models to on/off for Select Screen.
reset_playable_list(char which)3731 static void reset_playable_list(char which)
3732 {
3733 	int i;
3734 	for(i=0;i<models_cached;i++)
3735 	{
3736 		if(model_cache[i].model && model_cache[i].model->type == TYPE_PLAYER)
3737 		{
3738 			model_cache[i].selectable = which;
3739 		}
3740 	}
3741 }
3742 
3743 // Specify which Player Models are allowable for selecting
load_playable_list(char * buf)3744 static void load_playable_list(char* buf)
3745 {
3746 	int i, index;
3747 	char* value;
3748 	s_model *playermodels = NULL;
3749 	ArgList arglist;
3750 	char argbuf[MAX_ARG_LEN+1] = "";
3751 
3752 	reset_playable_list(0);
3753 	ParseArgs(&arglist,buf,argbuf);
3754 
3755 	for(i=1;(value=GET_ARG(i))[0];i++)
3756 	{
3757 		playermodels = findmodel(value);
3758 		//if(playermodels == NULL) shutdown(1, "Player model '%s' is not loaded.\n", value);
3759 		index = get_cached_model_index(playermodels->name);
3760 		if(index == -1) shutdown(1, "Player model '%s' is not cached.\n", value);
3761 		model_cache[index].selectable = 1;
3762 	}
3763 }
3764 
alloc_frames(s_anim * anim,int fcount)3765 void alloc_frames(s_anim * anim, int fcount)
3766 {
3767 	anim->sprite = malloc(fcount * sizeof(anim->sprite));
3768 	anim->delay = malloc(fcount * sizeof(anim->delay));
3769 	anim->vulnerable = malloc(fcount * sizeof(anim->vulnerable));
3770 	memset(anim->sprite, 0, fcount*sizeof(anim->sprite));
3771 	memset(anim->delay, 0, fcount*sizeof(anim->delay));
3772 	memset(anim->vulnerable, 0, fcount*sizeof(anim->vulnerable));
3773 }
3774 
free_frames(s_anim * anim)3775 void free_frames(s_anim * anim)
3776 {
3777 	int i;
3778 	if(anim->idle)			{free(anim->idle);			 anim->idle = NULL;}
3779 	if(anim->seta)          {free(anim->seta);          anim->seta = NULL;}
3780 	if(anim->move)          {free(anim->move);          anim->move = NULL;}
3781 	if(anim->movez)         {free(anim->movez);         anim->movez = NULL;}
3782 	if(anim->movea)         {free(anim->movea);         anim->movea = NULL;}
3783 	if(anim->delay)         {free(anim->delay);         anim->delay = NULL;}
3784 	if(anim->sprite)        {free(anim->sprite);        anim->sprite = NULL;}
3785 	if(anim->platform)      {free(anim->platform);      anim->platform = NULL;}
3786 	if(anim->vulnerable)    {free(anim->vulnerable);    anim->vulnerable = NULL;}
3787 	if(anim->bbox_coords)   {free(anim->bbox_coords);   anim->bbox_coords = NULL;}
3788 	if(anim->shadow)        {free(anim->shadow);        anim->shadow = NULL;}
3789 	if(anim->shadow_coords) {free(anim->shadow_coords); anim->shadow_coords = NULL;}
3790 	if(anim->soundtoplay)   {free(anim->soundtoplay);   anim->soundtoplay = NULL;}
3791 	if(anim->attacks)
3792 	{
3793 		for(i=0; i<anim->numframes; i++)
3794 		{
3795 			if(anim->attacks[i])
3796 			{
3797 				free(anim->attacks[i]);
3798 				anim->attacks[i] = NULL;
3799 			}
3800 		}
3801 		free(anim->attacks);
3802 		anim->attacks = NULL;
3803 	}
3804 	if(anim->drawmethods)
3805 	{
3806 		for(i=0; i<anim->numframes; i++)
3807 		{
3808 			if(anim->drawmethods[i])
3809 			{
3810 				free(anim->drawmethods[i]);
3811 				anim->drawmethods[i] = NULL;
3812 			}
3813 		}
3814 		free(anim->drawmethods);
3815 		anim->drawmethods = NULL;
3816 	}
3817 }
3818 
anim_list_delete(s_anim_list * list,int index)3819 s_anim_list *anim_list_delete(s_anim_list *list, int index)
3820 {
3821 	if(list == NULL) return NULL;
3822 	if(list->anim->model_index == index)
3823 	{
3824 		s_anim_list *next;
3825 		next = list->next;
3826 		free_anim(list->anim);
3827 		free(list);
3828 		return next;
3829 	}
3830 	list->next = anim_list_delete(list->next, index);
3831 	return list;
3832 }
3833 
free_anim(s_anim * anim)3834 void free_anim(s_anim * anim)
3835 {
3836 	if(!anim) return;
3837 	free_frames(anim);
3838 	if(anim->weaponframe)
3839 	{
3840 		free(anim->weaponframe);
3841 		anim->weaponframe = NULL;
3842 	}
3843 	if(anim->spawnframe)
3844 	{
3845 		free(anim->spawnframe);
3846 		anim->spawnframe = NULL;
3847 	}
3848 	if(anim->summonframe)
3849 	{
3850 		free(anim->summonframe);
3851 		anim->summonframe = NULL;
3852 	}
3853 	if(anim){
3854 		free(anim);
3855 		anim = NULL;
3856 	}
3857 }
3858 
hasFreetype(s_model * m,ModelFreetype t)3859 int hasFreetype(s_model* m, ModelFreetype t) {
3860 	assert(m);
3861 	return (m->freetypes & t) == t;
3862 }
3863 
addFreeType(s_model * m,ModelFreetype t)3864 void addFreeType(s_model* m, ModelFreetype t) {
3865 	assert(m);
3866 	m->freetypes |= t;
3867 }
3868 
3869 // Unload single model from memory
free_model(s_model * model)3870 int free_model(s_model* model)
3871 {
3872 	int i;
3873 	if(!model) return 0;
3874 	printf("Unload '%s'\n", model->name);
3875 
3876 	if(hasFreetype(model, MF_ANIMLIST))
3877 		for(i=0; i<max_animations; i++)
3878 			anim_list = anim_list_delete(anim_list, model->index);
3879 
3880 	if(hasFreetype(model, MF_COLOURMAP))
3881 		for(i=0; i<MAX_COLOUR_MAPS; i++)
3882 		{
3883 			if(model->colourmap[i] != NULL)
3884 			{
3885 				free(model->colourmap[i]);
3886 				model->colourmap[i] = NULL;
3887 			}
3888 		}
3889 
3890 	if(hasFreetype(model, MF_PALETTE) && model->palette)
3891 		{free(model->palette);                model->palette                = NULL;}
3892 	if(hasFreetype(model, MF_WEAPONS) && model->weapon && model->ownweapons)
3893 		{free(model->weapon);                 model->weapon                 = NULL;}
3894 	if(hasFreetype(model, MF_BRANCH) && model->branch)                      {free(model->branch);                 model->branch                 = NULL;}
3895 	if(hasFreetype(model, MF_ANIMATION) && model->animation)                   {free(model->animation);              model->animation              = NULL;}
3896 	if(hasFreetype(model, MF_DEF_FACTORS) && model->defense_factors)             {free(model->defense_factors);        model->defense_factors        = NULL;}
3897 	if(hasFreetype(model, MF_DEF_PAIN) && model->defense_pain)                {free(model->defense_pain);           model->defense_pain           = NULL;}
3898 	if(hasFreetype(model, MF_DEF_KNOCKDOWN) && model->defense_knockdown)           {free(model->defense_knockdown);      model->defense_knockdown      = NULL;}
3899 	if(hasFreetype(model, MF_DEF_BLOCKPOWER) && model->defense_blockpower)          {free(model->defense_blockpower);     model->defense_blockpower     = NULL;}
3900 	if(hasFreetype(model, MF_DEF_BLOCKTRESHOLD) && model->defense_blockthreshold)      {free(model->defense_blockthreshold); model->defense_blockthreshold = NULL;}
3901 	if(hasFreetype(model, MF_DEF_BLOCKRATIO) && model->defense_blockratio)          {free(model->defense_blockratio);     model->defense_blockratio     = NULL;}
3902 	if(hasFreetype(model, MF_DEF_BLOCKTYPE) && model->defense_blocktype)           {free(model->defense_blocktype);      model->defense_blocktype      = NULL;}
3903 	if(hasFreetype(model, MF_OFF_FACTORS) && model->offense_factors)             {free(model->offense_factors);        model->offense_factors        = NULL;}
3904 	if(hasFreetype(model, MF_SPECIAL) && model->special)                     {free(model->special);                model->special                = NULL;}
3905 	if(hasFreetype(model, MF_SMARTBOMB) && model->smartbomb)                   {free(model->smartbomb);              model->smartbomb              = NULL;}
3906 
3907 	if(hasFreetype(model, MF_SCRIPTS)) {
3908 		clear_all_scripts(&model->scripts,2);
3909 		free_all_scripts(&model->scripts);
3910 	}
3911 
3912 	deleteModel(model->name);
3913 
3914 	return models_loaded--;
3915 }
3916 
3917 // Unload all models and animations memory
free_models()3918 void free_models()
3919 {
3920 	s_model* temp;
3921 
3922 	while((temp = getFirstModel()))
3923 		free_model(temp);
3924 
3925 	// free animation ids
3926 	if(animdowns)       {free(animdowns);       animdowns          = NULL;}
3927 	if(animups)         {free(animups);         animups            = NULL;}
3928 	if(animbackwalks)   {free(animbackwalks);   animbackwalks      = NULL;}
3929 	if(animwalks)       {free(animwalks);       animwalks          = NULL;}
3930 	if(animidles)       {free(animidles);       animidles          = NULL;}
3931 	if(animspecials)    {free(animspecials);    animspecials       = NULL;}
3932 	if(animattacks)     {free(animattacks);     animattacks        = NULL;}
3933 	if(animfollows)     {free(animfollows);     animfollows        = NULL;}
3934 	if(animpains)       {free(animpains);       animpains          = NULL;}
3935 	if(animfalls)       {free(animfalls);       animfalls          = NULL;}
3936 	if(animrises)       {free(animrises);       animrises          = NULL;}
3937 	if(animriseattacks) {free(animriseattacks); animriseattacks    = NULL;}
3938 	if(animblkpains)    {free(animblkpains);    animblkpains       = NULL;}
3939 	if(animdies)        {free(animdies);        animdies           = NULL;}
3940 }
3941 
3942 
alloc_anim()3943 s_anim * alloc_anim()
3944 {
3945 	s_anim_list *curr = NULL, *head = NULL;
3946 	curr = malloc(sizeof(s_anim_list));
3947 	curr->anim = malloc(sizeof(s_anim));
3948 	if(curr == NULL || curr->anim == NULL) return NULL;
3949 	memset(curr->anim, 0, sizeof(s_anim));
3950 	if(anim_list == NULL){
3951 		anim_list = curr;
3952 		anim_list->next = NULL;
3953 	}
3954 	else{
3955 		head = anim_list;
3956 		anim_list = curr;
3957 		anim_list->next = head;
3958 	}
3959 	++anims_loaded;
3960 	return anim_list->anim;
3961 }
3962 
3963 
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)3964 int addframe(s_anim * a, int spriteindex, int framecount, short delay, unsigned char idle,
3965 			 short *bbox, s_attack* attack, short move, short movez,
3966 			 short movea, short seta, float* platform, int frameshadow, short* shadow_coords, int soundtoplay, s_drawmethod* drawmethod)
3967 {
3968 	ptrdiff_t currentframe;
3969 	if(framecount>0) alloc_frames(a, framecount);
3970 	else framecount = -framecount; // for alloc method, use a negative value
3971 
3972 	currentframe = a->numframes;
3973 	++a->numframes;
3974 
3975 	a->sprite[currentframe] = spriteindex;
3976 	a->delay[currentframe] = delay * GAME_SPEED / 100;
3977 
3978 	if((bbox[2]-bbox[0]) && (bbox[3]-bbox[1]))
3979 	{
3980 		if(!a->bbox_coords)
3981 		{
3982 			a->bbox_coords = malloc(framecount * sizeof(*a->bbox_coords));
3983 			memset(a->bbox_coords, 0, framecount * sizeof(*a->bbox_coords));
3984 		}
3985 		memcpy(a->bbox_coords[currentframe], bbox, sizeof(*a->bbox_coords));
3986 		a->vulnerable[currentframe] = 1;
3987 	}
3988 	if((attack->attack_coords[2]-attack->attack_coords[0]) &&
3989 		(attack->attack_coords[3]-attack->attack_coords[1]))
3990 	{
3991 		if(!a->attacks)
3992 		{
3993 			a->attacks = malloc(framecount * sizeof(s_attack*));
3994 			memset(a->attacks, 0, framecount * sizeof(s_attack*));
3995 		}
3996 		a->attacks[currentframe] = malloc(sizeof(s_attack));
3997 		memcpy(a->attacks[currentframe], attack, sizeof(s_attack));
3998 	}
3999 	if(drawmethod->flag)
4000 	{
4001 		if(!a->drawmethods)
4002 		{
4003 			a->drawmethods = malloc(framecount * sizeof(s_drawmethod*));
4004 			memset(a->drawmethods, 0, framecount * sizeof(s_drawmethod*));
4005 		}
4006 		setDrawMethod(a, currentframe, malloc(sizeof(s_drawmethod)));
4007 		//a->drawmethods[currenframe] = malloc(sizeof(s_drawmethod));
4008 		memcpy(getDrawMethod(a,currentframe), drawmethod, sizeof(s_drawmethod));
4009 		//memcpy(a->drawmethods[currentframe], drawmethod, sizeof(s_drawmethod));
4010 	}
4011 	if(idle && !a->idle)
4012 	{
4013 		a->idle = malloc(framecount*sizeof(*a->idle));
4014 		memset(a->idle, 0, framecount*sizeof(*a->idle));
4015 	}
4016 	if(a->idle) a->idle[currentframe] = idle;
4017 	if(move && !a->move)
4018 	{
4019 		a->move = malloc(framecount * sizeof(*a->move));
4020 		memset(a->move, 0, framecount * sizeof(*a->move));
4021 	}
4022 	if(a->move) a->move[currentframe] = move;
4023 	if(movez && !a->movez)
4024 	{
4025 		a->movez = malloc(framecount * sizeof(*a->movez));
4026 		memset(a->movez, 0, framecount * sizeof(*a->movez));
4027 	}
4028 	if(a->movez) a->movez[currentframe] = movez;						           // Move command for the "z" axis
4029 	if(movea && !a->movea)
4030 	{
4031 		a->movea = malloc(framecount * sizeof(*a->movea));
4032 		memset(a->movea, 0, framecount * sizeof(*a->movea));
4033 	}
4034 	if(a->movea) a->movea[currentframe] = movea;						           // Move command for moving along the "a" axis
4035 	if(seta>=0 && !a->seta)
4036 	{
4037 		a->seta = malloc(framecount * sizeof(*a->seta));
4038 		memset(a->seta, -1, framecount * sizeof(*a->seta)); //default to -1
4039 	}
4040 	if(a->seta) a->seta[currentframe] = seta;						               // Sets the "a" for the character on a frame/frame basis
4041 	if(frameshadow >= 0 && !a->shadow)
4042 	{
4043 		a->shadow = malloc(framecount * sizeof(*a->shadow));
4044 		memset(a->shadow, -1, framecount * sizeof(*a->shadow)); //default to -1
4045 	}
4046 	if(a->shadow) a->shadow[currentframe] = frameshadow;                          // shadow index for each frame
4047 	if(shadow_coords[0] || shadow_coords[1])
4048 	{
4049 		if(!a->shadow_coords)
4050 		{
4051 			a->shadow_coords=malloc(framecount * sizeof(*a->shadow_coords));
4052 			memset(a->shadow_coords, 0, framecount * sizeof(*a->shadow_coords));
4053 		}
4054 		memcpy(a->shadow_coords[currentframe], shadow_coords, sizeof(*a->shadow_coords));
4055 	}
4056 	if(platform[7]) //height
4057 	{
4058 		if(!a->platform)
4059 		{
4060 			a->platform = malloc(framecount * sizeof(*a->platform));
4061 			memset(a->platform, 0, framecount * sizeof(*a->platform));
4062 		}
4063 		memcpy(a->platform[currentframe], platform, sizeof(*a->platform));// Used so entity can be landed on
4064 	}
4065 	if(soundtoplay >= 0)
4066 	{
4067 		if(!a->soundtoplay)
4068 		{
4069 			a->soundtoplay = malloc(framecount * sizeof(*a->soundtoplay));
4070 			memset(a->soundtoplay, -1, framecount * sizeof(*a->soundtoplay)); // default to -1
4071 		}
4072 		a->soundtoplay[currentframe] = soundtoplay;
4073 	}
4074 
4075 	return a->numframes;
4076 }
4077 
4078 
4079 // ok this func only seems to overwrite the name which was assigned from models.txt with the one
4080 // in the models own text file.
4081 // it does so in the cache.
_peek_model_name(int index)4082 void _peek_model_name(int index)
4083 {
4084 	size_t size = 0;
4085 	ptrdiff_t pos = 0, len;
4086 	char *buf = NULL;
4087 	char *command, *value;
4088 	ArgList arglist;
4089 	char argbuf[MAX_ARG_LEN+1] = "";
4090 	modelCommands cmd;
4091 
4092 	if(buffer_pakfile(model_cache[index].path, &buf, &size)!=1) return;
4093 
4094 	while(pos<size)
4095 	{
4096 		ParseArgs(&arglist,buf+pos,argbuf);
4097 		command = GET_ARG(0);
4098 
4099 		if(command && command[0]){
4100 			cmd = getModelCommand(modelcmdlist, command);
4101 			if(cmd == CMD_MODEL_NAME)
4102 			{
4103 				value = GET_ARG(1);
4104 				free(model_cache[index].name);
4105 				model_cache[index].name = NULL;
4106 				len = strlen(value);
4107 				model_cache[index].name = malloc(len + 1);
4108 				strcpy(model_cache[index].name, value);
4109 				model_cache[index].name[len] = 0;
4110 				break;
4111 			}
4112 		}
4113 		pos += getNewLineStart(buf + pos);
4114 	}
4115 
4116 	if(buf != NULL)
4117 	{
4118 		free(buf);
4119 		buf = NULL;
4120 	}
4121 }
4122 
prepare_cache_map(size_t size)4123 void prepare_cache_map(size_t size)
4124 {
4125 	if(model_cache== NULL || size + 1 > cache_map_max_items )
4126 	{
4127 #ifdef VERBOSE
4128 		printf("%s %p\n", "prepare_cache_map was", model_cache);
4129 #endif
4130 		do {
4131 			cache_map_max_items += 128;
4132 		}
4133 		while (size + 1 > cache_map_max_items);
4134 
4135 		model_cache = realloc(model_cache, sizeof(s_modelcache) * cache_map_max_items);
4136 		if(model_cache == NULL) shutdown(1, "Out Of Memory!  Failed to create a new cache_map\n");
4137 	}
4138 }
4139 
cache_model(char * name,char * path,int flag)4140 void cache_model(char *name, char *path, int flag)
4141 {
4142 	int len;
4143 	printf("Cacheing '%s' from %s\n", name, path);
4144 	prepare_cache_map(models_cached+1);
4145 	memset(&model_cache[models_cached], 0, sizeof(s_modelcache));
4146 
4147 	len = strlen(name);
4148 	model_cache[models_cached].name = malloc(len + 1);
4149 	strcpy(model_cache[models_cached].name, name);
4150 	model_cache[models_cached].name[len] = 0;
4151 
4152 	len = strlen(path);
4153 	model_cache[models_cached].path = malloc(len + 1);
4154 	strcpy(model_cache[models_cached].path, path);
4155 	model_cache[models_cached].path[len] = 0;
4156 
4157 	model_cache[models_cached].loadflag = flag;
4158 
4159 	_peek_model_name(models_cached);
4160 	++models_cached;
4161 }
4162 
4163 
free_modelcache()4164 void free_modelcache()
4165 {
4166 	if(model_cache != NULL)
4167 	{
4168 		while(models_cached)
4169 		{
4170 			--models_cached;
4171 			free(model_cache[models_cached].name);
4172 			model_cache[models_cached].name = NULL;
4173 			free(model_cache[models_cached].path);
4174 			model_cache[models_cached].path = NULL;
4175 		}
4176 		free(model_cache);
4177 		model_cache = NULL;
4178 	}
4179 }
4180 
4181 
get_cached_model_index(char * name)4182 int get_cached_model_index(char * name)
4183 {
4184 	int i;
4185 	for(i=0; i<models_cached; i++)
4186 	{
4187 		if(stricmp(name, model_cache[i].name)==0) return i;
4188 	}
4189 	return -1;
4190 }
4191 
get_cached_model_path(char * name)4192 char *get_cached_model_path(char * name)
4193 {
4194 	int i;
4195 	for(i=0; i<models_cached; i++)
4196 	{
4197 		if(stricmp(name, model_cache[i].name)==0) return model_cache[i].path;
4198 	}
4199 	return NULL;
4200 }
4201 
4202 static void _readbarstatus(char*, s_barstatus*);
4203 
lcmHandleCommandName(ArgList * arglist,s_model * newchar,int cacheindex)4204 void lcmHandleCommandName(ArgList* arglist, s_model* newchar, int cacheindex) {
4205 	char* value = GET_ARGP(1);
4206 	s_model* tempmodel;
4207 	if((tempmodel=findmodel(value)) && tempmodel!=newchar) shutdown(1, "Duplicate model name '%s'", value);
4208 	/*if((tempmodel=find_model(value))) {
4209 		return tempmodel;
4210 	}*/
4211 	model_cache[cacheindex].model = newchar;
4212 	newchar->name = model_cache[cacheindex].name;
4213 	if(stricmp(newchar->name, "steam")==0)
4214 	{
4215 		newchar->alpha = 1;
4216 	}
4217 }
4218 
lcmHandleCommandType(ArgList * arglist,s_model * newchar,char * filename)4219 void lcmHandleCommandType(ArgList* arglist, s_model* newchar, char* filename) {
4220 	char* value = GET_ARGP(1);
4221 	int i;
4222 	if(stricmp(value, "none")==0){
4223 		newchar->type = TYPE_NONE;
4224 	}
4225 	else if(stricmp(value, "player")==0){
4226 		newchar->type = TYPE_PLAYER;
4227 		newchar->nopassiveblock = 1;
4228 		for(i=0; i<MAX_ATCHAIN; i++)
4229 		{
4230 			if(i < 2 || i > 3) newchar->atchain[i] = 1;
4231 			else newchar->atchain[i] = i;
4232 		}
4233 		newchar->chainlength            = 4;
4234 		newchar->bounce                 = 1;
4235 		newchar->subject_to_wall        = 1;
4236 		newchar->subject_to_platform    = 1;
4237 		newchar->subject_to_obstacle    = 1;
4238 		newchar->subject_to_hole        = 1;
4239 		newchar->subject_to_gravity     = 1;
4240 		newchar->subject_to_screen      = 1;
4241 		newchar->subject_to_minz        = 1;
4242 		newchar->subject_to_maxz        = 1;
4243 		newchar->no_adjust_base         = 0;
4244 	}
4245 	else if(stricmp(value, "enemy")==0){
4246 		newchar->type                   = TYPE_ENEMY;
4247 		newchar->bounce                 = 1;
4248 		newchar->subject_to_wall        = 1;
4249 		newchar->subject_to_platform    = 1;
4250 		newchar->subject_to_hole        = 1;
4251 		newchar->subject_to_obstacle    = 1;
4252 		newchar->subject_to_gravity     = 1;
4253 		newchar->subject_to_minz        = 1;
4254 		newchar->subject_to_maxz        = 1;
4255 		newchar->no_adjust_base         = 0;
4256 	}
4257 	else if(stricmp(value, "item")==0){
4258 		newchar->type                   = TYPE_ITEM;
4259 		newchar->subject_to_wall        = 1;
4260 		newchar->subject_to_platform    = 1;
4261 		newchar->subject_to_hole        = 1;
4262 		newchar->subject_to_obstacle    = 1;
4263 		newchar->subject_to_gravity     = 1;
4264 		newchar->subject_to_minz        = 1;
4265 		newchar->subject_to_maxz        = 1;
4266 		newchar->no_adjust_base         = 0;
4267 	}
4268 	else if(stricmp(value, "obstacle")==0){
4269 		newchar->type                   = TYPE_OBSTACLE;
4270 		if(newchar->aimove==-1) newchar->aimove = 0;
4271 		newchar->aimove |= AIMOVE1_NOMOVE;
4272 		if(newchar->aimove==-1) newchar->aiattack = 0;
4273 		newchar->aimove |= AIATTACK1_NOATTACK;
4274 		newchar->subject_to_wall        = 1;
4275 		newchar->subject_to_platform    = 1;
4276 		newchar->subject_to_hole        = 1;
4277 		newchar->subject_to_gravity     = 1;
4278 		newchar->subject_to_minz        = 1;
4279 		newchar->subject_to_maxz        = 1;
4280 		newchar->no_adjust_base         = 0;
4281 	}
4282 	else if(stricmp(value, "steamer")==0){
4283 		newchar->type = TYPE_STEAMER;
4284 	}
4285 	// my new types   7-1-2005
4286 	else if(stricmp(value, "pshot")==0){
4287 		newchar->type = TYPE_SHOT;
4288 		if(newchar->aimove==-1) newchar->aimove = 0;
4289 		newchar->aimove |= AIMOVE1_ARROW;
4290 		if(!newchar->offscreenkill) newchar->offscreenkill = 200;
4291 		newchar->subject_to_hole                = 0;
4292 		newchar->subject_to_gravity             = 1;
4293 		newchar->subject_to_wall                = 0;
4294 		newchar->subject_to_platform            = 0;
4295 		newchar->subject_to_screen              = 0;
4296 		newchar->subject_to_minz                = 1;
4297 		newchar->subject_to_maxz                = 1;
4298 		newchar->subject_to_platform            = 0;
4299 		newchar->no_adjust_base                 = 1;
4300 	}
4301 	else if(stricmp(value, "trap")==0){
4302 		newchar->type                   = TYPE_TRAP;
4303 		newchar->subject_to_wall        = 1;
4304 		newchar->subject_to_platform    = 1;
4305 		newchar->subject_to_hole        = 1;
4306 		newchar->subject_to_gravity     = 1;
4307 		newchar->subject_to_minz        = 1;
4308 		newchar->subject_to_maxz        = 1;
4309 		newchar->no_adjust_base         = 0;
4310 	}
4311 	else if(stricmp(value, "text")==0){    // Used for displaying text/images and freezing the screen
4312 		newchar->type                   = TYPE_TEXTBOX;
4313 		newchar->subject_to_gravity     = 0;
4314 		newchar->subject_to_minz        = 1;
4315 		newchar->subject_to_maxz        = 1;
4316 	}
4317 	else if(stricmp(value, "endlevel")==0){    // Used for ending the level when the players reach a certain point
4318 		newchar->type                   = TYPE_ENDLEVEL;
4319 		newchar->subject_to_wall        = 1;
4320 		newchar->subject_to_platform    = 1;
4321 		newchar->subject_to_hole        = 1;
4322 		newchar->subject_to_obstacle    = 1;
4323 		newchar->subject_to_gravity     = 1;
4324 	}
4325 	else if(stricmp(value, "npc")==0){    // NPC type
4326 		newchar->type                   = TYPE_NPC;
4327 		newchar->bounce                 = 1;
4328 		newchar->subject_to_wall        = 1;
4329 		newchar->subject_to_platform    = 1;
4330 		newchar->subject_to_hole        = 1;
4331 		newchar->subject_to_obstacle    = 1;
4332 		newchar->subject_to_gravity     = 1;
4333 		newchar->subject_to_minz        = 1;
4334 		newchar->subject_to_maxz        = 1;
4335 		newchar->no_adjust_base         = 0;
4336 	}
4337 	else if(stricmp(value, "panel")==0){    // NPC type
4338 		newchar->type                   = TYPE_PANEL;
4339 		newchar->antigravity            = 1.0; //float type
4340 		newchar->subject_to_gravity     = 1;
4341 		newchar->no_adjust_base         = 1;
4342 	}
4343 	else shutdown(1, "Model '%s' has invalid type: '%s'", filename, value);
4344 }
4345 
lcmHandleCommandSubtype(ArgList * arglist,s_model * newchar,char * filename)4346 void lcmHandleCommandSubtype(ArgList* arglist, s_model* newchar, char* filename) {
4347 	char* value = GET_ARGP(1);
4348 	int i;
4349 	if(stricmp(value, "biker")==0){
4350 		newchar->subtype                                        = SUBTYPE_BIKER;
4351 		if(newchar->aimove==-1) newchar->aimove                 = 0;
4352 		newchar->aimove |= AIMOVE1_BIKER;
4353 		for(i=0; i<MAX_ATKS; i++) newchar->defense_factors[i]   = 2;
4354 		if(!newchar->offscreenkill) newchar->offscreenkill = 300;
4355 		newchar->subject_to_hole                                = 1;
4356 		newchar->subject_to_gravity                             = 1;
4357 		newchar->subject_to_wall                                = 0;
4358 		newchar->subject_to_platform                            = 0;
4359 		newchar->subject_to_screen                              = 0;
4360 		newchar->subject_to_minz                                = 1;
4361 		newchar->subject_to_maxz                                = 1;
4362 		newchar->subject_to_platform                            = 0;
4363 		newchar->no_adjust_base                                 = 0;
4364 	}
4365 	else if(stricmp(value, "arrow")==0){  // 7-1-2005 Arrow type
4366 		newchar->subtype = SUBTYPE_ARROW;   // 7-1-2005 Arrow type
4367 		if(newchar->aimove==-1) newchar->aimove = 0;
4368 		newchar->aimove |= AIMOVE1_ARROW;
4369 		if(!newchar->offscreenkill) newchar->offscreenkill = 200;
4370 		newchar->subject_to_hole        = 0;
4371 		newchar->subject_to_gravity     = 1;
4372 		newchar->subject_to_wall        = 0;
4373 		newchar->subject_to_platform    = 0;
4374 		newchar->subject_to_screen      = 0;
4375 		newchar->subject_to_minz        = 1;
4376 		newchar->subject_to_maxz        = 1;
4377 		newchar->subject_to_platform    = 0;
4378 		newchar->no_adjust_base         = 1;
4379 	}
4380 	else if(stricmp(value, "notgrab")==0){  // 7-1-2005 notgrab type
4381 		newchar->subtype = SUBTYPE_NOTGRAB;   // 7-1-2005 notgrab type
4382 	}
4383 	//    ltb 1-18-05  Item Subtype
4384 	else if(stricmp(value, "touch")==0){  // 7-1-2005 notgrab type
4385 		newchar->subtype = SUBTYPE_TOUCH;   // 7-1-2005 notgrab type
4386 	}
4387 	else if(stricmp(value, "weapon")==0){  // 7-1-2005 notgrab type
4388 		newchar->subtype = SUBTYPE_WEAPON;   // 7-1-2005 notgrab type
4389 	}
4390 	else if(stricmp(value, "noskip")==0){    // Text animation cannot be skipped if subtype noskip
4391 		newchar->subtype = SUBTYPE_NOSKIP;
4392 	}
4393 	else if(stricmp(value, "flydie")==0){    // Obstacle will fly across the screen when hit if subtype flydie
4394 		newchar->subtype = SUBTYPE_FLYDIE;
4395 	}
4396 	else if(stricmp(value, "both")==0){
4397 		newchar->subtype = SUBTYPE_BOTH;
4398 	}
4399 	else if(stricmp(value, "project")==0){
4400 		newchar->subtype = SUBTYPE_PROJECTILE;
4401 	}
4402 	else if(stricmp(value, "follow")==0){
4403 		newchar->subtype = SUBTYPE_FOLLOW;
4404 	}
4405 	else if(stricmp(value, "chase")==0){
4406 		newchar->subtype = SUBTYPE_CHASE;
4407 	}
4408 	//    end new subtype
4409 	else shutdown(1, "Model '%s' has invalid subtype: '%s'", filename, value);
4410 }
4411 
lcmHandleCommandSmartbomb(ArgList * arglist,s_model * newchar,char * filename)4412 void lcmHandleCommandSmartbomb(ArgList* arglist, s_model* newchar, char* filename) {
4413 	//smartbomb now use a normal attack box
4414 	if(!newchar->smartbomb) {
4415 		newchar->smartbomb = malloc(sizeof(s_attack));
4416 		*(newchar->smartbomb) = emptyattack;
4417 	} else shutdown(1, "Model '%s' has multiple smartbomb commands defined.", filename);
4418 
4419 	newchar->smartbomb->attack_force = atoi(GET_ARGP(1));			// Special force
4420 	newchar->smartbomb->attack_type = atoi(GET_ARGP(2));			// Special attack type
4421 	newchar->smartbomb->attack_drop = 1; //by default
4422 	newchar->smartbomb->dropv[0] = 3;
4423 
4424 	if(newchar->smartbomb->attack_type==ATK_BLAST) {
4425 		newchar->smartbomb->blast = 1;
4426 		newchar->smartbomb->dropv[1] = 2.5;
4427 	} else {
4428 		newchar->smartbomb->dropv[1] = (float)1.2;
4429 	}
4430 
4431 	if(newchar->smartbomb->attack_type==ATK_FREEZE) {
4432 		newchar->smartbomb->freeze = 1;
4433 		newchar->smartbomb->forcemap = -1;
4434 		newchar->smartbomb->attack_drop = 0;
4435 	} else if(newchar->smartbomb->attack_type==ATK_STEAL) {
4436 		newchar->smartbomb->steal = 1;
4437 	}
4438 
4439 	if(newchar->type == TYPE_ITEM) {
4440 		newchar->dofreeze = 0;								// Items don't animate
4441 		newchar->smartbomb->freezetime = atoi(GET_ARGP(3)) * GAME_SPEED;
4442 	} else {
4443 		newchar->dofreeze = atoi(GET_ARGP(3));		// Are all animations frozen during special
4444 		newchar->smartbomb->freezetime = atoi(GET_ARGP(4)) * GAME_SPEED;
4445 	}
4446 }
4447 
lcmHandleCommandHostile(ArgList * arglist,s_model * newchar)4448 void lcmHandleCommandHostile(ArgList* arglist, s_model* newchar) {
4449 	int i = 1;
4450 	char* value = GET_ARGP(i);
4451 	newchar->hostile = 0;
4452 
4453 	while(value && value[0])
4454 	{
4455 		if(stricmp(value, "enemy")==0){
4456 			newchar->hostile |= TYPE_ENEMY;
4457 		} else if(stricmp(value, "player")==0){
4458 			newchar->hostile |= TYPE_PLAYER;
4459 		} else if(stricmp(value, "obstacle")==0){
4460 			newchar->hostile |= TYPE_OBSTACLE;
4461 		} else if(stricmp(value, "shot")==0){
4462 			newchar->hostile |= TYPE_SHOT;
4463 		} else if(stricmp(value, "npc")==0){
4464 			newchar->hostile |= TYPE_NPC;
4465 		}
4466 		i++;
4467 		value = GET_ARGP(i);
4468 	}
4469 }
lcmHandleCommandCandamage(ArgList * arglist,s_model * newchar)4470 void lcmHandleCommandCandamage(ArgList* arglist, s_model* newchar) {
4471 	int i = 1;
4472 	char* value = GET_ARGP(i);
4473 	newchar->candamage = 0;
4474 
4475 	while(value && value[0])
4476 	{
4477 		if(stricmp(value, "enemy")==0){
4478 			newchar->candamage |= TYPE_ENEMY;
4479 		} else if(stricmp(value, "player")==0){
4480 			newchar->candamage |= TYPE_PLAYER;
4481 		} else if(stricmp(value, "obstacle")==0){
4482 			newchar->candamage |= TYPE_OBSTACLE;
4483 		} else if(stricmp(value, "shot")==0){
4484 			newchar->candamage |= TYPE_SHOT;
4485 		} else if(stricmp(value, "npc")==0){
4486 			newchar->candamage |= TYPE_NPC;
4487 		} else if(stricmp(value, "ground")==0){ // not really needed, though
4488 			newchar->ground = 1;
4489 		}
4490 		i++;
4491 		value = GET_ARGP(i);
4492 	}
4493 }
4494 
lcmHandleCommandProjectilehit(ArgList * arglist,s_model * newchar)4495 void lcmHandleCommandProjectilehit(ArgList* arglist, s_model* newchar) {
4496 	int i = 1;
4497 	char* value = GET_ARGP(i);
4498 
4499 	newchar->projectilehit = 0;
4500 
4501 	while(value && value[0])
4502 	{
4503 		if(stricmp(value, "enemy")==0){
4504 			newchar->projectilehit |= TYPE_ENEMY;
4505 		} else if(stricmp(value, "player")==0){
4506 			newchar->projectilehit |= TYPE_PLAYER;
4507 		} else if(stricmp(value, "obstacle")==0){
4508 			newchar->projectilehit |= TYPE_OBSTACLE;
4509 		} else if(stricmp(value, "shot")==0){
4510 			newchar->projectilehit |= TYPE_SHOT;
4511 		} else if(stricmp(value, "npc")==0){
4512 			newchar->projectilehit |= TYPE_NPC;
4513 		}
4514 		i++;
4515 		value = GET_ARGP(i);
4516 	}
4517 }
4518 
lcmHandleCommandAimove(ArgList * arglist,s_model * newchar,int * aimoveset,char * filename)4519 void lcmHandleCommandAimove(ArgList* arglist, s_model* newchar, int* aimoveset, char* filename) {
4520 	char* value = GET_ARGP(1);
4521 	if(!*aimoveset)
4522 	{
4523 		newchar->aimove = 0;
4524 		*aimoveset = 1;
4525 	}
4526 
4527 	//main A.I. move switches
4528 	if(value && value[0])
4529 	{
4530 		if(stricmp(value, "normal")==0){
4531 			newchar->aimove |= AIMOVE1_NORMAL;
4532 		}
4533 		else if(stricmp(value, "chase")==0){
4534 			newchar->aimove |= AIMOVE1_CHASE;
4535 		}
4536 		else if(stricmp(value, "chasex")==0){
4537 			newchar->aimove |= AIMOVE1_CHASEX;
4538 		}
4539 		else if(stricmp(value, "chasez")==0){
4540 			newchar->aimove |= AIMOVE1_CHASEZ;
4541 		}
4542 		else if(stricmp(value, "avoid")==0){
4543 			newchar->aimove |= AIMOVE1_AVOID;
4544 		}
4545 		else if(stricmp(value, "avoidx")==0){
4546 			newchar->aimove |= AIMOVE1_AVOIDX;
4547 		}
4548 		else if(stricmp(value, "avoidz")==0){
4549 			newchar->aimove |= AIMOVE1_AVOIDZ;
4550 		}
4551 		else if(stricmp(value, "wander")==0){
4552 			newchar->aimove |= AIMOVE1_WANDER;
4553 		}
4554 		else if(stricmp(value, "biker")==0){
4555 			newchar->aimove |= AIMOVE1_BIKER;
4556 		}
4557 		else if(stricmp(value, "arrow")==0){
4558 			newchar->aimove |= AIMOVE1_ARROW;
4559 			if(!newchar->offscreenkill) newchar->offscreenkill = 200;
4560 		}
4561 		else if(stricmp(value, "star")==0){
4562 			newchar->aimove |= AIMOVE1_STAR;
4563 		}
4564 		else if(stricmp(value, "bomb")==0){
4565 			newchar->aimove |= AIMOVE1_BOMB;
4566 		}
4567 		else if(stricmp(value, "nomove")==0){
4568 			newchar->aimove |= AIMOVE1_NOMOVE;
4569 		}
4570 		else shutdown(1, "Model '%s' has invalid A.I. move switch: '%s'", filename, value);
4571 	}
4572 	value = GET_ARGP(2);
4573 	//sub A.I. move switches
4574 	if(value && value[0])
4575 	{
4576 		if(stricmp(value, "normal")==0){
4577 			newchar->aimove |= AIMOVE2_NORMAL;
4578 		}
4579 		else if(stricmp(value, "ignoreholes")==0){
4580 			newchar->aimove |= AIMOVE2_IGNOREHOLES;
4581 		}
4582 		else if(stricmp(value, "notargetidle")==0){
4583 			newchar->aimove |= AIMOVE2_NOTARGETIDLE;
4584 		}
4585 		else shutdown(1, "Model '%s' has invalid A.I. move switch: '%s'", filename, value);
4586 	}
4587 }
4588 
lcmHandleCommandWeapons(ArgList * arglist,s_model * newchar)4589 void lcmHandleCommandWeapons(ArgList* arglist, s_model* newchar) {
4590 	int weap;
4591 	char* value;
4592 	int last = 0;
4593 	if(!newchar->weapon)
4594 	{
4595 		newchar->weapon = malloc(sizeof(*newchar->weapon));
4596 		memset(newchar->weapon, 0xFF, sizeof(*newchar->weapon));
4597 		newchar->ownweapons = 1;
4598 	}
4599 	for(weap = 0; weap<MAX_WEAPONS; weap++){
4600 		value = GET_ARGP(weap+1);
4601 		if(value[0]){
4602 			if(stricmp(value, "none")!=0){
4603 				(*newchar->weapon)[weap] = get_cached_model_index(value);
4604 			} else { // make empty weapon slots  2007-2-16
4605 				(*newchar->weapon)[weap] = -1;
4606 			}
4607 			last = weap;
4608 		}
4609 		else (*newchar->weapon)[weap] = (*newchar->weapon)[last];
4610 	}
4611 }
lcmHandleCommandScripts(ArgList * arglist,Script * script,char * scriptname,char * filename)4612 void lcmHandleCommandScripts(ArgList* arglist, Script* script, char* scriptname, char* filename) {
4613 	Script_Init(script, scriptname, 0);
4614 	if(load_script(script, GET_ARGP(1)))
4615 		Script_Compile(script);
4616 	else shutdown(1, "Unable to load %s '%s' in file '%s'.\n", scriptname, GET_ARGP(1), filename);
4617 }
4618 
4619 //alloc a new model, and everything thats required,
4620 //set all values to defaults
init_model(int cacheindex,int unload)4621 s_model* init_model(int cacheindex, int unload) {
4622 	//to free: newchar, newchar->offense_factors, newchar->special, newchar->animation - OK
4623 	int i;
4624 
4625 	s_model* newchar = calloc(1, sizeof(s_model));
4626 	if(!newchar) shutdown(1, (char*)E_OUT_OF_MEMORY);
4627 	newchar->name = model_cache[cacheindex].name; // well give it a name for sort method
4628 	newchar->index = cacheindex;
4629 	newchar->isSubclassed = 0;
4630 	newchar->freetypes = MF_ALL;
4631 
4632 	newchar->defense_factors        = (float*)calloc(1, sizeof(float)*(max_attack_types + 1));
4633 	newchar->defense_pain           = (float*)calloc(1, sizeof(float)*(max_attack_types + 1));
4634 	newchar->defense_knockdown      = (float*)calloc(1, sizeof(float)*(max_attack_types + 1));
4635 	newchar->defense_blockpower     = (float*)calloc(1, sizeof(float)*(max_attack_types + 1));
4636 	newchar->defense_blockthreshold = (float*)calloc(1, sizeof(float)*(max_attack_types + 1));
4637 	newchar->defense_blockratio     = (float*)calloc(1, sizeof(float)*(max_attack_types + 1));
4638 	newchar->defense_blocktype      = (float*)calloc(1, sizeof(float)*(max_attack_types + 1));
4639 	newchar->offense_factors        = (float*)calloc(1, sizeof(float)*(max_attack_types + 1));
4640 
4641 	newchar->special                = calloc(1, sizeof(*newchar->special)*max_freespecials);
4642 	if(!newchar->special) shutdown(1, (char*)E_OUT_OF_MEMORY);
4643 
4644 	alloc_all_scripts(&newchar->scripts);
4645 
4646 	newchar->unload             = unload;
4647 	newchar->jumpspeed          = -1;
4648 	newchar->jumpheight         = 4;		        // 28-12-2004   Set default jump height to 4, if not specified
4649 	newchar->runjumpheight      = 4;		        // Default jump height if a player is running
4650 	newchar->runjumpdist        = 1;		        // Default jump distane if a player is running
4651 	newchar->grabdistance       = 36;		        //  30-12-2004 Default grabdistance is same as originally set
4652 	newchar->grabflip		    = 3;
4653 	newchar->throwdamage        = 21;		        // default throw damage
4654 	newchar->icon.def               = -1;
4655 	newchar->icon.die            = -1;
4656 	newchar->icon.pain           = -1;
4657 	newchar->icon.get            = -1;
4658 	newchar->icon.weapon              = -1;			    // No weapon icon set yet
4659 	newchar->diesound           = -1;
4660 	newchar->nolife             = 0;			    // default show life = 1 (yes)
4661 	newchar->remove             = 1;			    // Flag set to weapons are removed upon hitting an opponent
4662 	newchar->throwdist          = 2.5;
4663 	newchar->counter            = 3;			    // Default 3 times to drop a weapon / projectile
4664 	newchar->aimove             = -1;
4665 	newchar->aiattack           = -1;
4666 	newchar->throwframewait     = -1;               // makes sure throw animations run normally unless throwfram is specified, added by kbandressen 10/20/06
4667 	newchar->path               = model_cache[cacheindex].path;         // Record path, so script can get it without looping the whole model collection.
4668 	newchar->icon.mphigh        = -1;               //No mphigh icon yet.
4669     newchar->icon.mplow         = -1;               //No mplow icon yet.
4670     newchar->icon.mpmed         = -1;               //No mpmed icon yet.
4671 
4672 		// Default Attack1 in chain must be referenced if not used.
4673 	for(i=0; i<MAX_ATCHAIN; i++) newchar->atchain[i] = 1;
4674 	newchar->chainlength = 1;
4675 
4676 	if(magic_type == 1) newchar->mprate = 1;
4677 	else newchar->mprate                = 2;
4678 	newchar->chargerate = newchar->guardrate = 2;
4679 	newchar->risetime[0]                = -1;
4680 	newchar->sleepwait                  = 1000;
4681 	newchar->jugglepoints.current = newchar->jugglepoints.maximum = 0;
4682 	newchar->guardpoints.current = newchar->guardpoints.maximum = 0;
4683 	newchar->mpswitch                   = -1;       // switch between reduce mp or gain mp for mpstabletype 4
4684 	newchar->weaploss[0]                = -1;
4685 	newchar->weaploss[1]                = -1;
4686 	newchar->lifespan                   = (float)0xFFFFFFFF;
4687 	newchar->summonkill                 = 1;
4688 	newchar->candamage                  = -1;
4689 	newchar->hostile                    = -1;
4690 	newchar->projectilehit              = -1;
4691 	newchar->subject_to_wall            = -1;
4692 	newchar->subject_to_platform        = -1;
4693 	newchar->subject_to_obstacle        = -1;
4694 	newchar->subject_to_hole            = -1;
4695 	newchar->subject_to_gravity         = -1;
4696 	newchar->subject_to_screen          = -1;
4697 	newchar->subject_to_minz            = -1;
4698 	newchar->subject_to_maxz            = -1;
4699 	newchar->no_adjust_base             = -1;
4700 	newchar->pshotno                    = -1;
4701 	newchar->project                    = -1;
4702 	newchar->dust[0]                    = -1;
4703 	newchar->dust[1]                    = -1;
4704 	newchar->dust[2]                    = -1;
4705 	newchar->bomb                       = -1;
4706 	newchar->star                       = -1;
4707 	newchar->knife                      = -1;
4708     newchar->stealth.hide               = 0;
4709     newchar->stealth.detect             = 0;
4710 
4711 	newchar->animation = (s_anim**)calloc(1, sizeof(s_anim*)*max_animations);
4712 	if(!newchar->animation) shutdown(1, (char*)E_OUT_OF_MEMORY);
4713 
4714 	// default string value, only by reference
4715 	newchar->rider = get_cached_model_index("K'");
4716 	newchar->flash = newchar->bflash = get_cached_model_index("flash");
4717 
4718 	//Default offense/defense values.
4719 	for(i=0;i<max_attack_types;i++)
4720 	{
4721 		newchar->offense_factors[i]     = 1;
4722 		newchar->defense_factors[i]     = 1;
4723 		newchar->defense_knockdown[i]   = 1;
4724 	}
4725 
4726 	//Default sight ranges.
4727     newchar->sight.amin = -9999;
4728     newchar->sight.amax = 9999;
4729     newchar->sight.xmin = -9999;
4730     newchar->sight.xmax = 9999;
4731     newchar->sight.zmin = -9999;
4732     newchar->sight.zmax = 9999;
4733 
4734 	newchar->offense_factors[ATK_BLAST]     = 1;
4735 	newchar->defense_factors[ATK_BLAST]     = 1;
4736 	newchar->defense_knockdown[ATK_BLAST]   = 1;
4737 	newchar->offense_factors[ATK_BURN]      = 1;
4738 	newchar->defense_factors[ATK_BURN]      = 1;
4739 	newchar->defense_knockdown[ATK_BURN]    = 1;
4740 	newchar->offense_factors[ATK_FREEZE]    = 1;
4741 	newchar->defense_factors[ATK_FREEZE]    = 1;
4742 	newchar->defense_knockdown[ATK_FREEZE]  = 1;
4743 	newchar->offense_factors[ATK_SHOCK]     = 1;
4744 	newchar->defense_factors[ATK_SHOCK]     = 1;
4745 	newchar->defense_knockdown[ATK_SHOCK]   = 1;
4746 	newchar->offense_factors[ATK_STEAL]     = 1;
4747 	newchar->defense_factors[ATK_STEAL]     = 1;
4748 	newchar->defense_knockdown[ATK_STEAL]   = 1;
4749 
4750 	return newchar;
4751 }
4752 
update_model_loadflag(s_model * model,char unload)4753 void update_model_loadflag(s_model* model, char unload) {
4754 	model->unload = unload;
4755 }
4756 
load_cached_model(char * name,char * owner,char unload)4757 s_model* load_cached_model(char * name, char * owner, char unload)
4758 {
4759 	s_model *newchar = NULL,
4760 	*tempmodel = NULL;
4761 
4762 	s_anim *newanim = NULL;
4763 
4764 	char *filename = NULL,
4765 	*buf = NULL,
4766 	*scriptbuf = NULL,
4767 	*command = NULL,
4768 	*value = NULL,
4769 	*value2 = NULL,
4770 	*value3 = NULL;
4771 
4772 	char
4773 		namebuf[256] = {""},
4774 		argbuf[MAX_ARG_LEN+1] = "";
4775 
4776 	ArgList arglist;
4777 
4778 	float tempFloat;
4779 
4780 	int ani_id = -1,
4781 		script_id = -1,
4782 		i = 0,
4783 		j = 0,
4784 		tempInt = 0,
4785 		framecount = 0,
4786 		frameset = 0,
4787 		peek = 0,
4788 		cacheindex = 0,
4789 		curframe = 0,
4790 		delay = 0,
4791 		errorVal = 0,
4792 		shadow_set = 0,
4793 		idle = 0,
4794 		move = 0,
4795 		movez = 0,
4796 		movea = 0,
4797 		seta = -1,			// Used for setting custom "a". Set to -1 to distinguish between disabled and setting "a" to 0
4798 		frameshadow = -1,	// -1 will use default shadow for this entity, otherwise will use this value
4799 		soundtoplay = -1,
4800 		aimoveset = 0,
4801 		maskindex = -1;
4802 
4803 	size_t size = 0,
4804 		line = 0,
4805 		len = 0;
4806 
4807 	ptrdiff_t pos = 0,
4808 		index = 0;
4809 
4810 	short bbox[5] = { 0,0,0,0,0 },
4811 		bbox_con[5] = { 0,0,0,0,0 },
4812 		abox[5] = { 0,0,0,0,0 },
4813 		offset[2] = { 0,0 },
4814 		shadow_xz[2] = {0,0},
4815 		shadow_coords[2] = {0,0};
4816 
4817 	float platform[8] = { 0,0,0,0,0,0,0,0 },
4818 		platform_con[8] = { 0,0,0,0,0,0,0,0 };
4819 
4820 	s_attack attack,
4821 	*pattack = NULL;
4822 	char* shutdownmessage = NULL;
4823 
4824 	s_drawmethod drawmethod;
4825 
4826 	unsigned char mapflag[MAX_COLOUR_MAPS]; // in 24bit mode, we need to know whether a colourmap is a common map or a palette
4827 
4828 	static const char* pre_text =  // this is the skeleton of frame function
4829 		"void main()\n"
4830 		"{\n"
4831 		"    int frame = getlocalvar(\"frame\");\n"
4832 		"    int animnum = getlocalvar(\"animnum\");\n"
4833 		"\n}\n";
4834 
4835 	static const char* sur_text = // end of function text
4836 		"\n}\n";
4837 
4838 	static const char* ifid_text = // if expression to check animation id
4839 		"    if(animnum==%d)\n"
4840 		"    {\n"
4841 		"        return;\n"
4842 		"    }\n";
4843 
4844 	static const char* endifid_text = // end of if
4845 		"        return;\n"
4846 		"    }\n";
4847 
4848 	static const char* if_text = // this is the if expression of frame function
4849 		"        if(frame==%d)\n"
4850 		"        {\n";
4851 
4852 	static const char* endif_text = // end of if
4853 		"\n"
4854 		"        }\n" ;
4855 
4856 	static const char* comma_text = // arguments separator
4857 		", ";
4858 
4859 	static const char* call_text = //begin of function call
4860 		"            %s(";
4861 
4862 	static const char* endcall_text = //end of function call
4863 		");\n";
4864 
4865 	modelCommands cmd;
4866 	s_scripts tempscripts;
4867 
4868 #ifdef DEBUG
4869 	printf("load_cached_model: %s, unload: %d\n", name, unload);
4870 #endif
4871 
4872 	// Model already loaded but we might want to unload after level is completed.
4873 	if((tempmodel=findmodel(name))!=NULL) {
4874 		update_model_loadflag(tempmodel,unload);
4875 		return tempmodel;
4876 	}
4877 
4878 	cacheindex = get_cached_model_index(name);
4879 	if(cacheindex < 0) shutdown(1, "Fatal: No cache entry for '%s' within '%s'\n\n", name, owner);
4880 
4881 	filename = model_cache[cacheindex].path;
4882 
4883 	if(buffer_pakfile(filename, &buf, &size)!=1) shutdown(1, "Unable to open file '%s'\n\n", filename);
4884 
4885 	scriptbuf = (char*)malloc(size*2+1);
4886 
4887 	if(scriptbuf==NULL){
4888 		shutdown(1, "Unable to create script buffer for file '%s' (%i bytes)", filename, size*2);
4889 	}
4890 	scriptbuf[0] = 0;
4891 
4892 	//_peek_model_name(cacheindex);
4893 	newchar = init_model(cacheindex, unload);
4894 	//newchar->name = name;
4895 
4896 	//attention, we increase models_loaded here, this can be dangerous if we access that value later on,
4897 	//since recursive calls will change it!
4898 	models_loaded++;
4899 	addModel(newchar);
4900 
4901 	attack = emptyattack;      // empty attack
4902 	drawmethod = plainmethod;  // better than memset it to 0
4903 	memset(mapflag, 0, MAX_COLOUR_MAPS);
4904 
4905 
4906 	//char* test = "load   knife 0";
4907 	//ParseArgs(&arglist,test,argbuf);
4908 
4909 	// Now interpret the contents of buf line by line
4910 	while(pos<size)
4911 	{
4912 		//command = GET_ARG(0);
4913 		line++;
4914 		if(ParseArgs(&arglist,buf+pos,argbuf)){
4915 			command = GET_ARG(0);
4916 			cmd = getModelCommand(modelcmdlist, command);
4917 
4918 			switch(cmd) {
4919 				case CMD_MODEL_SUBCLASS:
4920 					//inherit everything from an existing, cached model
4921 					tempmodel = findmodel(GET_ARG(1));
4922 					if (!tempmodel) {
4923 						shutdownmessage = "tried to subclass a non-existing/not previously loaded model!";
4924 						goto lCleanup;
4925 					}
4926 					tempscripts = newchar->scripts;
4927 					*newchar = *tempmodel;
4928 					newchar->scripts = tempscripts;
4929 					copy_all_scripts(&tempmodel->scripts, &newchar->scripts, 1);
4930 					newchar->isSubclassed = 1;
4931 					newchar->freetypes = MF_SCRIPTS;
4932 					break;
4933 				case CMD_MODEL_NAME:
4934 					lcmHandleCommandName(&arglist, newchar, cacheindex);
4935 					break;
4936 				case CMD_MODEL_TYPE:
4937 					lcmHandleCommandType(&arglist, newchar, filename);
4938 					break;
4939 				case CMD_MODEL_SUBTYPE:
4940 					lcmHandleCommandSubtype(&arglist, newchar, filename);
4941 					break;
4942 				case CMD_MODEL_STATS:
4943 					value = GET_ARG(1);
4944 					newchar->stats[atoi(value)] = GET_FLOAT_ARG(2);
4945 					break;
4946 				case CMD_MODEL_HEALTH:
4947 					value = GET_ARG(1);
4948 					newchar->health = atoi(value);
4949 					break;
4950 				case CMD_MODEL_SCROLL:
4951 					value = GET_ARG(1);
4952 					newchar->scroll = atof(value);
4953 					break;
4954 				case CMD_MODEL_MP: //Left for backward compatability. See mpset. // mp values to put max mp for player by tails
4955 					value = GET_ARG(1);
4956 					newchar->mp = atoi(value);
4957 					break;
4958 				case CMD_MODEL_NOLIFE:	// Feb 25, 2005 - Flag to display enemy life or not
4959 					newchar->nolife = GET_INT_ARG(1);
4960 					break;
4961 				case CMD_MODEL_MAKEINV:	// Mar 12, 2005 - If a value is supplied, corresponds to amount of time the player spawns invincible
4962 					newchar->makeinv = GET_INT_ARG(1) * GAME_SPEED;
4963 					if(GET_INT_ARG(2)) newchar->makeinv = -newchar->makeinv;
4964 					break;
4965 				case CMD_MODEL_RISEINV:
4966 					newchar->riseinv = GET_INT_ARG(1) * GAME_SPEED;
4967 					if(GET_INT_ARG(2)) newchar->riseinv = -newchar->riseinv;
4968 					break;
4969 				case CMD_MODEL_LOAD:
4970 					value = GET_ARG(1);
4971 					tempmodel = findmodel(value);
4972 					if(!tempmodel)
4973 						load_cached_model(value, name, GET_INT_ARG(2));
4974 					else
4975 						update_model_loadflag(tempmodel, GET_INT_ARG(2));
4976 					break;
4977 				case CMD_MODEL_SCORE:
4978 					newchar->score = GET_INT_ARG(1);
4979 					newchar->multiple = GET_INT_ARG(2);			// New var multiple for force/scoring
4980 					break;
4981 				case CMD_MODEL_SMARTBOMB:
4982 					lcmHandleCommandSmartbomb(&arglist, newchar, filename);
4983 					break;
4984 				case CMD_MODEL_BOUNCE:
4985 					newchar->bounce = GET_INT_ARG(1);
4986 					break;
4987 				case CMD_MODEL_NOQUAKE:  // Mar 12, 2005 - Flag to determine if entity shakes screen
4988 					newchar->noquake = GET_INT_ARG(1);
4989 					break;
4990 				case CMD_MODEL_BLOCKBACK:	// Flag to determine if attacks can be blocked from behind
4991 					newchar->blockback = GET_INT_ARG(1);
4992 					break;
4993 				case CMD_MODEL_HITENEMY:	// Flag to determine if an enemy projectile will hit enemies
4994 					value = GET_ARG(1);
4995 					if(atoi(value) == 1)
4996 						newchar->candamage = newchar->hostile = TYPE_PLAYER | TYPE_ENEMY;
4997 					else if(atoi(value) == 2)
4998 						newchar->candamage = newchar->hostile = TYPE_PLAYER;
4999 					newchar->ground = GET_INT_ARG(2);    // Added to determine if enemies are damaged with mid air projectiles or ground only
5000 					break;
5001 				case CMD_MODEL_HOSTILE:
5002 					lcmHandleCommandHostile(&arglist, newchar);
5003 					break;
5004 				case CMD_MODEL_CANDAMAGE:
5005 					lcmHandleCommandCandamage(&arglist, newchar);
5006 					break;
5007 				case CMD_MODEL_PROJECTILEHIT:
5008 					lcmHandleCommandProjectilehit(&arglist, newchar);
5009 					break;
5010 				case CMD_MODEL_AIMOVE:
5011 					lcmHandleCommandAimove(&arglist, newchar, &aimoveset, filename);
5012 					break;
5013 				case CMD_MODEL_AIATTACK:
5014 					if(newchar->aiattack==-1) newchar->aiattack = 0;
5015 					//do nothing for now, until ai attack is implemented
5016 					break;
5017 				case CMD_MODEL_SUBJECT_TO_WALL:
5018 					newchar->subject_to_wall = (0!=GET_INT_ARG(1));
5019 					break;
5020 				case CMD_MODEL_SUBJECT_TO_HOLE:
5021 					newchar->subject_to_hole = (0!=GET_INT_ARG(1));
5022 					break;
5023 				case CMD_MODEL_SUBJECT_TO_PLATFORM:
5024 					newchar->subject_to_platform = (0!=GET_INT_ARG(1));
5025 					break;
5026 				case CMD_MODEL_SUBJECT_TO_OBSTACLE:
5027 					newchar->subject_to_obstacle = (0!=GET_INT_ARG(1));
5028 					break;
5029 				case CMD_MODEL_SUBJECT_TO_GRAVITY:
5030 					newchar->subject_to_gravity = (0!=GET_INT_ARG(1));
5031 					break;
5032 				case CMD_MODEL_SUBJECT_TO_SCREEN:
5033 					newchar->subject_to_screen = (0!=GET_INT_ARG(1));
5034 					break;
5035 				case CMD_MODEL_SUBJECT_TO_MINZ:
5036 					newchar->subject_to_minz = (0!=GET_INT_ARG(1));
5037 					break;
5038 				case CMD_MODEL_SUBJECT_TO_MAXZ:
5039 					newchar->subject_to_maxz = (0!=GET_INT_ARG(1));
5040 					break;
5041 				case CMD_MODEL_NO_ADJUST_BASE:
5042 					newchar->no_adjust_base = (0!=GET_INT_ARG(1));
5043 					break;
5044 				case CMD_MODEL_INSTANTITEMDEATH:
5045 					newchar->instantitemdeath = GET_INT_ARG(1);
5046 					break;
5047 				case CMD_MODEL_SECRET:
5048 					newchar->secret = GET_INT_ARG(1);
5049 					break;
5050 				case CMD_MODEL_MODELFLAG: //model copy flag
5051 					newchar->model_flag = GET_INT_ARG(1);
5052 					break;
5053 				// weapons
5054 				case CMD_MODEL_WEAPLOSS:
5055 					newchar->weaploss[0] = GET_INT_ARG(1);
5056 					newchar->weaploss[1] = GET_INT_ARG(2);
5057 					break;
5058 				case CMD_MODEL_WEAPNUM:
5059 					newchar->weapnum = GET_INT_ARG(1);
5060 					break;
5061 				case CMD_MODEL_PROJECT: // New projectile subtype
5062 					value = GET_ARG(1);
5063 					if(stricmp(value, "none")==0) newchar->project = -1;
5064 					else newchar->project = get_cached_model_index(value);
5065 					break;
5066 				case CMD_MODEL_WEAPONS:
5067 					lcmHandleCommandWeapons(&arglist, newchar);
5068 					break;
5069 				case CMD_MODEL_SHOOTNUM: //here weapons things like shoot rest type of weapon ect..by tails
5070 					newchar->shootnum = GET_INT_ARG(1);
5071 					break;
5072 				case CMD_MODEL_RELOAD:
5073 					newchar->reload = GET_INT_ARG(1);
5074 					break;
5075 				case CMD_MODEL_TYPESHOT:
5076 					newchar->typeshot = GET_INT_ARG(1);
5077 					break;
5078 				case CMD_MODEL_COUNTER:
5079 					newchar->counter = GET_INT_ARG(1);
5080 					break;
5081 				case CMD_MODEL_ANIMAL:
5082 					newchar->animal = GET_INT_ARG(1);
5083 					break;
5084 				case CMD_MODEL_RIDER:
5085 					value = GET_ARG(1);
5086 					if(stricmp(value, "none")==0) newchar->rider = -1;
5087 					else newchar->rider = get_cached_model_index(value);
5088 					break;
5089 				case CMD_MODEL_KNIFE: case CMD_MODEL_FIREB: case CMD_MODEL_PLAYSHOT: case CMD_MODEL_PLAYSHOTW:
5090 					value = GET_ARG(1);
5091 					if(stricmp(value, "none")==0) newchar->knife = -1;
5092 					else  newchar->knife = get_cached_model_index(value);
5093 					break;
5094 				case CMD_MODEL_PLAYSHOTNO:
5095 					value = GET_ARG(1);
5096 					if(stricmp(value, "none")==0) newchar->pshotno = -1;
5097 					else newchar->pshotno = get_cached_model_index(value);
5098 					break;
5099 				case CMD_MODEL_STAR:
5100 					value = GET_ARG(1);
5101 					if(stricmp(value, "none")==0) newchar->star = -1;
5102 					else newchar->star = get_cached_model_index(value);
5103 					break;
5104 				case CMD_MODEL_BOMB: case CMD_MODEL_PLAYBOMB:
5105 					value = GET_ARG(1);
5106 					if(stricmp(value, "none")==0) newchar->bomb = -1;
5107 					else newchar->bomb = get_cached_model_index(value);
5108 					break;
5109 				case CMD_MODEL_FLASH:	 // Now all characters can have their own flash - even projectiles (useful for blood)
5110 					value = GET_ARG(1);
5111 					if(stricmp(value, "none")==0) newchar->flash = -1;
5112 					else newchar->flash = get_cached_model_index(value);
5113 					break;
5114 				case CMD_MODEL_BFLASH:	// Flash that is spawned if an attack is blocked
5115 					value = GET_ARG(1);
5116 					if(stricmp(value, "none")==0) newchar->bflash = -1;
5117 					else newchar->bflash = get_cached_model_index(value);
5118 					break;
5119 				case CMD_MODEL_DUST:	// Spawned when hitting the ground to "kick up dust"
5120 					value = GET_ARG(1);
5121 					if(stricmp(value, "none")==0) newchar->dust[0] = -1;
5122 					else newchar->dust[0] = get_cached_model_index(value);
5123 					value = GET_ARG(2);
5124 					if(stricmp(value, "none")==0) newchar->dust[1] = -1;
5125 					else newchar->dust[1] = get_cached_model_index(value);
5126 					value = GET_ARG(3);
5127 					if(stricmp(value, "none")==0) newchar->dust[2] = -1;
5128 					else newchar->dust[2] = get_cached_model_index(value);
5129 					break;
5130 				case CMD_MODEL_BRANCH: // for endlevel item's level branch
5131 					value = GET_ARG(1);
5132 					if(!newchar->branch)
5133 					{
5134 						newchar->branch = malloc(MAX_NAME_LEN+1);
5135 						newchar->branch[0] = 0;
5136 					}
5137 					strncpy(newchar->branch, value, MAX_NAME_LEN);
5138 					break;
5139 				case CMD_MODEL_CANTGRAB: case CMD_MODEL_NOTGRAB:
5140 					tempInt = GET_INT_ARG(1);
5141 					if(tempInt == 2) newchar->grabforce = -999999;
5142 					else             newchar->antigrab = 1;
5143 					break;
5144 				case CMD_MODEL_ANTIGRAB: // a can grab b: a->antigrab - b->grabforce <=0
5145 					newchar->antigrab = GET_INT_ARG(1);
5146 					break;
5147 				case CMD_MODEL_GRABFORCE:
5148 					newchar->grabforce = GET_INT_ARG(1);
5149 					break;
5150 				case CMD_MODEL_GRABBACK:
5151 					newchar->grabback = GET_INT_ARG(1);
5152 					break;
5153 				case CMD_MODEL_OFFSCREENKILL:
5154 					newchar->offscreenkill = GET_INT_ARG(1);
5155 					break;
5156 				case CMD_MODEL_FALLDIE: case CMD_MODEL_DEATH:
5157 					newchar->falldie = GET_INT_ARG(1);
5158 					break;
5159 				case CMD_MODEL_SPEED:
5160 					value = GET_ARG(1);
5161 					newchar->speed = atof(value);
5162 					newchar->speed /= 10;
5163 					if(newchar->speed < 0.5) newchar->speed = 0.5;
5164 					if(newchar->speed > 30) newchar->speed = 30;
5165 					break;
5166 				case CMD_MODEL_SPEEDF:
5167 					value = GET_ARG(1);
5168 					newchar->speed = atof(value);
5169 					break;
5170 				case CMD_MODEL_JUMPSPEED:
5171 					value = GET_ARG(1);
5172 					newchar->jumpspeed = atof(value);
5173 					newchar->jumpspeed /= 10;
5174 					break;
5175 				case CMD_MODEL_JUMPSPEEDF:
5176 					value = GET_ARG(1);
5177 					newchar->jumpspeed = atof(value);
5178 					break;
5179 				case CMD_MODEL_ANTIGRAVITY:
5180 					value = GET_ARG(1);
5181 					newchar->antigravity = atof(value);
5182 					newchar->antigravity /= 100;
5183 					break;
5184 				case CMD_MODEL_STEALTH:
5185 					newchar->stealth.hide = GET_INT_ARG(1);
5186 					newchar->stealth.detect = GET_INT_ARG(2);
5187 					break;
5188 				case CMD_MODEL_JUGGLEPOINTS:
5189 					value = GET_ARG(1);
5190 					newchar->jugglepoints.current = atoi(value);
5191 					newchar->jugglepoints.maximum = atoi(value);
5192 					break;
5193 				case CMD_MODEL_RISEATTACKTYPE:
5194 					value = GET_ARG(1);
5195 					newchar->riseattacktype = atoi(value);
5196 					break;
5197 				case CMD_MODEL_GUARDPOINTS:
5198 					value = GET_ARG(1);
5199 					newchar->guardpoints.current = atoi(value);
5200 					newchar->guardpoints.maximum = atoi(value);
5201 					break;
5202 				case CMD_MODEL_DEFENSE:
5203 					#define tempdef(x, y, z, p, k, b, t, r, e) \
5204 					x(stricmp(value, #y)==0)\
5205 					{\
5206 					if(arglist.count>=2) newchar->z[ATK_##y] = GET_FLOAT_ARG(2);\
5207 					/*newchar->z[ATK_##y] /= 100;*/\
5208 					if(arglist.count>=3) newchar->p[ATK_##y] = GET_FLOAT_ARG(3);\
5209 					if(arglist.count>=4) newchar->k[ATK_##y] = GET_FLOAT_ARG(4);\
5210 					/*newchar->k[ATK_##y] /= 100;*/\
5211 					if(arglist.count>=5) newchar->b[ATK_##y] = GET_FLOAT_ARG(5);\
5212 					if(arglist.count>=6) newchar->t[ATK_##y] = GET_FLOAT_ARG(6);\
5213 					if(arglist.count>=7) newchar->r[ATK_##y] = GET_FLOAT_ARG(7);\
5214 					/*newchar->r[ATK_##y] /= 100;*/\
5215 					if(arglist.count>=8) newchar->e[ATK_##y] = GET_FLOAT_ARG(8);\
5216 					}
5217 					{
5218 						value = GET_ARG(1);
5219 						tempdef(if, NORMAL, defense_factors, defense_pain, defense_knockdown, defense_blockpower, defense_blockthreshold, defense_blockratio, defense_blocktype)
5220 						tempdef(else if, NORMAL2,   defense_factors, defense_pain, defense_knockdown, defense_blockpower, defense_blockthreshold, defense_blockratio, defense_blocktype)
5221 						tempdef(else if, NORMAL3,   defense_factors, defense_pain, defense_knockdown, defense_blockpower, defense_blockthreshold, defense_blockratio, defense_blocktype)
5222 						tempdef(else if, NORMAL4,   defense_factors, defense_pain, defense_knockdown, defense_blockpower, defense_blockthreshold, defense_blockratio, defense_blocktype)
5223 						tempdef(else if, NORMAL5,   defense_factors, defense_pain, defense_knockdown, defense_blockpower, defense_blockthreshold, defense_blockratio, defense_blocktype)
5224 						tempdef(else if, NORMAL6,   defense_factors, defense_pain, defense_knockdown, defense_blockpower, defense_blockthreshold, defense_blockratio, defense_blocktype)
5225 						tempdef(else if, NORMAL7,   defense_factors, defense_pain, defense_knockdown, defense_blockpower, defense_blockthreshold, defense_blockratio, defense_blocktype)
5226 						tempdef(else if, NORMAL8,   defense_factors, defense_pain, defense_knockdown, defense_blockpower, defense_blockthreshold, defense_blockratio, defense_blocktype)
5227 						tempdef(else if, NORMAL9,   defense_factors, defense_pain, defense_knockdown, defense_blockpower, defense_blockthreshold, defense_blockratio, defense_blocktype)
5228 						tempdef(else if, NORMAL10,  defense_factors, defense_pain, defense_knockdown, defense_blockpower, defense_blockthreshold, defense_blockratio, defense_blocktype)
5229 						tempdef(else if, BLAST,     defense_factors, defense_pain, defense_knockdown, defense_blockpower, defense_blockthreshold, defense_blockratio, defense_blocktype)
5230 						tempdef(else if, STEAL,     defense_factors, defense_pain, defense_knockdown, defense_blockpower, defense_blockthreshold, defense_blockratio, defense_blocktype)
5231 						tempdef(else if, BURN,      defense_factors, defense_pain, defense_knockdown, defense_blockpower, defense_blockthreshold, defense_blockratio, defense_blocktype)
5232 						tempdef(else if, SHOCK,     defense_factors, defense_pain, defense_knockdown, defense_blockpower, defense_blockthreshold, defense_blockratio, defense_blocktype)
5233 						tempdef(else if, FREEZE,    defense_factors, defense_pain, defense_knockdown, defense_blockpower, defense_blockthreshold, defense_blockratio, defense_blocktype)
5234 						else if(strnicmp(value, "normal", 6)==0)
5235 						{
5236 							tempInt = atoi(value+6);
5237 							if(tempInt<11) tempInt = 11;
5238 							if(arglist.count>=2) newchar->defense_factors[tempInt+STA_ATKS-1]        = GET_FLOAT_ARG(2);
5239 							if(arglist.count>=3) newchar->defense_pain[tempInt+STA_ATKS-1]           = GET_FLOAT_ARG(3);
5240 							if(arglist.count>=4) newchar->defense_knockdown[tempInt+STA_ATKS-1]      = GET_FLOAT_ARG(4);
5241 							if(arglist.count>=5) newchar->defense_blockpower[tempInt+STA_ATKS-1]     = GET_FLOAT_ARG(5);
5242 							if(arglist.count>=6) newchar->defense_blockthreshold[tempInt+STA_ATKS-1] = GET_FLOAT_ARG(6);
5243 							if(arglist.count>=7) newchar->defense_blockratio[tempInt+STA_ATKS-1]     = GET_FLOAT_ARG(7);
5244 							if(arglist.count>=8) newchar->defense_blocktype[tempInt+STA_ATKS-1]      = GET_FLOAT_ARG(8);
5245 						}
5246 						else if(stricmp(value, "ALL")==0)
5247 						{
5248 							for(i=0;i<max_attack_types;i++)
5249 							{
5250 								if(arglist.count>=2) newchar->defense_factors[i]         = GET_FLOAT_ARG(2);
5251 								if(arglist.count>=3) newchar->defense_pain[i]            = GET_FLOAT_ARG(3);
5252 								if(arglist.count>=4) newchar->defense_knockdown[i]       = GET_FLOAT_ARG(4);
5253 								if(arglist.count>=5) newchar->defense_blockpower[i]      = GET_FLOAT_ARG(5);
5254 								if(arglist.count>=6) newchar->defense_blockthreshold[i]  = GET_FLOAT_ARG(6);
5255 								if(arglist.count>=7) newchar->defense_blockratio[i]      = GET_FLOAT_ARG(7);
5256 								if(arglist.count>=8) newchar->defense_blocktype[i]       = GET_FLOAT_ARG(8);
5257 							}
5258 						}
5259 					}
5260 					#undef tempdef
5261 					break;
5262 				case CMD_MODEL_OFFENSE:
5263 					#define tempoff(x, y, z) \
5264 					x(stricmp(value, #y)==0)\
5265 					{\
5266 					newchar->z[ATK_##y] = GET_FLOAT_ARG(2);\
5267 					/*newchar->z[ATK_##y] /= 100;*/\
5268 					}
5269 					{
5270 						value = GET_ARG(1);
5271 						tempoff(if,         NORMAL,     offense_factors)
5272 						tempoff(else if,    NORMAL2,    offense_factors)
5273 						tempoff(else if,    NORMAL3,    offense_factors)
5274 						tempoff(else if,    NORMAL4,    offense_factors)
5275 						tempoff(else if,    NORMAL5,    offense_factors)
5276 						tempoff(else if,    NORMAL6,    offense_factors)
5277 						tempoff(else if,    NORMAL7,    offense_factors)
5278 						tempoff(else if,    NORMAL8,    offense_factors)
5279 						tempoff(else if,    NORMAL9,    offense_factors)
5280 						tempoff(else if,    NORMAL10,   offense_factors)
5281 						tempoff(else if,    BLAST,      offense_factors)
5282 						tempoff(else if,    STEAL,      offense_factors)
5283 						tempoff(else if,    BURN,       offense_factors)
5284 						tempoff(else if,    SHOCK,      offense_factors)
5285 						tempoff(else if,    FREEZE,     offense_factors)
5286 						else if(strnicmp(value, "normal", 6)==0)
5287 						{
5288 							tempInt = atoi(value+6);
5289 							if(tempInt<11) tempInt = 11;
5290 							newchar->offense_factors[tempInt+STA_ATKS-1] = GET_FLOAT_ARG(2);
5291 						}
5292 						else if(stricmp(value, "ALL")==0)
5293 						{
5294 							tempFloat = GET_FLOAT_ARG(2);
5295 							for(i=0;i<max_attack_types;i++)
5296 							{
5297 								newchar->offense_factors[i] = tempFloat;
5298 							}
5299 						}
5300 					}
5301 					#undef tempoff
5302 					break;
5303 				case CMD_MODEL_HEIGHT:
5304 					newchar->height = GET_INT_ARG(1);
5305 					break;
5306 				case CMD_MODEL_JUMPHEIGHT:
5307 					newchar->jumpheight = GET_FLOAT_ARG(1);
5308 					break;
5309 				case CMD_MODEL_JUMPMOVE:
5310 					newchar->jumpmovex = GET_INT_ARG(1);
5311 					newchar->jumpmovez = GET_INT_ARG(2);
5312 					break;
5313 				case CMD_MODEL_KNOCKDOWNCOUNT:
5314 					newchar->knockdowncount = GET_FLOAT_ARG(1);
5315 					break;
5316 				case CMD_MODEL_GRABDISTANCE:
5317 					newchar->grabdistance = GET_FLOAT_ARG(1);                    // 30-12-2004 and store for character
5318 					break;
5319 				case CMD_MODEL_GRABFLIP:
5320 					newchar->grabflip = GET_INT_ARG(1);
5321 					break;
5322 				case CMD_MODEL_GRABFINISH:
5323 					newchar->grabfinish = GET_INT_ARG(1);
5324 					break;
5325 				case CMD_MODEL_THROWDAMAGE:
5326 					newchar->throwdamage = GET_INT_ARG(1);
5327 					break;
5328 				case CMD_MODEL_SHADOW:
5329 					newchar->shadow = GET_INT_ARG(1);
5330 					break;
5331 				case CMD_MODEL_GFXSHADOW:
5332 					newchar->gfxshadow = GET_INT_ARG(1);
5333 					break;
5334 				case CMD_MODEL_AIRONLY:	// Shadows display in air only?
5335 					newchar->aironly = GET_INT_ARG(1);
5336 					break;
5337 				case CMD_MODEL_FMAP:	// Map that corresponds with the remap when a character is frozen
5338 					newchar->maps.frozen = GET_INT_ARG(1);
5339 					break;
5340 				case CMD_MODEL_KOMAP:	// Remap when character is KO'd.
5341 					newchar->maps.ko = GET_INT_ARG(1);  //Remap.
5342 					newchar->maps.kotype = GET_INT_ARG(2);  //Type: 0 start of fall/death, 1 last frame.
5343 					break;
5344 				case CMD_MODEL_HMAP:	// Maps range unavailable to player in select screen.
5345 					newchar->maps.hide_start = GET_INT_ARG(1); //First unavailable map.
5346 					newchar->maps.hide_end = GET_INT_ARG(2); //Last unavailable map.
5347 					break;
5348 				case CMD_MODEL_SETLAYER:
5349 					newchar->setlayer = GET_INT_ARG(1);
5350 					break;
5351 				case CMD_MODEL_TOFLIP:	  // Flag to determine if flashes images will be flipped or not
5352 					newchar->toflip = GET_INT_ARG(1);
5353 					break;
5354 				case CMD_MODEL_NODIEBLINK:
5355 					// Added to determine if dying animation blinks or not
5356 					newchar->nodieblink = GET_INT_ARG(1);
5357 					break;
5358 				case CMD_MODEL_NOATFLASH:	 // Flag to determine if an opponents attack spawns their flash or not
5359 					newchar->noatflash = GET_INT_ARG(1);
5360 					break;
5361 				case CMD_MODEL_NOMOVE:
5362 					// If set, will be static (speed must be set to 0 or left blank)
5363 					newchar->nomove = GET_INT_ARG(1);
5364 					newchar->noflip = GET_INT_ARG(2);    // If set, static will not flip directions
5365 					if(newchar->nomove) newchar->nodrop = 1;
5366 					break;
5367 				case CMD_MODEL_NODROP:
5368 					newchar->nodrop = GET_INT_ARG(1);
5369 					break;
5370 				case CMD_MODEL_THOLD:
5371 					// Threshold for enemies/players block
5372 					newchar->thold = GET_INT_ARG(1);
5373 					break;
5374 				case CMD_MODEL_RUNNING:
5375 					// The speed at which the player runs
5376 					newchar->runspeed = GET_FLOAT_ARG(1);
5377 					newchar->runspeed /= 10;
5378 					newchar->runjumpheight = GET_FLOAT_ARG(2);    // The height at which a player jumps when running
5379 					newchar->runjumpdist = GET_FLOAT_ARG(3);    // The distance a player jumps when running
5380 					newchar->runupdown = GET_INT_ARG(4);
5381 					newchar->runhold = GET_INT_ARG(5);
5382 					break;
5383 				case CMD_MODEL_BLOCKODDS:
5384 					// Odds that an attack will hit an enemy (1 : blockodds)
5385 					newchar->blockodds = GET_INT_ARG(1);
5386 					break;
5387 				case CMD_MODEL_HOLDBLOCK:
5388 					newchar->holdblock = GET_INT_ARG(1);
5389 					break;
5390 				case CMD_MODEL_BLOCKPAIN:
5391 					newchar->blockpain = GET_INT_ARG(1);
5392 					break;
5393 				case CMD_MODEL_NOPASSIVEBLOCK:
5394 					newchar->nopassiveblock = GET_INT_ARG(1);
5395 					break;
5396 				case CMD_MODEL_EDELAY:
5397 					newchar->edelay.mode        = GET_INT_ARG(1);
5398 					newchar->edelay.factor      = GET_FLOAT_ARG(2);
5399 					newchar->edelay.cap_min     = GET_INT_ARG(3);
5400 					newchar->edelay.cap_max     = GET_INT_ARG(4);
5401 					newchar->edelay.range_min   = GET_INT_ARG(5);
5402 					newchar->edelay.range_max   = GET_INT_ARG(6);
5403 					break;
5404 				case CMD_MODEL_PAINGRAB:
5405 					newchar->paingrab = GET_INT_ARG(1);
5406 					break;
5407 				case CMD_MODEL_THROW:
5408 					newchar->throwdist = GET_FLOAT_ARG(1);
5409 					newchar->throwheight = GET_FLOAT_ARG(2);
5410 					break;
5411 				case CMD_MODEL_GRABWALK:
5412 					newchar->grabwalkspeed = GET_FLOAT_ARG(1);
5413 					newchar->grabwalkspeed /= 10;
5414 					if(newchar->grabwalkspeed < 0.5) newchar->grabwalkspeed = 0.5;
5415 					break;
5416 				case CMD_MODEL_GRABTURN:
5417 					newchar->grabturn = GET_INT_ARG(1);
5418 					break;
5419 				case CMD_MODEL_THROWFRAMEWAIT:
5420 					newchar->throwframewait = GET_INT_ARG(1);
5421 					break;
5422 				case CMD_MODEL_DIESOUND:
5423 					newchar->diesound = sound_load_sample(GET_ARG(1), packfile, 0);
5424 					break;
5425 				case CMD_MODEL_ICON:
5426 					value = GET_ARG(1);
5427 					if(newchar->icon.def > -1) {
5428 						shutdownmessage = "model has multiple icons defined";
5429 						goto lCleanup;
5430 					}
5431 					newchar->icon.def = loadsprite(value,0,0,pixelformat); //use same palette as the owner
5432 					newchar->icon.pain = newchar->icon.def;
5433 					newchar->icon.die = newchar->icon.def;
5434 					newchar->icon.get = newchar->icon.def;
5435 					break;
5436 				case CMD_MODEL_ICONPAIN:
5437 					value = GET_ARG(1);
5438 					newchar->icon.pain = loadsprite(value,0,0,pixelformat);
5439 					break;
5440 				case CMD_MODEL_ICONDIE:
5441 					value = GET_ARG(1);
5442 					newchar->icon.die = loadsprite(value,0,0,pixelformat);
5443 					break;
5444 				case CMD_MODEL_ICONGET:
5445 					value = GET_ARG(1);
5446 					newchar->icon.get = loadsprite(value,0,0,pixelformat);
5447 					break;
5448 				case CMD_MODEL_ICONW:
5449 					value = GET_ARG(1);
5450 					newchar->icon.weapon = loadsprite(value,0,0,pixelformat);
5451 					break;
5452 				case CMD_MODEL_ICONMPHIGH:
5453 					value = GET_ARG(1);
5454 					newchar->icon.mphigh = loadsprite(value,0,0,pixelformat);
5455 					break;
5456 				case CMD_MODEL_ICONMPHALF:
5457 					value = GET_ARG(1);
5458 					newchar->icon.mpmed = loadsprite(value,0,0,pixelformat);
5459 					break;
5460 				case CMD_MODEL_ICONMPLOW:
5461 					value = GET_ARG(1);
5462 					newchar->icon.mplow = loadsprite(value,0,0,pixelformat);
5463 					break;
5464 				case CMD_MODEL_PARROW:
5465 					// Image that is displayed when player 1 spawns invincible
5466 					value = GET_ARG(1);
5467 					newchar->parrow[0][0] = loadsprite(value,0,0,pixelformat);
5468 					newchar->parrow[0][1] = GET_INT_ARG(2);
5469 					newchar->parrow[0][2] = GET_INT_ARG(3);
5470 					break;
5471 				case CMD_MODEL_PARROW2:
5472 					// Image that is displayed when player 2 spawns invincible
5473 					value = GET_ARG(1);
5474 					newchar->parrow[1][0] = loadsprite(value,0,0,pixelformat);
5475 					newchar->parrow[1][1] = GET_INT_ARG(2);
5476 					newchar->parrow[1][2] = GET_INT_ARG(3);
5477 					break;
5478 				case CMD_MODEL_PARROW3:
5479 					value = GET_ARG(1);
5480 					newchar->parrow[2][0] = loadsprite(value,0,0,pixelformat);
5481 					newchar->parrow[2][1] = GET_INT_ARG(2);
5482 					newchar->parrow[2][2] = GET_INT_ARG(3);
5483 					break;
5484 				case CMD_MODEL_PARROW4:
5485 					value = GET_ARG(1);
5486 					newchar->parrow[3][0] = loadsprite(value,0,0,pixelformat);
5487 					newchar->parrow[3][1] = GET_INT_ARG(2);
5488 					newchar->parrow[3][2] = GET_INT_ARG(3);
5489 					break;
5490 				case CMD_MODEL_ATCHAIN:
5491 					newchar->chainlength = 0;
5492 					for(i = 0; i < MAX_ATCHAIN; i++)
5493 					{
5494 						newchar->atchain[i] = GET_INT_ARG(i + 1);
5495 						if(newchar->atchain[i] < 0) newchar->atchain[i] = 0;
5496 						if(newchar->atchain[i] > max_attacks) newchar->atchain[i] = max_attacks;
5497 						if(newchar->atchain[i]) newchar->chainlength = i+1;
5498 					}
5499 					break;
5500 				case CMD_MODEL_COMBOSTYLE:
5501 					newchar->combostyle = GET_INT_ARG(1);
5502 					break;
5503 				case CMD_MODEL_CREDIT:
5504 					newchar->credit = GET_INT_ARG(1);
5505 					break;
5506 				case CMD_MODEL_NOPAIN:
5507 					newchar->nopain = GET_INT_ARG(1);
5508 					break;
5509 				case CMD_MODEL_ESCAPEHITS:
5510 					// How many times an enemy can be hit before retaliating
5511 					newchar->escapehits = GET_INT_ARG(1);
5512 					break;
5513 				case CMD_MODEL_CHARGERATE:
5514 					// How much mp does this character gain while recharging?
5515 					newchar->chargerate = GET_INT_ARG(1);
5516 					break;
5517 				case CMD_MODEL_MPRATE:
5518 					newchar->mprate = GET_INT_ARG(1);
5519 					break;
5520 				case CMD_MODEL_MPSET:
5521 					// Mp bar wax/wane.
5522 					newchar->mp             = GET_INT_ARG(1); //Max MP.
5523 					newchar->mpstable       = GET_INT_ARG(2); //MP stable setting.
5524 					newchar->mpstableval    = GET_INT_ARG(3); //MP stable value (% Mp bar will try and maintain).
5525 					newchar->mprate         = GET_INT_ARG(4); //Rate MP value rises over time.
5526 					newchar->mpdroprate     = GET_INT_ARG(5); //Rate MP value drops over time.
5527 					newchar->chargerate     = GET_INT_ARG(6); //MP Chargerate.
5528 					break;
5529 				case CMD_MODEL_SLEEPWAIT:
5530 					newchar->sleepwait = GET_INT_ARG(1);
5531 					break;
5532 				case CMD_MODEL_GUARDRATE:
5533 					newchar->guardrate = GET_INT_ARG(1);
5534 					break;
5535 				case CMD_MODEL_AGGRESSION:
5536 					newchar->aggression = GET_INT_ARG(1);
5537 					break;
5538 				case CMD_MODEL_RISETIME:
5539 					newchar->risetime[0] = GET_INT_ARG(1);
5540 					newchar->risetime[1] = GET_INT_ARG(2);
5541 					break;
5542 				case CMD_MODEL_FACING:
5543 					newchar->facing = GET_INT_ARG(1);
5544 					break;
5545 				case CMD_MODEL_TURNDELAY:
5546 					newchar->turndelay = GET_INT_ARG(1);
5547 					break;
5548 				case CMD_MODEL_LIFESPAN:
5549 					newchar->lifespan = GET_FLOAT_ARG(1)*GAME_SPEED;
5550 					break;
5551 				case CMD_MODEL_SUMMONKILL:
5552 					newchar->summonkill = GET_INT_ARG(1);
5553 					break;
5554 				case CMD_MODEL_LIFEPOSITION:
5555 					if((value=GET_ARG(1))[0]) newchar->hpx = atoi(value);
5556 					if((value=GET_ARG(2))[0]) newchar->hpy = atoi(value);
5557 					break;
5558 				case CMD_MODEL_LIFEBARSTATUS:
5559 					_readbarstatus(buf+pos, &(newchar->hpbarstatus));
5560 					newchar->hpbarstatus.colourtable = &hpcolourtable;
5561 					break;
5562 				case CMD_MODEL_ICONPOSITION:
5563 					if((value=GET_ARG(1))[0]) newchar->icon.x = atoi(value);
5564 					if((value=GET_ARG(2))[0]) newchar->icon.y = atoi(value);
5565 					break;
5566 				case CMD_MODEL_NAMEPOSITION:
5567 					if((value=GET_ARG(1))[0]) newchar->namex = atoi(value);
5568 					if((value=GET_ARG(2))[0]) newchar->namey = atoi(value);
5569 					break;
5570 				case CMD_MODEL_COM:
5571 					{
5572 						// Section for custom freespecials starts here
5573 						int i;
5574 						int t;
5575 						for(i = 0, t = 1; i < MAX_SPECIAL_INPUTS-3; i++, t++)
5576 						{
5577 							value = GET_ARG(t);
5578 							if(!value[0]) break;
5579 							if(stricmp(value, "u")==0){
5580 								newchar->special[newchar->specials_loaded][i] = FLAG_MOVEUP;
5581 							}
5582 							else if(stricmp(value, "d")==0){
5583 								newchar->special[newchar->specials_loaded][i] = FLAG_MOVEDOWN;
5584 							}
5585 							else if(stricmp(value, "f")==0){
5586 								newchar->special[newchar->specials_loaded][i] = FLAG_FORWARD;
5587 							}
5588 							else if(stricmp(value, "b")==0){
5589 								newchar->special[newchar->specials_loaded][i] = FLAG_BACKWARD;
5590 							}
5591 							else if(stricmp(value, "a")==0){
5592 								newchar->special[newchar->specials_loaded][i] = FLAG_ATTACK;
5593 							}
5594 							else if(stricmp(value, "a2")==0){
5595 								newchar->special[newchar->specials_loaded][i] = FLAG_ATTACK2;
5596 							}
5597 							else if(stricmp(value, "a3")==0){
5598 								newchar->special[newchar->specials_loaded][i] = FLAG_ATTACK3;
5599 							}
5600 							else if(stricmp(value, "a4")==0){
5601 								newchar->special[newchar->specials_loaded][i] = FLAG_ATTACK4;
5602 							}
5603 							else if(stricmp(value, "j")==0){
5604 								newchar->special[newchar->specials_loaded][i] = FLAG_JUMP;
5605 							}
5606 							else if(stricmp(value, "s")==0){
5607 								newchar->special[newchar->specials_loaded][i] = FLAG_SPECIAL;
5608 							}
5609 							else if(stricmp(value, "k")==0){
5610 								newchar->special[newchar->specials_loaded][i] = FLAG_SPECIAL;
5611 							}
5612 							else if(strnicmp(value, "freespecial", 11)==0 && (!value[11] || (value[11] >= '1' && value[11] <= '9'))){
5613 								tempInt = atoi(value+11);
5614 								if(tempInt<1) tempInt = 1;
5615 								newchar->special[newchar->specials_loaded][MAX_SPECIAL_INPUTS-2] = animspecials[tempInt-1];
5616 							}
5617 							else {
5618 								shutdownmessage = "Invalid freespecial command";
5619 								goto lCleanup;
5620 							}
5621 						}
5622 						newchar->special[newchar->specials_loaded][MAX_SPECIAL_INPUTS-3]=i-1; // max steps
5623 						newchar->specials_loaded++;
5624 						if(newchar->specials_loaded > max_freespecials) {
5625 							shutdownmessage = "Too many Freespecials and/or Cancels. Please increase Maxfreespecials"; // OX. This is to catch freespecials that use same animation.
5626 							goto lCleanup;
5627 						}
5628 					}
5629 					// End section for custom freespecials
5630 					break;
5631 				case CMD_MODEL_REMAP:
5632 					{
5633 						// This command should not be used under 24bit mode, but for old mods, just give it a default palette
5634 						value = GET_ARG(1);
5635 						value2 = GET_ARG(2);
5636 						errorVal = load_colourmap(newchar, value, value2);
5637 						if(pixelformat==PIXEL_x8 && newchar->palette==NULL)
5638 						{
5639 							newchar->palette = malloc(PAL_BYTES);
5640 							if(loadimagepalette(value, packfile, newchar->palette)==0) {
5641 								shutdownmessage = "Failed to load palette!";
5642 								goto lCleanup;
5643 							}
5644 						}
5645 						mapflag[newchar->maps_loaded-1] = 1;
5646 						if(!errorVal){
5647 							switch(errorVal){
5648 								case 0: // uhm wait, we just tested for !errorVal...
5649 									shutdownmessage = "Failed to create colourmap. Image Used Twice!";
5650 									goto lCleanup;
5651 									break;
5652 								case -1:
5653 									shutdownmessage = "Failed to create colourmap. MAX_COLOUR_MAPS full!";
5654 									goto lCleanup;
5655 									break;
5656 								case -2:
5657 									shutdownmessage = "Failed to create colourmap. Failed to tracemalloc(256)!";
5658 									goto lCleanup;
5659 									break;
5660 								case -3:
5661 									shutdownmessage = "Failed to create colourmap. Failed to create bitmap1";
5662 									goto lCleanup;
5663 									break;
5664 								case -4:
5665 									shutdownmessage = "Failed to create colourmap. Failed to create bitmap2";
5666 									goto lCleanup;
5667 									break;
5668 							}
5669 						}
5670 					}
5671 					break;
5672 				case CMD_MODEL_PALETTE:
5673 					// main palette for the entity under 24bit mode
5674 					if(pixelformat!=PIXEL_x8) printf("Warning: command '%s' is not available under 8bit mode\n", command);
5675 					else if(newchar->palette==NULL)
5676 					{
5677 						value = GET_ARG(1);
5678 						newchar->palette = malloc(PAL_BYTES);
5679 						if(loadimagepalette(value, packfile, newchar->palette)==0) {
5680 							shutdownmessage = "Failed to load palette!";
5681 							goto lCleanup;
5682 						}
5683 					}
5684 					break;
5685 				case CMD_MODEL_ALTERNATEPAL:
5686 					// remap for the entity under 24bit mode, this method can replace remap command
5687 					if(pixelformat!=PIXEL_x8) printf("Warning: command '%s' is not available under 8bit mode\n", command);
5688 					else if(newchar->maps_loaded<MAX_COLOUR_MAPS) {
5689 						value = GET_ARG(1);
5690 						newchar->colourmap[(int)newchar->maps_loaded] = malloc(PAL_BYTES);
5691 						if(loadimagepalette(value, packfile, newchar->colourmap[(int)newchar->maps_loaded])==0) {
5692 							shutdownmessage = "Failed to load palette!";
5693 							goto lCleanup;
5694 						}
5695 						newchar->maps_loaded++;
5696 					}
5697 					break;
5698 				case CMD_MODEL_GLOBALMAP:
5699 					// use global palette under 24bit mode, so some entity/panel/bg can still use palette feature, that saves some memory
5700 					if(pixelformat!=PIXEL_x8) printf("Warning: command '%s' is not available under 8bit mode\n", command);
5701 					else newchar->globalmap = GET_INT_ARG(1);
5702 					break;
5703 				case CMD_MODEL_ALPHA:
5704 					newchar->alpha = GET_INT_ARG(1);
5705 					break;
5706 				case CMD_MODEL_REMOVE:
5707 					newchar->remove = GET_INT_ARG(1);
5708 					break;
5709 				case CMD_MODEL_SCRIPT:
5710 					//load the update script
5711 					lcmHandleCommandScripts(&arglist, newchar->scripts.update_script, "updateentityscript", filename);
5712 					break;
5713 				case CMD_MODEL_THINKSCRIPT:
5714 					lcmHandleCommandScripts(&arglist, newchar->scripts.think_script, "thinkscript", filename);
5715 					break;
5716 				case CMD_MODEL_TAKEDAMAGESCRIPT:
5717 					lcmHandleCommandScripts(&arglist, newchar->scripts.takedamage_script, "takedamagescript", filename);
5718 					break;
5719 				case CMD_MODEL_ONFALLSCRIPT:
5720 					lcmHandleCommandScripts(&arglist, newchar->scripts.onfall_script, "onfallscript", filename);
5721 					break;
5722 				case CMD_MODEL_ONPAINSCRIPT:
5723 					lcmHandleCommandScripts(&arglist, newchar->scripts.onpain_script, "onpainscript", filename);
5724 					break;
5725 				case CMD_MODEL_ONBLOCKSSCRIPT:
5726 					lcmHandleCommandScripts(&arglist, newchar->scripts.onblocks_script, "onblocksscript", filename);
5727 					break;
5728 				case CMD_MODEL_ONBLOCKWSCRIPT:
5729 					lcmHandleCommandScripts(&arglist, newchar->scripts.onblockw_script, "onblockwscript", filename);
5730 					break;
5731 				case CMD_MODEL_ONBLOCKOSCRIPT:
5732 					lcmHandleCommandScripts(&arglist, newchar->scripts.onblocko_script, "onblockoscript", filename);
5733 					break;
5734 				case CMD_MODEL_ONBLOCKZSCRIPT:
5735 					lcmHandleCommandScripts(&arglist, newchar->scripts.onblockz_script, "onblockzscript", filename);
5736 					break;
5737 				case CMD_MODEL_ONBLOCKASCRIPT:
5738 					lcmHandleCommandScripts(&arglist, newchar->scripts.onblocka_script, "onblockascript", filename);
5739 					break;
5740 				case CMD_MODEL_ONMOVEXSCRIPT:
5741 					lcmHandleCommandScripts(&arglist, newchar->scripts.onmovex_script, "onmovexscript", filename);
5742 					break;
5743 				case CMD_MODEL_ONMOVEZSCRIPT:
5744 					lcmHandleCommandScripts(&arglist, newchar->scripts.onmovez_script, "onmovezscript", filename);
5745 					break;
5746 				case CMD_MODEL_ONMOVEASCRIPT:
5747 					lcmHandleCommandScripts(&arglist, newchar->scripts.onmovea_script, "onmoveascript", filename);
5748 					break;
5749 				case CMD_MODEL_ONDEATHSCRIPT:
5750 					lcmHandleCommandScripts(&arglist, newchar->scripts.ondeath_script, "ondeathscript", filename);
5751 					break;
5752 				case CMD_MODEL_ONKILLSCRIPT:
5753 					lcmHandleCommandScripts(&arglist, newchar->scripts.onkill_script, "onkillscript", filename);
5754 					break;
5755 				case CMD_MODEL_DIDBLOCKSCRIPT:
5756 					lcmHandleCommandScripts(&arglist, newchar->scripts.didblock_script, "didblockscript", filename);
5757 					break;
5758 				case CMD_MODEL_ONDOATTACKSCRIPT:
5759 					lcmHandleCommandScripts(&arglist, newchar->scripts.ondoattack_script, "ondoattackscript", filename);
5760 					break;
5761 				case CMD_MODEL_DIDHITSCRIPT:
5762 					lcmHandleCommandScripts(&arglist, newchar->scripts.didhit_script, "didhitscript", filename);
5763 					break;
5764 				case CMD_MODEL_ONSPAWNSCRIPT:
5765 					lcmHandleCommandScripts(&arglist, newchar->scripts.onspawn_script, "onspawnscript", filename);
5766 					break;
5767 				case CMD_MODEL_ANIMATIONSCRIPT:
5768 					Script_Init(newchar->scripts.animation_script, "animationscript", 0);
5769 					if(!load_script(newchar->scripts.animation_script, GET_ARG(1))) {
5770 						shutdownmessage = "Unable to load animation script!";
5771 						goto lCleanup;
5772 					}
5773 					//dont compile, until at end of this function
5774 					break;
5775 				case CMD_MODEL_KEYSCRIPT:
5776 					lcmHandleCommandScripts(&arglist, newchar->scripts.key_script, "entitykeyscript", filename);
5777 					break;
5778 				case CMD_MODEL_ANIM:
5779 					{
5780 						value = GET_ARG(1);
5781 						frameset = 0;
5782 						framecount = 0;
5783 						// Create new animation
5784 						newanim = alloc_anim();
5785 						if(!newanim){
5786 							shutdownmessage = "Not enough memory for animations!";
5787 							goto lCleanup;
5788 						}
5789 						newanim->model_index = newchar->index;
5790 						// Reset vars
5791 						curframe = 0;
5792 						memset(bbox, 0, sizeof(bbox));
5793 						memset(abox, 0, sizeof(abox));
5794 						memset(offset, 0, sizeof(offset));
5795 						memset(shadow_coords, 0, sizeof(shadow_coords));
5796 						memset(shadow_xz, 0, sizeof(shadow_xz));
5797 						memset(platform, 0, sizeof(platform));
5798 						shadow_set = 0;
5799 						attack = emptyattack;
5800 						attack.hitsound = -1;
5801 						attack.hitflash = -1;
5802 						attack.blockflash = -1;
5803 						attack.blocksound = -1;
5804 						drawmethod = plainmethod;
5805 						idle = 0;
5806 						move = 0;
5807 						movez = 0;
5808 						movea = 0;
5809 						seta = -1;
5810 						frameshadow = -1;
5811 						soundtoplay = -1;
5812 
5813 						if(!newanim->range.xmin) newanim->range.xmin = -10;
5814 						newanim->range.xmax = (int)newchar->jumpheight*20;    //30-12-2004 default range affected by jump height
5815 						newanim->range.zmin = (int)-newchar->grabdistance/3;  //zmin
5816 						newanim->range.zmax = (int)newchar->grabdistance/3;   //zmax
5817 						newanim->range.amin = -1000;                          //amin
5818 						newanim->range.amax = 1000;                           //amax
5819 						newanim->range.bmin = -1000;                          //Base min.
5820 						newanim->range.bmax = 1000;                           //Base max.
5821 
5822 						newanim->jumpframe.v = 0;                           // Default disabled
5823 						newanim->fastattack = 0;
5824 						newanim->energycost.mponly = 0;							//MP only.
5825 						newanim->energycost.disable = 0;							//Disable flag.
5826 						newanim->chargetime = 2;			// Default for backwards compatibility
5827 						newanim->shootframe = -1;
5828 						newanim->throwframe = -1;
5829 						newanim->tossframe = -1;			// this get 1 of weapons numshots shots in the animation that you want(normaly the last)by tails
5830 						newanim->jumpframe.f = -1;
5831 						newanim->flipframe = -1;
5832 						newanim->attackone = -1;
5833 						newanim->dive.x = newanim->dive.v = 0;
5834 						newanim->followanim = 0;			// Default disabled
5835 						newanim->followcond = 0;
5836 						newanim->counterrange.framestart = -1;		//Start frame.
5837 						newanim->counterrange.frameend = -1;		//End frame.
5838 						newanim->counterrange.condition = 0;		//Counter cond.
5839 						newanim->counterrange.damaged = 0;		//Counter damage.
5840 						newanim->unsummonframe = -1;
5841 						newanim->landframe.frame = -1;
5842 						newanim->dropframe = -1;
5843 						newanim->cancel = 0;  // OX. For cancelling anims into a freespecial. 0 by default , 3 when enabled. IMPORTANT!! Must stay as it is!
5844 						newanim->animhits = 0; //OX counts hits on a per anim basis for cancels.
5845 						newanim->subentity = newanim->custbomb = newanim->custknife = newanim->custstar = newanim->custpshotno = -1;
5846 						newanim->quakeframe.framestart = 0;
5847 
5848 						if(strnicmp(value, "idle", 4)==0 &&
5849 						(!value[4] || (value[4] >= '1' && value[4]<='9'))){
5850 								tempInt = atoi(value+4);
5851 								if(tempInt<1) tempInt = 1;
5852 								ani_id = animidles[tempInt-1];
5853 						}
5854 						else if(stricmp(value, "waiting")==0){
5855 								ani_id = ANI_SELECT;
5856 						}
5857 						else if(strnicmp(value, "walk", 4)==0 &&
5858 						(!value[4] || (value[4] >= '1' && value[4]<='9'))){
5859 							tempInt = atoi(value+4);
5860 							if(tempInt<1) tempInt = 1;
5861 							ani_id = animwalks[tempInt-1];
5862 						}
5863 						else if(stricmp(value, "sleep")==0){
5864 							ani_id = ANI_SLEEP;
5865 						}
5866 						else if(stricmp(value, "run")==0){
5867 							ani_id = ANI_RUN;
5868 						}
5869 						else if(strnicmp(value, "up", 2)==0 &&
5870 						(!value[2] || (value[2] >= '1' && value[2]<='9'))){
5871 							tempInt = atoi(value+2);
5872 							if(tempInt<1) tempInt = 1;
5873 							ani_id = animups[tempInt-1];
5874 						}
5875 						else if(strnicmp(value, "down", 4)==0 &&
5876 						(!value[4] || (value[4] >= '1' && value[4]<='9'))){
5877 							tempInt = atoi(value+4);
5878 							if(tempInt<1) tempInt = 1;
5879 							ani_id = animdowns[tempInt-1];
5880 						}
5881 						else if(strnicmp(value, "backwalk", 8)==0 &&
5882 						(!value[8] || (value[8] >= '1' && value[8]<='9'))){
5883 							tempInt = atoi(value+8);
5884 							if(tempInt<1) tempInt = 1;
5885 							ani_id = animbackwalks[tempInt-1];
5886 						}
5887 						else if(stricmp(value, "jump")==0){
5888 							ani_id = ANI_JUMP;
5889 							newanim->range.xmin = 50;    // Used for enemies that jump on walls
5890 							newanim->range.xmax = 60;    // Used for enemies that jump on walls
5891 						}
5892 						else if(stricmp(value, "duck")==0){
5893 							ani_id = ANI_DUCK;
5894 						}
5895 						else if(stricmp(value, "land")==0){
5896 							ani_id = ANI_LAND;
5897 						}
5898 						else if(stricmp(value, "pain")==0){
5899 							ani_id = ANI_PAIN;
5900 						}
5901 						else if(strnicmp(value, "pain", 4)==0 && value[4]>='1' && value[4]<='9'){
5902 							tempInt = atoi(value+4);
5903 							if(tempInt==1){
5904 								ani_id = ANI_PAIN;
5905 							}
5906 							else if(tempInt==2){
5907 								ani_id = ANI_PAIN2;
5908 							}
5909 							else if(tempInt==3){
5910 								ani_id = ANI_PAIN3;
5911 							}
5912 							else if(tempInt==4){
5913 								ani_id = ANI_PAIN4;
5914 							}
5915 							else if(tempInt==5){
5916 								ani_id = ANI_PAIN5;
5917 							}
5918 							else if(tempInt==6){
5919 								ani_id = ANI_PAIN6;
5920 							}
5921 							else if(tempInt==7){
5922 								ani_id = ANI_PAIN7;
5923 							}
5924 							else if(tempInt==8){
5925 								ani_id = ANI_PAIN8;
5926 							}
5927 							else if(tempInt==9){
5928 								ani_id = ANI_PAIN9;
5929 							}
5930 							else if(tempInt==10){
5931 								ani_id = ANI_PAIN10;
5932 							}
5933 							else{
5934 								if(tempInt<MAX_ATKS-STA_ATKS+1) tempInt = MAX_ATKS-STA_ATKS+1;
5935 								ani_id = animpains[tempInt+STA_ATKS-1];
5936 							}
5937 						}
5938 						else if(stricmp(value, "spain")==0){    // If shock attacks don't knock opponent down, play this
5939 							ani_id = ANI_SHOCKPAIN;
5940 						}
5941 						else if(stricmp(value, "bpain")==0){    // If burn attacks don't knock opponent down, play this
5942 							ani_id = ANI_BURNPAIN;
5943 						}
5944 						else if(stricmp(value, "fall")==0){
5945 							ani_id = ANI_FALL;   // If no new animation, load fall animation into both "respawn" & "fall"
5946 							newanim->bounce = 4;
5947 						}
5948 						else if(strnicmp(value, "fall", 4)==0 && value[4]>='1' && value[4]<='9'){
5949 							tempInt = atoi(value+4);
5950 							if(tempInt==1){
5951 								ani_id = ANI_FALL;
5952 							}
5953 							else if(tempInt==2){
5954 								ani_id = ANI_FALL2;
5955 							}
5956 							else if(tempInt==3){
5957 								ani_id = ANI_FALL3;
5958 							}
5959 							else if(tempInt==4){
5960 								ani_id = ANI_FALL4;
5961 							}
5962 							else if(tempInt==5){
5963 								ani_id = ANI_FALL5;
5964 							}
5965 							else if(tempInt==6){
5966 								ani_id = ANI_FALL6;
5967 							}
5968 							else if(tempInt==7){
5969 								ani_id = ANI_FALL7;
5970 							}
5971 							else if(tempInt==8){
5972 								ani_id = ANI_FALL8;
5973 							}
5974 							else if(tempInt==9){
5975 								ani_id = ANI_FALL9;
5976 							}
5977 							else if(tempInt==10){
5978 								ani_id = ANI_FALL10;
5979 							}
5980 							else{
5981 								if(tempInt<MAX_ATKS-STA_ATKS+1) tempInt = MAX_ATKS-STA_ATKS+1;
5982 								ani_id = animfalls[tempInt+STA_ATKS-1];
5983 							}
5984 							newanim->bounce = 4;
5985 						}
5986 						else if(stricmp(value, "shock")==0){    // If shock attacks do knock opponent down, play this
5987 							ani_id = ANI_SHOCK;
5988 							newanim->bounce = 4;
5989 						}
5990 						else if(stricmp(value, "burn")==0){    // If burn attacks do knock opponent down, play this
5991 							ani_id = ANI_BURN;
5992 							newanim->bounce = 4;
5993 						}
5994 						else if(stricmp(value, "death")==0){      //  If new animation is present, overwrite new_anim with it.
5995 							ani_id = ANI_DIE;
5996 						}
5997 						else if(strnicmp(value, "death", 5)==0 && value[5]>='1' && value[5]<='9'){
5998 							tempInt = atoi(value+5);
5999 							if(tempInt==1){
6000 								ani_id = ANI_DIE;
6001 							}
6002 							else if(tempInt==2){
6003 								ani_id = ANI_DIE2;
6004 							}
6005 							else if(tempInt==3){
6006 								ani_id = ANI_DIE3;
6007 							}
6008 							else if(tempInt==4){
6009 								ani_id = ANI_DIE4;
6010 							}
6011 							else if(tempInt==5){
6012 								ani_id = ANI_DIE5;
6013 							}
6014 							else if(tempInt==6){
6015 								ani_id = ANI_DIE6;
6016 							}
6017 							else if(tempInt==7){
6018 								ani_id = ANI_DIE7;
6019 							}
6020 							else if(tempInt==8){
6021 								ani_id = ANI_DIE8;
6022 							}
6023 							else if(tempInt==9){
6024 								ani_id = ANI_DIE9;
6025 							}
6026 							else if(tempInt==10){
6027 								ani_id = ANI_DIE10;
6028 							}
6029 							else{
6030 								if(tempInt<MAX_ATKS-STA_ATKS+1) tempInt = MAX_ATKS-STA_ATKS+1;
6031 								ani_id = animdies[tempInt+STA_ATKS-1];
6032 							}
6033 						}
6034 						else if(stricmp(value, "sdie")==0){
6035 							ani_id = ANI_SHOCKDIE;
6036 						}
6037 						else if(stricmp(value, "bdie")==0){
6038 							ani_id = ANI_BURNDIE;
6039 						}
6040 						else if(stricmp(value, "chipdeath")==0){
6041 							ani_id = ANI_CHIPDEATH;
6042 						}
6043 						else if(stricmp(value, "guardbreak")==0){
6044 							ani_id = ANI_GUARDBREAK;
6045 						}
6046 						else if(stricmp(value, "riseb")==0){
6047 							ani_id = ANI_RISEB;
6048 						}
6049 
6050 
6051 						else if(stricmp(value, "rises")==0){
6052 							ani_id = ANI_RISES;
6053 						}
6054 						else if(stricmp(value, "rise")==0){
6055 							ani_id = ANI_RISE;   // If no new animation, load fall animation into both "respawn" & "fall"
6056 						}
6057 						else if(strnicmp(value, "rise", 4)==0 && value[4]>='1' && value[4]<='9'){
6058 							tempInt = atoi(value+4);
6059 							if(tempInt==1){
6060 								ani_id = ANI_RISE;
6061 							}
6062 							else if(tempInt==2){
6063 								ani_id = ANI_RISE2;
6064 							}
6065 							else if(tempInt==3){
6066 								ani_id = ANI_RISE3;
6067 							}
6068 							else if(tempInt==4){
6069 								ani_id = ANI_RISE4;
6070 							}
6071 							else if(tempInt==5){
6072 								ani_id = ANI_RISE5;
6073 							}
6074 							else if(tempInt==6){
6075 								ani_id = ANI_RISE6;
6076 							}
6077 							else if(tempInt==7){
6078 								ani_id = ANI_RISE7;
6079 							}
6080 							else if(tempInt==8){
6081 								ani_id = ANI_RISE8;
6082 							}
6083 							else if(tempInt==9){
6084 								ani_id = ANI_RISE9;
6085 							}
6086 							else if(tempInt==10){
6087 								ani_id = ANI_RISE10;
6088 							}
6089 							else{
6090 								if(tempInt<MAX_ATKS-STA_ATKS+1) tempInt = MAX_ATKS-STA_ATKS+1;
6091 								ani_id = animrises[tempInt+STA_ATKS-1];
6092 							}
6093 						}
6094 						else if(stricmp(value, "riseattackb")==0){
6095 							ani_id = ANI_RISEATTACKB;
6096 						}
6097 						else if(stricmp(value, "riseattacks")==0){
6098 							ani_id = ANI_RISEATTACKS;
6099 						}
6100 						else if(stricmp(value, "riseattack")==0){
6101 							ani_id = ANI_RISEATTACK;   // If no new animation, load fall animation into both "respawn" & "fall"
6102 						}
6103 						else if(strnicmp(value, "riseattack", 10)==0 && value[10]>='1' && value[10]<='9'){
6104 							tempInt = atoi(value+10);
6105 							if(tempInt==1){
6106 								ani_id = ANI_RISEATTACK;
6107 							}
6108 							else if(tempInt==2){
6109 								ani_id = ANI_RISEATTACK2;
6110 							}
6111 							else if(tempInt==3){
6112 								ani_id = ANI_RISEATTACK3;
6113 							}
6114 							else if(tempInt==4){
6115 								ani_id = ANI_RISEATTACK4;
6116 							}
6117 							else if(tempInt==6){
6118 								ani_id = ANI_RISEATTACK5;
6119 							}
6120 							else if(tempInt==6){
6121 								ani_id = ANI_RISEATTACK6;
6122 							}
6123 							else if(tempInt==7){
6124 								ani_id = ANI_RISEATTACK7;
6125 							}
6126 							else if(tempInt==8){
6127 								ani_id = ANI_RISEATTACK8;
6128 							}
6129 							else if(tempInt==9){
6130 								ani_id = ANI_RISEATTACK9;
6131 							}
6132 							else if(tempInt==10){
6133 								ani_id = ANI_RISEATTACK10;
6134 							}
6135 							else{
6136 								if(tempInt<MAX_ATKS-STA_ATKS+1) tempInt = MAX_ATKS-STA_ATKS+1;
6137 								ani_id = animriseattacks[tempInt+STA_ATKS-1];
6138 							}
6139 						}
6140 						else if(stricmp(value, "select")==0){
6141 							ani_id = ANI_PICK;
6142 						}
6143 						else if(strnicmp(value, "attack", 6)==0 &&
6144 							(!value[6] || (value[6] >= '1' && value[6]<='9')))
6145 						{
6146 							tempInt = atoi(value+6);
6147 							if(tempInt<1) tempInt = 1;
6148 							ani_id = animattacks[tempInt-1];
6149 						}
6150 						else if(stricmp(value, "throwattack")==0){
6151 							ani_id = ANI_THROWATTACK;
6152 						}
6153 						else if(stricmp(value, "upper")==0){
6154 							ani_id = ANI_UPPER;
6155 							attack.counterattack = 100; //default to 100
6156 							newanim->range.xmin = -10;
6157 							newanim->range.xmax = 120;
6158 						}
6159 						else if(stricmp(value, "cant")==0){
6160 							ani_id = ANI_CANT;
6161 						}
6162 						else if(stricmp(value, "jumpcant")==0){
6163 							ani_id = ANI_JUMPCANT;
6164 						}
6165 						else if(stricmp(value, "charge")==0){
6166 							ani_id = ANI_CHARGE;
6167 						}
6168 						else if(stricmp(value, "faint")==0){
6169 							ani_id = ANI_FAINT;
6170 						}
6171 						else if(stricmp(value, "dodge")==0){
6172 							ani_id = ANI_DODGE;
6173 						}
6174 						else if(stricmp(value, "special")==0 || stricmp(value, "special1")==0){
6175 							ani_id = ANI_SPECIAL;
6176 							newanim->energycost.cost = 6;
6177 						}
6178 						else if(stricmp(value, "special2")==0){
6179 							ani_id = ANI_SPECIAL2;
6180 						}
6181 						else if(stricmp(value, "special3")==0 || stricmp(value, "jumpspecial")==0){
6182 							ani_id = ANI_JUMPSPECIAL;
6183 						}
6184 						else if(strnicmp(value, "freespecial", 11)==0 && (!value[11] || (value[11] >= '1' && value[11] <= '9'))){
6185 							tempInt = atoi(value+11);
6186 							if(tempInt<1) tempInt = 1;
6187 							ani_id = animspecials[tempInt-1];
6188 							switch(tempInt) // old default values
6189 							{
6190 								case 1:
6191 									if(!is_set(newchar, ANI_FREESPECIAL))
6192 									{
6193 										newchar->special[newchar->specials_loaded][0] = FLAG_FORWARD;
6194 										newchar->special[newchar->specials_loaded][1] = FLAG_FORWARD;
6195 										newchar->special[newchar->specials_loaded][2] = FLAG_ATTACK;
6196 										newchar->special[newchar->specials_loaded][MAX_SPECIAL_INPUTS-2] = ANI_FREESPECIAL;
6197 										newchar->special[newchar->specials_loaded][MAX_SPECIAL_INPUTS-3] = 3;
6198 										newchar->specials_loaded++;
6199 									}
6200 									break;
6201 								case 2:
6202 									if(!is_set(newchar, ANI_FREESPECIAL2))
6203 									{
6204 										newchar->special[newchar->specials_loaded][0] = FLAG_MOVEDOWN;
6205 										newchar->special[newchar->specials_loaded][1] = FLAG_MOVEDOWN;
6206 										newchar->special[newchar->specials_loaded][2] = FLAG_ATTACK;
6207 										newchar->special[newchar->specials_loaded][MAX_SPECIAL_INPUTS-2] = ANI_FREESPECIAL2;
6208 										newchar->special[newchar->specials_loaded][MAX_SPECIAL_INPUTS-3] = 3;
6209 										newchar->specials_loaded++;
6210 									}
6211 									break;
6212 								case 3:
6213 									if(!is_set(newchar, ANI_FREESPECIAL3))
6214 									{
6215 										newchar->special[newchar->specials_loaded][0] = FLAG_MOVEUP;
6216 										newchar->special[newchar->specials_loaded][1] = FLAG_MOVEUP;
6217 										newchar->special[newchar->specials_loaded][2] = FLAG_ATTACK;
6218 										newchar->special[newchar->specials_loaded][MAX_SPECIAL_INPUTS-2] = ANI_FREESPECIAL3;
6219 										newchar->special[newchar->specials_loaded][MAX_SPECIAL_INPUTS-3] = 3;
6220 										newchar->specials_loaded++;
6221 									}
6222 									break;
6223 							}
6224 						}
6225 						else if(stricmp(value, "jumpattack")==0){
6226 							ani_id = ANI_JUMPATTACK;
6227 							if(newchar->jumpheight==4)
6228 							{
6229 								newanim->range.xmin = 150;
6230 								newanim->range.xmax = 200;
6231 							}
6232 						}
6233 						else if(stricmp(value, "jumpattack2")==0){
6234 							ani_id = ANI_JUMPATTACK2;
6235 						}
6236 						else if(stricmp(value, "jumpattack3")==0){
6237 							ani_id = ANI_JUMPATTACK3;
6238 						}
6239 						else if(stricmp(value, "jumpforward")==0){
6240 							ani_id = ANI_JUMPFORWARD;
6241 						}
6242 						else if(stricmp(value, "runjumpattack")==0){
6243 							ani_id = ANI_RUNJUMPATTACK;
6244 						}
6245 						else if(stricmp(value, "runattack")==0){
6246 							ani_id = ANI_RUNATTACK;    // New attack for when a player is running
6247 						}
6248 						else if(stricmp(value, "attackup")==0){
6249 							ani_id = ANI_ATTACKUP;    // New attack for when a player presses u u
6250 						}
6251 						else if(stricmp(value, "attackdown")==0){
6252 							ani_id = ANI_ATTACKDOWN;    // New attack for when a player presses d d
6253 						}
6254 						else if(stricmp(value, "attackforward")==0){
6255 							ani_id = ANI_ATTACKFORWARD;    // New attack for when a player presses f f
6256 						}
6257 						else if(stricmp(value, "attackbackward")==0){
6258 							ani_id = ANI_ATTACKBACKWARD;    // New attack for when a player presses b a
6259 						}
6260 						else if(stricmp(value, "attackboth")==0){    // Attack that is executed by holding down j and pressing a
6261 							ani_id = ANI_ATTACKBOTH;
6262 						}
6263 						else if(stricmp(value, "get")==0){
6264 							ani_id = ANI_GET;
6265 						}
6266 						else if(stricmp(value, "grab")==0){
6267 							ani_id = ANI_GRAB;
6268 						}
6269 						else if(stricmp(value, "grabwalk")==0){
6270 							ani_id = ANI_GRABWALK;
6271 						}
6272 						else if(stricmp(value, "grabwalkup")==0){
6273 							ani_id = ANI_GRABWALKUP;
6274 						}
6275 						else if(stricmp(value, "grabwalkdown")==0){
6276 							ani_id = ANI_GRABWALKDOWN;
6277 						}
6278 						else if(stricmp(value, "grabbackwalk")==0){
6279 							ani_id = ANI_GRABBACKWALK;
6280 						}
6281 						else if(stricmp(value, "grabturn")==0){
6282 							ani_id = ANI_GRABTURN;
6283 						}
6284 						else if(stricmp(value, "grabbed")==0){    // New grabbed animation for when grabbed
6285 							ani_id = ANI_GRABBED;
6286 						}
6287 						else if(stricmp(value, "grabbedwalk")==0){    // New animation for when grabbed and forced to walk
6288 							ani_id = ANI_GRABBEDWALK;
6289 						}
6290 						else if(stricmp(value, "grabbedwalkup")==0){
6291 							ani_id = ANI_GRABWALKUP;
6292 						}
6293 						else if(stricmp(value, "grabbedwalkdown")==0){
6294 							ani_id = ANI_GRABWALKDOWN;
6295 						}
6296 						else if(stricmp(value, "grabbedbackwalk")==0){
6297 							ani_id = ANI_GRABBEDBACKWALK;
6298 						}
6299 						else if(stricmp(value, "grabbedturn")==0){
6300 							ani_id = ANI_GRABBEDTURN;
6301 						}
6302 						else if(stricmp(value, "grabattack")==0){
6303 							ani_id = ANI_GRABATTACK;
6304 							newanim->attackone = 1; // default to 1, attack one one opponent
6305 						}
6306 						else if(stricmp(value, "grabattack2")==0){
6307 							ani_id = ANI_GRABATTACK2;
6308 							newanim->attackone = 1;
6309 						}
6310 						else if(stricmp(value, "grabforward")==0){    // New grab attack for when pressing forward attack
6311 							ani_id = ANI_GRABFORWARD;
6312 							newanim->attackone = 1;
6313 						}
6314 						else if(stricmp(value, "grabforward2")==0){    // New grab attack for when pressing forward attack
6315 							ani_id = ANI_GRABFORWARD2;
6316 							newanim->attackone = 1;
6317 						}
6318 						else if(stricmp(value, "grabbackward")==0){    // New grab attack for when pressing backward attack
6319 							ani_id = ANI_GRABBACKWARD;
6320 							newanim->attackone = 1;
6321 						}
6322 						else if(stricmp(value, "grabbackward2")==0){    // New grab attack for when pressing backward attack
6323 							ani_id = ANI_GRABBACKWARD2;
6324 							newanim->attackone = 1;
6325 						}
6326 						else if(stricmp(value, "grabup")==0){    // New grab attack for when pressing up attack
6327 							ani_id = ANI_GRABUP;
6328 							newanim->attackone = 1;
6329 						}
6330 						else if(stricmp(value, "grabup2")==0){    // New grab attack for when pressing up attack
6331 							ani_id = ANI_GRABUP2;
6332 							newanim->attackone = 1;
6333 						}
6334 						else if(stricmp(value, "grabdown")==0){    // New grab attack for when pressing down attack
6335 							ani_id = ANI_GRABDOWN;
6336 							newanim->attackone = 1;
6337 						}
6338 						else if(stricmp(value, "grabdown2")==0){    // New grab attack for when pressing down attack
6339 							ani_id = ANI_GRABDOWN2;
6340 							newanim->attackone = 1;
6341 						}
6342 						else if(stricmp(value, "spawn")==0){      //  spawn/respawn works separately now
6343 							ani_id = ANI_SPAWN;
6344 						}
6345 						else if(stricmp(value, "respawn")==0){      //  spawn/respawn works separately now
6346 							ani_id = ANI_RESPAWN;
6347 						}
6348 						else if(stricmp(value, "throw")==0){
6349 							ani_id = ANI_THROW;
6350 						}
6351 						else if(stricmp(value, "block")==0){    // Now enemies can block attacks on occasion
6352 							ani_id = ANI_BLOCK;
6353 							newanim->range.xmin = 1;
6354 							newanim->range.xmax = 100;
6355 						}
6356 						else if(strnicmp(value, "follow", 6)==0 && (!value[6] || (value[6]>='1' && value[6]<='9'))){
6357 							tempInt = atoi(value+6);
6358 							if(tempInt<1) tempInt = 1;
6359 							ani_id = animfollows[tempInt-1];
6360 						}
6361 						else if(stricmp(value, "chargeattack")==0){
6362 							ani_id = ANI_CHARGEATTACK;
6363 						}
6364 						else if(stricmp(value, "vault")==0){
6365 							ani_id = ANI_VAULT;
6366 						}
6367 						else if(stricmp(value, "turn")==0){
6368 							ani_id = ANI_TURN;
6369 						}
6370 						else if(stricmp(value, "forwardjump")==0){
6371 							ani_id = ANI_FORWARDJUMP;
6372 						}
6373 						else if(stricmp(value, "runjump")==0){
6374 							ani_id = ANI_RUNJUMP;
6375 						}
6376 						else if(stricmp(value, "jumpland")==0){
6377 							ani_id = ANI_JUMPLAND;
6378 						}
6379 						else if(stricmp(value, "jumpdelay")==0){
6380 							ani_id = ANI_JUMPDELAY;
6381 						}
6382 						else if(stricmp(value, "hitwall")==0){
6383 							ani_id = ANI_HITWALL;
6384 						}
6385 						else if(stricmp(value, "slide")==0){
6386 							ani_id = ANI_SLIDE;
6387 						}
6388 						else if(stricmp(value, "runslide")==0){
6389 							ani_id = ANI_RUNSLIDE;
6390 						}
6391 						else if(stricmp(value, "blockpainb")==0){
6392 							ani_id = ANI_BLOCKPAINB;
6393 						}
6394 						else if(stricmp(value, "blockpains")==0){
6395 							ani_id = ANI_BLOCKPAINS;
6396 						}
6397 						else if(stricmp(value, "blockpain")==0){
6398 							ani_id = ANI_BLOCKPAIN;   // If no new animation, load fall animation into both "respawn" & "fall"
6399 						}
6400 						else if(strnicmp(value, "blockpain", 9)==0 && value[9]>='1' && value[9]<='9'){
6401 							tempInt = atoi(value+9);
6402 							if(tempInt==1){
6403 								ani_id = ANI_BLOCKPAIN;
6404 							}
6405 							else if(tempInt==2){
6406 								ani_id = ANI_BLOCKPAIN2;
6407 							}
6408 							else if(tempInt==3){
6409 								ani_id = ANI_BLOCKPAIN3;
6410 							}
6411 							else if(tempInt==4){
6412 								ani_id = ANI_BLOCKPAIN4;
6413 							}
6414 							else if(tempInt==5){
6415 								ani_id = ANI_BLOCKPAIN5;
6416 							}
6417 							else if(tempInt==6){
6418 								ani_id = ANI_BLOCKPAIN6;
6419 							}
6420 							else if(tempInt==7){
6421 								ani_id = ANI_BLOCKPAIN7;
6422 							}
6423 							else if(tempInt==8){
6424 								ani_id = ANI_BLOCKPAIN8;
6425 							}
6426 							else if(tempInt==9){
6427 								ani_id = ANI_BLOCKPAIN9;
6428 							}
6429 							else if(tempInt==10){
6430 								ani_id = ANI_BLOCKPAIN10;
6431 							}
6432 							else{
6433 								if(tempInt<MAX_ATKS-STA_ATKS+1) tempInt = MAX_ATKS-STA_ATKS+1;
6434 								ani_id = animblkpains[tempInt+STA_ATKS-1];
6435 							}
6436 						}
6437 						else if(stricmp(value, "duckattack")==0){
6438 							ani_id = ANI_DUCKATTACK;
6439 						}
6440 						else if(stricmp(value, "walkoff")==0){
6441 							ani_id = ANI_WALKOFF;
6442 						}
6443 						else {
6444 							shutdownmessage = "Invalid animation name!";
6445 							goto lCleanup;
6446 						}
6447 
6448 						newchar->animation[ani_id] = newanim;
6449 					}
6450 					break;
6451 				case CMD_MODEL_LOOP:
6452 					if(!newanim) {
6453 						shutdownmessage = "Can't set loop: no animation specified!";
6454 						goto lCleanup;
6455 					}
6456 					newanim->loop.mode          = GET_INT_ARG(1); //0 = Off, 1 = on.
6457 					newanim->loop.framestart    = GET_INT_ARG(2); //Loop to frame.
6458 					newanim->loop.frameend      = GET_INT_ARG(3); //Loop end frame.
6459 					break;
6460 				case CMD_MODEL_ANIMHEIGHT:
6461 					newanim->height = GET_INT_ARG(1);
6462 					break;
6463 				case CMD_MODEL_DELAY:
6464 					delay = GET_INT_ARG(1);
6465 					break;
6466 				case CMD_MODEL_OFFSET:
6467 					offset[0] = GET_INT_ARG(1);
6468 					offset[1] = GET_INT_ARG(2);
6469 					break;
6470 				case CMD_MODEL_SHADOWCOORDS:
6471 					shadow_xz[0] = GET_INT_ARG(1);
6472 					shadow_xz[1] = GET_INT_ARG(2);
6473 					shadow_set=1;
6474 					break;
6475 				case CMD_MODEL_ENERGYCOST: case CMD_MODEL_MPCOST:
6476 					newanim->energycost.cost    = GET_INT_ARG(1);
6477 					newanim->energycost.mponly  = GET_INT_ARG(2);
6478 					newanim->energycost.disable = GET_INT_ARG(3);
6479 					break;
6480 				case CMD_MODEL_MPONLY:
6481 					newanim->energycost.mponly = GET_INT_ARG(1);
6482 					break;
6483 				case CMD_MODEL_CHARGETIME:
6484 					newanim->chargetime = GET_FLOAT_ARG(1);
6485 					break;
6486 				case CMD_MODEL_DIVE:	//dive kicks
6487 					newanim->dive.x = GET_FLOAT_ARG(1);
6488 					newanim->dive.v = GET_FLOAT_ARG(2);
6489 					break;
6490 				case CMD_MODEL_DIVE1:
6491 					newanim->dive.x = GET_FLOAT_ARG(1);
6492 					break;
6493 				case CMD_MODEL_DIVE2:
6494 					newanim->dive.v = GET_FLOAT_ARG(1);
6495 					break;
6496 				case CMD_MODEL_ATTACKONE:
6497 					newanim->attackone = GET_INT_ARG(1);
6498 					break;
6499 				case CMD_MODEL_COUNTERATTACK:
6500 					attack.counterattack = GET_INT_ARG(1);
6501 					break;
6502 				case CMD_MODEL_THROWFRAME:	case CMD_MODEL_PSHOTFRAME: case CMD_MODEL_PSHOTFRAMEW: case CMD_MODEL_PSHOTFRAMENO:
6503 					newanim->throwframe = GET_INT_ARG(1);
6504 					newanim->throwa = GET_INT_ARG(2);
6505 					if(!newanim->throwa)
6506 						newanim->throwa = 70;
6507 					else if(newanim->throwa == -1)
6508 						newanim->throwa = 0;
6509 					break;
6510 				case CMD_MODEL_SHOOTFRAME:
6511 					newanim->shootframe = GET_INT_ARG(1);
6512 					newanim->throwa = GET_INT_ARG(2);
6513 					if(newanim->throwa == -1)
6514 						newanim->throwa = 0;
6515 					break;
6516 				case CMD_MODEL_TOSSFRAME: case CMD_MODEL_PBOMBFRAME:
6517 					newanim->tossframe = GET_INT_ARG(1);
6518 					newanim->throwa = GET_INT_ARG(2);
6519 					if(newanim->throwa < 0) newanim->throwa = -1;
6520 					break;
6521 				case CMD_MODEL_CUSTKNIFE: case CMD_MODEL_CUSTPSHOT: case CMD_MODEL_CUSTPSHOTW:
6522 					newanim->custknife= get_cached_model_index(GET_ARG(1));
6523 					break;
6524 				case CMD_MODEL_CUSTPSHOTNO:
6525 					newanim->custpshotno= get_cached_model_index(GET_ARG(1));
6526 					break;
6527 				case CMD_MODEL_CUSTBOMB: case CMD_MODEL_CUSTPBOMB:
6528 					newanim->custbomb= get_cached_model_index(GET_ARG(1));
6529 					break;
6530 				case CMD_MODEL_CUSTSTAR:
6531 					newanim->custstar= get_cached_model_index(GET_ARG(1));
6532 					break;
6533 				case CMD_MODEL_JUMPFRAME:
6534 					{
6535 						newanim->jumpframe.f    = GET_INT_ARG(1);   //Frame.
6536 						newanim->jumpframe.v    = GET_FLOAT_ARG(2); //Vertical velocity.
6537 						value = GET_ARG(3);
6538 						if(value[0])
6539 						{
6540 							newanim->jumpframe.x = GET_FLOAT_ARG(3);
6541 							newanim->jumpframe.z = GET_FLOAT_ARG(4);
6542 						}
6543 						else // k, only for backward compatibility :((((((((((((((((
6544 						{
6545 							if(newanim->jumpframe.v <= 0)
6546 							{
6547 								if(newchar->type == TYPE_PLAYER)
6548 								{
6549 									newanim->jumpframe.v = newchar->jumpheight / 2;
6550 									newanim->jumpframe.z = 0;
6551 									newanim->jumpframe.x = 2;
6552 								}
6553 								else
6554 								{
6555 									newanim->jumpframe.v = newchar->jumpheight;
6556 									newanim->jumpframe.z = newanim->jumpframe.x = 0;
6557 								}
6558 							}
6559 							else
6560 							{
6561 								if(newchar->type != TYPE_ENEMY && newchar->type != TYPE_NPC)
6562 									newanim->jumpframe.z = newanim->jumpframe.x = 0;
6563 								else
6564 								{
6565 									newanim->jumpframe.z = 0;
6566 									newanim->jumpframe.x = (float)1.3;
6567 								}
6568 							}
6569 						}
6570 
6571 						value = GET_ARG(5);
6572 						if(value[0]) newanim->jumpframe.ent = get_cached_model_index(value);
6573 						else newanim->jumpframe.ent = -1;
6574 
6575 					}
6576 					break;
6577 				case CMD_MODEL_BOUNCEFACTOR:
6578 					newanim->bounce = GET_FLOAT_ARG(1);
6579 					break;
6580 				case CMD_MODEL_LANDFRAME:
6581 					newanim->landframe.frame = GET_INT_ARG(1);
6582 					value = GET_ARG(2);
6583 					if(value[0]) newanim->landframe.ent = get_cached_model_index(value);
6584 					else newanim->landframe.ent = -1;
6585 					break;
6586 				case CMD_MODEL_DROPFRAME:
6587 					newanim->dropframe = GET_INT_ARG(1);
6588 					break;
6589 				case CMD_MODEL_CANCEL:
6590 					{
6591 						int i;                                                                   // OX. Modified copy/paste of COM settings code
6592 						int t;
6593 						newanim->cancel = 3;
6594 						for(i = 0, t = 4; i < MAX_SPECIAL_INPUTS-6; i++, t++)
6595 						{
6596 							value = GET_ARG(t);
6597 							if(!value[0]) break;
6598 							if(stricmp(value, "u")==0){
6599 								newchar->special[newchar->specials_loaded][i] = FLAG_MOVEUP;
6600 							}
6601 							else if(stricmp(value, "d")==0){
6602 								newchar->special[newchar->specials_loaded][i] = FLAG_MOVEDOWN;
6603 							}
6604 							else if(stricmp(value, "f")==0){
6605 								newchar->special[newchar->specials_loaded][i] = FLAG_FORWARD;
6606 							}
6607 							else if(stricmp(value, "b")==0){
6608 								newchar->special[newchar->specials_loaded][i] = FLAG_BACKWARD;
6609 							}
6610 							else if(stricmp(value, "a")==0){
6611 								newchar->special[newchar->specials_loaded][i] = FLAG_ATTACK;
6612 							}
6613 							else if(stricmp(value, "a2")==0){
6614 								newchar->special[newchar->specials_loaded][i] = FLAG_ATTACK2;
6615 							}
6616 							else if(stricmp(value, "a3")==0){
6617 								newchar->special[newchar->specials_loaded][i] = FLAG_ATTACK3;
6618 							}
6619 							else if(stricmp(value, "a4")==0){
6620 								newchar->special[newchar->specials_loaded][i] = FLAG_ATTACK4;
6621 							}
6622 							else if(stricmp(value, "j")==0){
6623 								newchar->special[newchar->specials_loaded][i] = FLAG_JUMP;
6624 							}
6625 							else if(stricmp(value, "s")==0){
6626 								newchar->special[newchar->specials_loaded][i] = FLAG_SPECIAL;
6627 							}
6628 							else if(stricmp(value, "k")==0){
6629 								newchar->special[newchar->specials_loaded][i] = FLAG_SPECIAL;
6630 							}
6631 							else if(strnicmp(value, "freespecial", 11)==0 && (!value[11] || (value[11] >= '1' && value[11] <= '9'))){
6632 								tempInt = atoi(value+11);
6633 								if(tempInt<1) tempInt = 1;
6634 								newchar->special[newchar->specials_loaded][MAX_SPECIAL_INPUTS-5] = animspecials[tempInt-1];
6635 								newchar->special[newchar->specials_loaded][MAX_SPECIAL_INPUTS-7] = GET_INT_ARG(1); // stores start frame
6636 								newchar->special[newchar->specials_loaded][MAX_SPECIAL_INPUTS-8] = GET_INT_ARG(2); // stores end frame
6637 								newchar->special[newchar->specials_loaded][MAX_SPECIAL_INPUTS-9] = ani_id;                    // stores current anim
6638 								newchar->special[newchar->specials_loaded][MAX_SPECIAL_INPUTS-10] = GET_INT_ARG(3);// stores hits
6639 							}
6640 							else {
6641 								shutdownmessage = "Invalid cancel command!";
6642 								goto lCleanup;
6643 							}
6644 						}
6645 						newchar->special[newchar->specials_loaded][MAX_SPECIAL_INPUTS-6]=i-1; // max steps
6646 						newchar->specials_loaded++;
6647 						if(newchar->specials_loaded > max_freespecials) {
6648 							shutdownmessage = "Too many Freespecials and/or Cancels. Please increase Maxfreespecials";
6649 							goto lCleanup;
6650 						}
6651 					}
6652 					break;
6653 				case CMD_MODEL_SOUND:
6654 					soundtoplay = sound_load_sample(GET_ARG(1), packfile, 0);
6655 					break;
6656 				case CMD_MODEL_HITFX:
6657 					attack.hitsound = sound_load_sample(GET_ARG(1), packfile, 0);
6658 					break;
6659 				case CMD_MODEL_HITFLASH:
6660 					value = GET_ARG(1);
6661 					if(stricmp(value, "none")==0) attack.hitflash = -1;
6662 					else attack.hitflash = get_cached_model_index(value);
6663 					break;
6664 				case CMD_MODEL_BLOCKFLASH:
6665 					value = GET_ARG(1);
6666 					if(stricmp(value, "none")==0) attack.blockflash = -1;
6667 					else attack.blockflash = get_cached_model_index(value);
6668 					break;
6669 				case CMD_MODEL_BLOCKFX:
6670 					attack.blocksound = sound_load_sample(GET_ARG(1), packfile, 0);
6671 					break;
6672 				case CMD_MODEL_FASTATTACK:
6673 					newanim->fastattack = GET_INT_ARG(1);
6674 					break;
6675 				case CMD_MODEL_BBOX:
6676 					bbox[0] = GET_INT_ARG(1);
6677 					bbox[1] = GET_INT_ARG(2);
6678 					bbox[2] = GET_INT_ARG(3);
6679 					bbox[3] = GET_INT_ARG(4);
6680 					bbox[4] = GET_INT_ARG(5);
6681 					break;
6682 				case CMD_MODEL_BBOXZ:
6683 					bbox[4] = GET_INT_ARG(1);
6684 					break;
6685 				case CMD_MODEL_PLATFORM:
6686 					//for(i=0;(GET_ARG(i+1)[0]; i++);
6687 					for(i=0;i<arglist.count && arglist.args[i] && arglist.args[i][0];i++);
6688 					if(i<8)
6689 					{
6690 						for(i=0;i<6; i++) platform[i+2] = GET_FLOAT_ARG(i+1);
6691 						platform[0] = 99999;
6692 					}
6693 					else for(i=0; i<8; i++) platform[i] = GET_FLOAT_ARG(i+1);
6694 					break;
6695 				case CMD_MODEL_DRAWMETHOD:
6696 					// special effects
6697 					drawmethod.scalex = GET_INT_ARG(1);
6698 					drawmethod.scaley = GET_INT_ARG(2);
6699 					drawmethod.flipx = GET_INT_ARG(3);
6700 					drawmethod.flipy = GET_INT_ARG(4);
6701 					drawmethod.shiftx = GET_INT_ARG(5);
6702 					drawmethod.alpha = GET_INT_ARG(6);
6703 					if(!blendfx_is_set)
6704 					{
6705 						if(drawmethod.alpha>0 && drawmethod.alpha<=MAX_BLENDINGS)
6706 						{
6707 							blendfx[drawmethod.alpha-1] = 1;
6708 						}
6709 					}
6710 					drawmethod.remap = GET_INT_ARG(7);
6711 					drawmethod.fillcolor = parsecolor(GET_ARG(8));
6712 					drawmethod.rotate = GET_INT_ARG(9);
6713 					drawmethod.fliprotate = GET_INT_ARG(10);
6714 					if(drawmethod.scalex<0) {drawmethod.scalex = -drawmethod.scalex;drawmethod.flipx = !drawmethod.flipx;}
6715 					if(drawmethod.scaley<0) {drawmethod.scaley = -drawmethod.scaley;drawmethod.flipy = !drawmethod.flipy;}
6716 					if(drawmethod.rotate)
6717 					{
6718 						drawmethod.rotate = (drawmethod.rotate%360 + 360)%360;
6719 					}
6720 					drawmethod.flag = 1;
6721 					break;
6722 				case CMD_MODEL_NODRAWMETHOD:
6723 					//disable special effects
6724 					drawmethod.flag = 0;
6725 					break;
6726 				case CMD_MODEL_ATTACK: case CMD_MODEL_ATTACK1:  case CMD_MODEL_ATTACK2: case CMD_MODEL_ATTACK3:
6727 				case CMD_MODEL_ATTACK4: case CMD_MODEL_ATTACK5: case CMD_MODEL_ATTACK6: case CMD_MODEL_ATTACK7:
6728 				case CMD_MODEL_ATTACK8: case CMD_MODEL_ATTACK9: case CMD_MODEL_ATTACK10:
6729 				case CMD_MODEL_SHOCK: case CMD_MODEL_BURN: case CMD_MODEL_STEAL: case CMD_MODEL_FREEZE: case CMD_MODEL_ITEMBOX:
6730 				case CMD_MODEL_ATTACK_ETC:
6731 					abox[0] = GET_INT_ARG(1);
6732 					abox[1] = GET_INT_ARG(2);
6733 					abox[2] = GET_INT_ARG(3);
6734 					abox[3] = GET_INT_ARG(4);
6735 					attack.dropv[0] = 3;
6736 					attack.dropv[1] = (float)1.2;
6737 					attack.dropv[2] = 0;
6738 					attack.attack_force = GET_INT_ARG(5);
6739 
6740 					attack.attack_drop = GET_INT_ARG(6);
6741 
6742 					attack.no_block = GET_INT_ARG(7);
6743 					attack.no_flash = GET_INT_ARG(8);
6744 					attack.pause_add = GET_INT_ARG(9);
6745 					attack.attack_coords[4] = GET_INT_ARG(10); // depth or z
6746 
6747 					switch(cmd) {
6748 						case CMD_MODEL_ATTACK: case CMD_MODEL_ATTACK1:
6749 							attack.attack_type = ATK_NORMAL;
6750 							break;
6751 						case CMD_MODEL_ATTACK2:
6752 							attack.attack_type  = ATK_NORMAL2;
6753 							break;
6754 						case CMD_MODEL_ATTACK3:
6755 							attack.attack_type  = ATK_NORMAL3;
6756 							break;
6757 						case CMD_MODEL_ATTACK4:
6758 							attack.attack_type  = ATK_NORMAL4;
6759 							break;
6760 						case CMD_MODEL_ATTACK5:
6761 							attack.attack_type  = ATK_NORMAL5;
6762 							break;
6763 						case CMD_MODEL_ATTACK6:
6764 							attack.attack_type  = ATK_NORMAL6;
6765 							break;
6766 						case CMD_MODEL_ATTACK7:
6767 							attack.attack_type  = ATK_NORMAL7;
6768 							break;
6769 						case CMD_MODEL_ATTACK8:
6770 							attack.attack_type  = ATK_NORMAL8;
6771 							break;
6772 						case CMD_MODEL_ATTACK9:
6773 							attack.attack_type  = ATK_NORMAL9;
6774 							break;
6775 						case CMD_MODEL_ATTACK10:
6776 							attack.attack_type  = ATK_NORMAL10;
6777 							break;
6778 						case CMD_MODEL_SHOCK:
6779 							attack.attack_type  = ATK_SHOCK;
6780 							break;
6781 						case CMD_MODEL_BURN:
6782 							attack.attack_type  = ATK_BURN;
6783 							break;
6784 						case CMD_MODEL_STEAL:
6785 							attack.steal = 1;
6786 							attack.attack_type  = ATK_STEAL;
6787 							break;
6788 						case CMD_MODEL_FREEZE:
6789 							attack.attack_type  = ATK_FREEZE;
6790 							attack.freeze = 1;
6791 							attack.freezetime = GET_INT_ARG(6) * GAME_SPEED;
6792 							attack.forcemap = -1;
6793 							attack.attack_drop = 0;
6794 							break;
6795 						case CMD_MODEL_ITEMBOX:
6796 							attack.attack_type  = ATK_ITEM;
6797 							break;
6798 						default:
6799 							tempInt = atoi(command+6);
6800 							if(tempInt<MAX_ATKS-STA_ATKS+1)
6801 								tempInt = MAX_ATKS-STA_ATKS+1;
6802 							attack.attack_type = tempInt+STA_ATKS-1;
6803 					}
6804 					break;
6805 				case CMD_MODEL_ATTACKZ: case CMD_MODEL_HITZ:
6806 					attack.attack_coords[4] = GET_INT_ARG(1);
6807 					break;
6808 				case CMD_MODEL_BLAST:
6809 					abox[0] = GET_INT_ARG(1);
6810 					abox[1] = GET_INT_ARG(2);
6811 					abox[2] = GET_INT_ARG(3);
6812 					abox[3] = GET_INT_ARG(4);
6813 					attack.dropv[0] = 3;
6814 					attack.dropv[1] = 2.5;
6815 					attack.dropv[2] = 0;
6816 					attack.attack_force = GET_INT_ARG(5);
6817 					attack.no_block = GET_INT_ARG(6);
6818 					attack.no_flash = GET_INT_ARG(7);
6819 					attack.pause_add = GET_INT_ARG(8);
6820 					attack.attack_drop = 1;
6821 					attack.attack_type = ATK_BLAST;
6822 					attack.attack_coords[4] = GET_INT_ARG(9); // depth or z
6823 					attack.blast = 1;
6824 					break;
6825 				case CMD_MODEL_DROPV:
6826 					// drop velocity add if the target is knocked down
6827 					pattack = (!newanim && newchar->smartbomb)?newchar->smartbomb:&attack;
6828 					pattack->dropv[0] = GET_FLOAT_ARG(1); // height add
6829 					pattack->dropv[1] = GET_FLOAT_ARG(2); // xdir add
6830 					pattack->dropv[2] = GET_FLOAT_ARG(3); // zdir add
6831 					break;
6832 				case CMD_MODEL_OTG:
6833 					// Over The Ground hit.
6834 					attack.otg = GET_INT_ARG(1);
6835 					break;
6836 				case CMD_MODEL_JUGGLECOST:
6837 					// if cost >= opponents jugglepoints , we can juggle
6838 					attack.jugglecost = GET_INT_ARG(1);
6839 					break;
6840 				case CMD_MODEL_GUARDCOST:
6841 					// if cost >= opponents guardpoints , opponent will play guardcrush anim
6842 					attack.guardcost = GET_INT_ARG(1);
6843 					break;
6844 				case CMD_MODEL_STUN:
6845 					//Like Freeze, but no auto remap.
6846 					pattack = (!newanim && newchar->smartbomb)?newchar->smartbomb:&attack;
6847 					pattack->freeze = 1;
6848 					pattack->freezetime = GET_INT_ARG(1) * GAME_SPEED;
6849 					pattack->attack_drop = 0;
6850 					break;
6851 				case CMD_MODEL_GRABIN:
6852 					// fake grab distanse efffect, not link
6853 					pattack = (!newanim && newchar->smartbomb)?newchar->smartbomb:&attack;
6854 					pattack->grab =  GET_INT_ARG(1);
6855 					pattack->grab_distance = GET_FLOAT_ARG(2);
6856 					break;
6857 				case CMD_MODEL_NOREFLECT:
6858 					// only cost target's hp, don't knock down or cause pain, unless the target is killed
6859 					pattack = (!newanim && newchar->smartbomb)?newchar->smartbomb:&attack;
6860 					pattack->no_pain = GET_INT_ARG(1);
6861 					break;
6862 				case CMD_MODEL_NOKILL:
6863 					// don't kill the target, leave 1 hp
6864 					pattack = (!newanim && newchar->smartbomb)?newchar->smartbomb:&attack;
6865 					pattack->no_kill = GET_INT_ARG(1);
6866 					break;
6867 				case CMD_MODEL_FORCEDIRECTION:
6868 					// the attack direction
6869 					pattack = (!newanim && newchar->smartbomb)?newchar->smartbomb:&attack;
6870 					pattack->force_direction = GET_INT_ARG(1);
6871 					break;
6872 				case CMD_MODEL_DAMAGEONLANDING:
6873 					// fake throw damage on landing
6874 					pattack = (!newanim && newchar->smartbomb)?newchar->smartbomb:&attack;
6875 					pattack->damage_on_landing = GET_INT_ARG(1);
6876 					pattack->blast = GET_INT_ARG(2);
6877 					break;
6878 				case CMD_MODEL_SEAL:
6879 					// Disable special moves for specified time.
6880 					pattack = (!newanim && newchar->smartbomb)?newchar->smartbomb:&attack;
6881 					pattack->sealtime = GET_INT_ARG(1) * GAME_SPEED;
6882 					pattack->seal = GET_INT_ARG(2);
6883 					break;
6884 				case CMD_MODEL_STAYDOWN:
6885 					// Disable special moves for specified time.
6886 					pattack = (!newanim && newchar->smartbomb)?newchar->smartbomb:&attack;
6887 					pattack->staydown[0]    = GET_INT_ARG(1); //Risetime modifier.
6888 					pattack->staydown[1]    = GET_INT_ARG(2); //Riseattack time addition and toggle.
6889 					break;
6890 				case CMD_MODEL_DOT:
6891 					// Cause damage over time effect.
6892 					attack.dot_index  = GET_INT_ARG(1);  //Index.
6893 					attack.dot_time   = GET_INT_ARG(2);  //Time to expiration.
6894 					attack.dot        = GET_INT_ARG(3);  //Mode, see common_dot.
6895 					attack.dot_force  = GET_INT_ARG(4);  //Amount per tick.
6896 					attack.dot_rate   = GET_INT_ARG(5);  //Tick delay.
6897 					break;
6898 				case CMD_MODEL_FORCEMAP:
6899 					// force color map change for specified time
6900 					pattack = (!newanim && newchar->smartbomb)?newchar->smartbomb:&attack;
6901 					pattack->forcemap = GET_INT_ARG(1);
6902 					pattack->maptime = GET_FLOAT_ARG(2) * GAME_SPEED;
6903 					break;
6904 				case CMD_MODEL_IDLE:
6905 					idle = GET_INT_ARG(1);
6906 					break;
6907 				case CMD_MODEL_MOVE:
6908 					move = GET_INT_ARG(1);
6909 					break;
6910 				case CMD_MODEL_MOVEZ:
6911 					movez = GET_INT_ARG(1);
6912 					break;
6913 				case CMD_MODEL_MOVEA:
6914 					movea = GET_INT_ARG(1);
6915 					break;
6916 				case CMD_MODEL_SETA:
6917 					seta = GET_INT_ARG(1);
6918 					break;
6919 				case CMD_MODEL_FSHADOW:
6920 					frameshadow = GET_INT_ARG(1);
6921 					break;
6922 				case CMD_MODEL_RANGE:
6923 					if(!newanim) {
6924 						shutdownmessage = "Cannot set range: no animation!";
6925 						goto lCleanup;
6926 					}
6927 					newanim->range.xmin = GET_INT_ARG(1);
6928 					newanim->range.xmax = GET_INT_ARG(2);
6929 					break;
6930 				case CMD_MODEL_RANGEZ:
6931 					if(!newanim) {
6932 						shutdownmessage = "Cannot set rangez: no animation!";
6933 						goto lCleanup;
6934 					}
6935 					newanim->range.zmin = GET_INT_ARG(1);
6936 					newanim->range.zmax = GET_INT_ARG(2);
6937 					break;
6938 				case CMD_MODEL_RANGEA:
6939 					if(!newanim) {
6940 						shutdownmessage = "Cannot set rangea: no animation!";
6941 						goto lCleanup;
6942 					}
6943 					newanim->range.amin = GET_INT_ARG(1);
6944 					newanim->range.amax = GET_INT_ARG(2);
6945 					break;
6946 				case CMD_MODEL_RANGEB:
6947 					if(!newanim) {
6948 						shutdownmessage = "Cannot set rangeb: no animation!";
6949 						goto lCleanup;
6950 					}
6951 					newanim->range.bmin = GET_INT_ARG(1);
6952 					newanim->range.bmax = GET_INT_ARG(2);
6953 					break;
6954 				case CMD_MODEL_FRAME:
6955 					{
6956 						if(!newanim) {
6957 							shutdownmessage = "Cannot add frame: animation not specified!";
6958 							goto lCleanup;
6959 						}
6960 						peek = 0;
6961 						if(frameset && framecount>=0) framecount = -framecount;
6962 						while(!frameset){
6963 							value3 = findarg(buf+pos+peek, 0);
6964 							if(stricmp(value3, "frame")==0) framecount++;
6965 							if((stricmp(value3, "anim")==0) || (pos+peek >= size)) frameset = 1;
6966 							// Go to next line
6967 							while(buf[pos+peek] && buf[pos+peek]!='\n' && buf[pos+peek]!='\r') ++peek;
6968 							while(buf[pos+peek]=='\n' || buf[pos+peek]=='\r') ++peek;
6969 						}
6970 						value = GET_ARG(1);
6971 						//printf("frame count: %d\n",framecount);
6972 						//printf("Load sprite '%s'...\n", value);
6973 						index = loadsprite(value, offset[0], offset[1],PIXEL_8);//don't use palette for the sprite since it will one palette from the entity's remap list in 24bit mode
6974 						if(pixelformat==PIXEL_x8)
6975 						{
6976 							// for old mod just give it a default palette
6977 							if(newchar->palette==NULL)
6978 							{
6979 								newchar->palette = malloc(PAL_BYTES);
6980 								if(loadimagepalette(value, packfile, newchar->palette)==0) {
6981 									shutdownmessage = "Failed to load palette!";
6982 									goto lCleanup;
6983 								}
6984 							}
6985 							if(index>=0)
6986 							{
6987 								sprite_map[index].sprite->palette = newchar->palette;
6988 								sprite_map[index].sprite->pixelformat = pixelformat;
6989 							}
6990 						}
6991 						if((index>=0) && (maskindex>=0))
6992 						{
6993 							sprite_map[index].sprite->mask = sprite_map[maskindex].sprite;
6994 							maskindex = -1;
6995 						}
6996 						// Adjust coords: add offsets and change size to coords
6997 						bbox_con[0] = bbox[0] - offset[0];
6998 						bbox_con[1] = bbox[1] - offset[1];
6999 						bbox_con[2] = bbox[2] + bbox_con[0];
7000 						bbox_con[3] = bbox[3] + bbox_con[1];
7001 						bbox_con[4] = bbox[4];
7002 						attack.attack_coords[0] = abox[0] - offset[0];
7003 						attack.attack_coords[1] = abox[1] - offset[1];
7004 						attack.attack_coords[2] = abox[2] + attack.attack_coords[0];
7005 						attack.attack_coords[3] = abox[3] + attack.attack_coords[1];
7006 						//attack.attack_coords[4] = abox[4];
7007 						if(platform[0]==99999) // old style
7008 						{
7009 							platform_con[0] = 0;
7010 							platform_con[1] = 3;
7011 							platform_con[2] = platform[2] - offset[0];
7012 							platform_con[3] = platform[3] - offset[0];
7013 							platform_con[4] = platform[4] - offset[0];
7014 							platform_con[5] = platform[5] - offset[0];
7015 							platform_con[6] = platform[6]+3;
7016 						}
7017 						else // wall style
7018 						{
7019 							platform_con[0] = platform[0] - offset[0];
7020 							platform_con[1] = platform[1] - offset[1];
7021 							platform_con[2] = platform[2];
7022 							platform_con[3] = platform[3];
7023 							platform_con[4] = platform[4];
7024 							platform_con[5] = platform[5];
7025 							platform_con[6] = platform[6];
7026 						}
7027 						platform_con[6] = platform[6];
7028 						platform_con[7] = platform[7];
7029 						if(shadow_set)
7030 						{
7031 							shadow_coords[0] = shadow_xz[0] - offset[0];
7032 							shadow_coords[1] = shadow_xz[1] - offset[1];
7033 						}
7034 						else
7035 						{
7036 							shadow_coords[0] = shadow_coords[1] = 0;
7037 						}
7038 
7039 						curframe = addframe(newanim, index, framecount, delay, (unsigned char)idle,
7040 								bbox_con, &attack, move, movez,
7041 								movea, seta, platform_con, frameshadow, shadow_coords, soundtoplay, &drawmethod);
7042 
7043 								memset(bbox_con, 0, sizeof(bbox_con));
7044 								soundtoplay = -1;
7045 					}
7046 					break;
7047 				case CMD_MODEL_ALPHAMASK:
7048 					if(!newanim){
7049 						shutdownmessage = "Cannot add alpha mask: animation not specified!";
7050 						goto lCleanup;
7051 					}
7052 					if(maskindex>=0) {
7053 						shutdownmessage = "Cannot add alpha mask: a mask has already been specified for this frame!";
7054 						goto lCleanup;
7055 					}
7056 					value = GET_ARG(1);
7057 					//printf("frame count: %d\n",framecount);
7058 					//printf("Load sprite '%s'...\n", value);
7059 					index = loadsprite(value, offset[0], offset[1],PIXEL_8);//don't use palette for the mask
7060 					maskindex = index;
7061 					break;
7062 				case CMD_MODEL_FLIPFRAME:
7063 					newanim->flipframe = GET_INT_ARG(1);
7064 					break;
7065 				case CMD_MODEL_FOLLOWANIM:
7066 					newanim->followanim = GET_INT_ARG(1);
7067 					if(newanim->followanim > max_follows) newanim->followanim = max_follows;
7068 					if(newanim->followanim < 0) newanim->followanim = 0;
7069 					break;
7070 				case CMD_MODEL_FOLLOWCOND:
7071 					newanim->followcond = GET_INT_ARG(1);
7072 					break;
7073 				case CMD_MODEL_COUNTERFRAME:
7074 					newanim->counterrange.framestart    = GET_INT_ARG(1);
7075 					newanim->counterrange.frameend	    = GET_INT_ARG(1);
7076 					newanim->counterrange.condition	    = GET_INT_ARG(2);
7077 					newanim->counterrange.damaged	    = GET_INT_ARG(3);
7078 					break;
7079 				case CMD_MODEL_COUNTERRANGE:
7080 					newanim->counterrange.framestart	= GET_INT_ARG(1);
7081 					newanim->counterrange.frameend	    = GET_INT_ARG(2);
7082 					newanim->counterrange.condition	    = GET_INT_ARG(3);
7083 					newanim->counterrange.damaged	    = GET_INT_ARG(4);
7084 					break;
7085 				case CMD_MODEL_WEAPONFRAME:
7086 					newanim->weaponframe    = malloc(2 * sizeof(newanim->weaponframe));
7087 					memset(newanim->weaponframe, 0, 2 * sizeof(newanim->weaponframe));
7088 					newanim->weaponframe[0] = GET_INT_ARG(1);
7089 					newanim->weaponframe[1] = GET_INT_ARG(2);
7090 					break;
7091 				case CMD_MODEL_QUAKEFRAME:
7092 					newanim->quakeframe.framestart  = GET_INT_ARG(1);
7093 					newanim->quakeframe.repeat      = GET_INT_ARG(2);
7094 					newanim->quakeframe.v           = GET_INT_ARG(3);
7095 					newanim->quakeframe.cnt         = 0;
7096 					break;
7097 				case CMD_MODEL_SUBENTITY: case CMD_MODEL_CUSTENTITY:
7098 					value = GET_ARG(1);
7099 					if(value[0]) newanim->subentity = get_cached_model_index(value);
7100 					break;
7101 				case CMD_MODEL_SPAWNFRAME:
7102 					newanim->spawnframe    = malloc(5 * sizeof(newanim->spawnframe));
7103 					memset(newanim->spawnframe, 0, 5 * sizeof(newanim->spawnframe));
7104 					newanim->spawnframe[0] = GET_FLOAT_ARG(1);
7105 					newanim->spawnframe[1] = GET_FLOAT_ARG(2);
7106 					newanim->spawnframe[2] = GET_FLOAT_ARG(3);
7107 					newanim->spawnframe[3] = GET_FLOAT_ARG(4);
7108 					newanim->spawnframe[4] = GET_FLOAT_ARG(5);
7109 					break;
7110 				case CMD_MODEL_SUMMONFRAME:
7111 					newanim->summonframe    = malloc(5 * sizeof(newanim->summonframe));
7112 					memset(newanim->summonframe, 0, 5 * sizeof(newanim->summonframe));
7113 					newanim->summonframe[0] = GET_FLOAT_ARG(1);
7114 					newanim->summonframe[1] = GET_FLOAT_ARG(2);
7115 					newanim->summonframe[2] = GET_FLOAT_ARG(3);
7116 					newanim->summonframe[3] = GET_FLOAT_ARG(4);
7117 					newanim->summonframe[4] = GET_FLOAT_ARG(5);
7118 					break;
7119 				case CMD_MODEL_UNSUMMONFRAME:
7120 					newanim->unsummonframe = GET_INT_ARG(1);
7121 					break;
7122 				case CMD_MODEL_AT_SCRIPT:
7123 					if(ani_id < 0)  {
7124 						shutdownmessage = "command '@script' must follow an animation!";
7125 						goto lCleanup;
7126 					}
7127 					if(!scriptbuf[0]){ // if empty, paste the main function text here
7128 						strcat(scriptbuf, pre_text);
7129 					}
7130 					scriptbuf[strlen(scriptbuf) - strlen(sur_text)] = 0; // cut last chars
7131 					if(script_id != ani_id){ // if expression 1
7132 						sprintf(namebuf, ifid_text, ani_id);
7133 						strcat(scriptbuf, namebuf);
7134 						script_id = ani_id;
7135 					}
7136 					scriptbuf[strlen(scriptbuf) - strlen(endifid_text)] = 0; // cut last chars
7137 					while(strncmp(buf+pos, "@script", 7)){
7138 						pos++;
7139 					}
7140 					pos += 7;
7141 					while(strncmp(buf+pos, "@end_script", 11)){
7142 						len = strlen(scriptbuf);
7143 						scriptbuf[len] = *(buf+pos);
7144 						scriptbuf[len+1] = 0;
7145 						pos++;
7146 					}
7147 					pos += 11;
7148 					strcat(scriptbuf, endifid_text); // put back last  chars
7149 					strcat(scriptbuf, sur_text); // put back last  chars
7150 					break;
7151 				case CMD_MODEL_AT_CMD:
7152 					//translate @cmd into script function call
7153 					if(ani_id < 0) {
7154 						shutdownmessage = "command '@cmd' must follow an animation!";
7155 						goto lCleanup;
7156 					}
7157 					if(!scriptbuf[0]){ // if empty, paste the main function text here
7158 						strcat(scriptbuf, pre_text);
7159 					}
7160 					scriptbuf[strlen(scriptbuf) - strlen(sur_text)] = 0; // cut last chars
7161 					if(script_id != ani_id){ // if expression 1
7162 						sprintf(namebuf, ifid_text, ani_id);
7163 						strcat(scriptbuf, namebuf);
7164 						script_id = ani_id;
7165 					}
7166 					j = 1;
7167 					value = GET_ARG(j);
7168 					scriptbuf[strlen(scriptbuf) - strlen(endifid_text)] = 0; // cut last chars
7169 					if(value && value[0]){
7170 						sprintf(namebuf, if_text, curframe);//only execute in current frame
7171 						strcat(scriptbuf, namebuf);
7172 						sprintf(namebuf, call_text, value);
7173 						strcat(scriptbuf, namebuf);
7174 						do{ //argument and comma
7175 							j++;
7176 							value = GET_ARG(j);
7177 							if(value && value[0]) {
7178 								if(j!=2) strcat(scriptbuf, comma_text);
7179 								strcat(scriptbuf, value);
7180 							}
7181 						}while(value && value[0]);
7182 					}
7183 					strcat(scriptbuf, endcall_text);
7184 					strcat(scriptbuf, endif_text); //end of if
7185 					strcat(scriptbuf, endifid_text); // put back last  chars
7186 					strcat(scriptbuf, sur_text); // put back last  chars
7187 					break;
7188 				default:
7189 					if(command && command[0])
7190 						printf("Command '%s' not understood in file '%s'!", command, filename);
7191 			}
7192 
7193 		}
7194 		// Go to next line
7195 		pos += getNewLineStart(buf + pos);
7196 	}
7197 
7198 
7199 	tempInt = 1;
7200 	if(scriptbuf[0]) {
7201 		//printf("\n%s\n", scriptbuf);
7202 		if(!Script_IsInitialized(newchar->scripts.animation_script))
7203 			Script_Init(newchar->scripts.animation_script, newchar->name, 0);
7204 		tempInt = Script_AppendText(newchar->scripts.animation_script, scriptbuf, filename);
7205 		//Interpreter_OutputPCode(newchar->scripts.animation_script.pinterpreter, "code");
7206 		writeToScriptLog("\n####animationscript function main#####\n# ");
7207 		writeToScriptLog(filename);
7208 		writeToScriptLog("\n########################################\n");
7209 		writeToScriptLog(scriptbuf);
7210 	}
7211 	if(!newchar->isSubclassed)
7212 		Script_Compile(newchar->scripts.animation_script);
7213 
7214 	if(!tempInt)// parse script failed
7215 	{
7216 		shutdownmessage = "Error parsing function main of animation script in file '%s'!";
7217 		goto lCleanup;
7218 	}
7219 
7220 	// We need a little more work to initialize the new A.I. types if they are not loaded from file
7221 	if(newchar->aiattack==-1) newchar->aiattack = 0;
7222 	if(newchar->aimove==-1) newchar->aimove = 0;
7223 	//if(!newchar->offscreenkill) newchar->offscreenkill = 1000;
7224 
7225 	if(newchar->risetime[0]==-1)
7226 	{
7227 		if(newchar->type==TYPE_PLAYER)
7228 		{
7229 			if(newchar->animation[ANI_RISEATTACK]) newchar->risetime[0] = GAME_SPEED/2;
7230 			else newchar->risetime[0]=GAME_SPEED;
7231 		}
7232 		else if(newchar->type==TYPE_ENEMY || newchar->type==TYPE_NPC)
7233 		{
7234 			newchar->risetime[0] = 0;
7235 		}
7236 	}
7237 
7238 	if(newchar->hostile<0) {// not been initialized, so initialize it
7239 		switch (newchar->type){
7240 		case TYPE_ENEMY:
7241 			newchar->hostile = TYPE_PLAYER ;
7242 			break;
7243 		case TYPE_PLAYER: // dont really needed, since you don't need A.I. control for players
7244 			newchar->hostile = TYPE_PLAYER | TYPE_ENEMY | TYPE_OBSTACLE;
7245 			break;
7246 		case TYPE_TRAP:
7247 			newchar->hostile  = TYPE_ENEMY | TYPE_PLAYER;
7248 		case TYPE_OBSTACLE:
7249 			newchar->hostile = 0;
7250 			break;
7251 		case TYPE_SHOT:  // only target enemies
7252 			newchar->hostile = TYPE_ENEMY ;
7253 			break;
7254 		case TYPE_NPC: // default npc behivior
7255 			newchar->hostile = TYPE_ENEMY ;
7256 			break;
7257 		}
7258 	}
7259 
7260 	if(newchar->candamage<0) {// not been initialized, so initialize it
7261 		switch (newchar->type){
7262 		case TYPE_ENEMY:
7263 			newchar->candamage = TYPE_PLAYER | TYPE_SHOT;
7264 			if(newchar->subtype == SUBTYPE_ARROW) newchar->candamage |= TYPE_OBSTACLE;
7265 			break;
7266 		case TYPE_PLAYER:
7267 			newchar->candamage = TYPE_PLAYER | TYPE_ENEMY | TYPE_OBSTACLE;
7268 			break;
7269 		case TYPE_TRAP:
7270 			newchar->candamage  = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE;
7271 		case TYPE_OBSTACLE:
7272 			newchar->candamage = TYPE_PLAYER | TYPE_ENEMY | TYPE_OBSTACLE;
7273 			break;
7274 		case TYPE_SHOT:
7275 			newchar->candamage = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE;
7276 			break;
7277 		case TYPE_NPC:
7278 			newchar->candamage = TYPE_ENEMY | TYPE_OBSTACLE;
7279 			break;
7280 		case TYPE_ITEM:
7281 			newchar->candamage = TYPE_PLAYER;
7282 			break;
7283 		}
7284 	}
7285 
7286 	if(newchar->projectilehit<0) {// not been initialized, so initialize it
7287 		switch (newchar->type){
7288 		case TYPE_ENEMY:
7289 			newchar->projectilehit = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE;
7290 			break;
7291 		case TYPE_PLAYER:
7292 			newchar->projectilehit = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE;
7293 			break;
7294 		case TYPE_TRAP: // hmm, don't really needed
7295 			newchar->projectilehit  = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE;
7296 		case TYPE_OBSTACLE: // hmm, don't really needed
7297 			newchar->projectilehit = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE;
7298 			break;
7299 		case TYPE_SHOT: // hmm, don't really needed
7300 			newchar->projectilehit = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE;
7301 			break;
7302 		case TYPE_NPC:
7303 			newchar->projectilehit = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE;
7304 			break;
7305 		}
7306 	}
7307 
7308 	if(newchar->jumpspeed < 0) newchar->jumpspeed = MAX(newchar->speed, 1);
7309 
7310 	if(blendfx_is_set==0)
7311 	{
7312 		if(newchar->alpha)
7313 		{
7314 			blendfx[newchar->alpha-1] = 1;
7315 		}
7316 		if(newchar->gfxshadow || newchar->shadow)
7317 		{
7318 			blendfx[BLEND_MULTIPLY] = 1;
7319 		}
7320 	}
7321 
7322 	// we need to convert 8bit colourmap into 24bit palette
7323 	if(pixelformat==PIXEL_x8)
7324 	{
7325 		convert_map_to_palette(newchar, mapflag);
7326 	}
7327 
7328 	printf("Loading '%s' from %s\n", newchar->name, filename);
7329 
7330 	lCleanup:
7331 
7332 	if(buf != NULL){
7333 		free(buf);
7334 		buf = NULL;
7335 	}
7336 	if(scriptbuf){
7337 		free(scriptbuf);
7338 		scriptbuf = NULL;
7339 	}
7340 
7341 	if(!shutdownmessage)
7342 		return newchar;
7343 
7344 	shutdown(1, "Fatal Error in load_cached_model, file: %s, line %d, message: %s\n", filename, line, shutdownmessage);
7345 	return NULL;
7346 }
7347 
7348 
7349 
is_set(s_model * model,int m)7350 int is_set(s_model * model, int m){    // New function to determine if a freespecial has been set
7351 	int i;
7352 
7353 	for(i = 0; i < model->specials_loaded; i++){
7354 		if(model->special[i][MAX_SPECIAL_INPUTS-2] == m){
7355 			return 1;
7356 		}
7357 	}
7358 
7359 	return 0;
7360 }
7361 
load_script_setting()7362 int load_script_setting()
7363 {
7364 	char * filename = "data/script.txt";
7365 	char *buf, *command;
7366 	ptrdiff_t pos = 0;
7367 	size_t size = 0;
7368 	ArgList arglist;
7369 	char argbuf[MAX_ARG_LEN+1] = "";
7370 
7371 	if(buffer_pakfile(filename, &buf, &size)!=1) return 0;
7372 
7373 	while(pos<size)
7374 	{
7375 		ParseArgs(&arglist,buf+pos,argbuf);
7376 		command = GET_ARG(0);
7377 		if(command && command[0])
7378 		{
7379 			if(stricmp(command, "maxscriptvars")==0) // each script can have a variable list that can be accessed by index
7380 			{
7381 				max_script_vars = GET_INT_ARG(1) ;
7382 				if(max_script_vars<0) max_script_vars = 0;
7383 			}
7384 			else if(stricmp(command, "maxentityvars")==0) // each entity can have a variable list that can be accessed by index
7385 			{
7386 				max_entity_vars = GET_INT_ARG(1) ;
7387 				if(max_entity_vars<0) max_entity_vars = 0;
7388 			}
7389 			else if(stricmp(command, "maxindexedvars")==0) // a global variable list that can be accessed by index
7390 			{
7391 				max_indexed_vars = GET_INT_ARG(1);
7392 				if(max_indexed_vars<0) max_indexed_vars = 0;
7393 			}
7394 			else if(stricmp(command, "maxglobalvars")==0) // for global_var_list, default to 2048
7395 			{
7396 				max_global_vars = GET_INT_ARG(1);
7397 				if(max_global_vars<0) max_global_vars = 0;
7398 			}
7399 			else if(stricmp(command, "keyscriptrate")==0) // Rate that keyscripts fire when holding a key.
7400 			{
7401 				keyscriptrate = GET_INT_ARG(1);
7402 			}
7403 			else if(stricmp(command, "alwaysupdate")==0) //execute update script whenever update() is called
7404 			{
7405 				alwaysupdate = GET_INT_ARG(1);
7406 			}
7407 		}
7408 		// Go to next line
7409 	pos += getNewLineStart(buf + pos);
7410 	}
7411 
7412 	if(buf != NULL)
7413 	{
7414 		free(buf);
7415 		buf = NULL;
7416 	}
7417 	return 1;
7418 }
7419 
7420 // Load / cache all models
load_models()7421 int load_models()
7422 {
7423 	char filename[128] = "data/models.txt";
7424 	int i;
7425 	char *buf;
7426 	size_t size;
7427 	ptrdiff_t pos;
7428 	char * command;
7429 	int line = 0;
7430 
7431 	char tmpBuff[128] = {""};
7432 	int maxanim = MAX_ANIS; // temporary counter
7433 
7434 	ArgList arglist;
7435 	char argbuf[MAX_ARG_LEN+1] = "";
7436 	modelstxtCommands cmd;
7437 	int modelLoadCount = 0;
7438 
7439 	free_modelcache();
7440 
7441 	if(isLoadingScreenTypeBg(loadingbg[0].set)) {
7442 		// New alternative background path for PSP
7443 		if(custBkgrds != NULL)
7444 		{
7445 			strcpy(tmpBuff,custBkgrds);
7446 			strncat(tmpBuff,"loading", 7);
7447 			load_background(tmpBuff, 0);
7448 		}
7449 		else load_background("data/bgs/loading", 0);
7450 		standard_palette(1);
7451 	}
7452 	if(isLoadingScreenTypeBar(loadingbg[0].set)) {
7453 		lifebar_colors();
7454 		init_colourtable();
7455 	}
7456 
7457 	update_loading(&loadingbg[0], -1, 1); // initialize the update screen
7458 
7459 	// reload default values
7460 	max_idles        = MAX_IDLES;
7461 	max_walks        = MAX_WALKS;
7462 	max_ups          = MAX_UPS;
7463 	max_downs        = MAX_DOWNS;
7464 	max_backwalks    = MAX_BACKWALKS;
7465 	max_attack_types = MAX_ATKS;
7466 	max_freespecials = MAX_SPECIALS;
7467 	max_follows      = MAX_FOLLOWS;
7468 	max_attacks      = MAX_ATTACKS;
7469 	max_animations   = MAX_ANIS;
7470 
7471 	// free old values
7472 	if(animspecials){free(animspecials); animspecials = NULL;}
7473 	if(animattacks){free(animattacks);  animattacks = NULL;}
7474 	if(animfollows){free(animfollows);  animfollows = NULL;}
7475 	if(animpains){free(animpains);    animpains = NULL;}
7476 	if(animfalls){free(animfalls);    animfalls = NULL;}
7477 	if(animrises){free(animrises);    animrises = NULL;}
7478 	if(animriseattacks){free(animriseattacks);    animriseattacks = NULL;}
7479 	if(animblkpains) {free(animblkpains); animblkpains = NULL;}
7480 	if(animdies){free(animdies);     animdies = NULL;}
7481 	if(animwalks){free(animwalks);     animwalks = NULL;}
7482 	if(animbackwalks){free(animbackwalks);     animbackwalks = NULL;}
7483 	if(animidles){free(animidles);     animidles = NULL;}
7484 	if(animups){free(animups);     animups = NULL;}
7485 	if(animdowns){free(animdowns);     animdowns = NULL;}
7486 
7487 	if(custModels != NULL)
7488 	{
7489 		strcpy(filename, "data/");
7490 		strcat(filename, custModels);
7491 	}
7492 
7493 	// Read file
7494 	if(buffer_pakfile(filename, &buf, &size)!=1) shutdown(1, "Error loading model list from %s", filename);
7495 
7496 	pos = 0;
7497 	while(pos<size) // peek global settings
7498 	{
7499 		line++;
7500 		ParseArgs(&arglist,buf+pos,argbuf);
7501 		command = GET_ARG(0);
7502 		cmd = getModelstxtCommand(modelstxtcmdlist,command);
7503 		switch(cmd) {
7504 			case CMD_MODELSTXT_MAXIDLES:
7505 				// max idle stances
7506 				max_idles = GET_INT_ARG(1);
7507 				if(max_idles < MAX_IDLES) max_idles = MAX_IDLES;
7508 				break;
7509 			case CMD_MODELSTXT_MAXWALKS:
7510 				max_walks = GET_INT_ARG(1);
7511 				if(max_walks < MAX_WALKS) max_walks = MAX_WALKS;
7512 				break;
7513 			case CMD_MODELSTXT_MAXBACKWALKS:
7514 				// max backward walks
7515 				max_backwalks = GET_INT_ARG(1);
7516 				if(max_backwalks < MAX_BACKWALKS) max_backwalks = MAX_BACKWALKS;
7517 				break;
7518 			case CMD_MODELSTXT_MAXUPS:
7519 				// max up walks
7520 				max_ups = GET_INT_ARG(1);
7521 				if(max_ups < MAX_UPS) max_ups = MAX_UPS;
7522 				break;
7523 			case CMD_MODELSTXT_MAXDOWNS:
7524 				// max down walks
7525 				max_downs = GET_INT_ARG(1);
7526 				if(max_downs < MAX_DOWNS) max_downs = MAX_DOWNS;
7527 				break;
7528 			case CMD_MODELSTXT_MAXATTACKTYPES:
7529 				// max attacktype/pain/fall/die
7530 				max_attack_types = GET_INT_ARG(1) + STA_ATKS;
7531 				if(max_attack_types < MAX_ATKS) max_attack_types = MAX_ATKS;
7532 				break;
7533 			case CMD_MODELSTXT_MAXFOLLOWS:
7534 				// max follow-ups
7535 				max_follows = GET_INT_ARG(1);
7536 				if(max_follows<MAX_FOLLOWS) max_follows = MAX_FOLLOWS;
7537 				break;
7538 			case CMD_MODELSTXT_MAXFREESPECIALS:
7539 				// max freespecials
7540 				max_freespecials = GET_INT_ARG(1);
7541 				if(max_freespecials<MAX_SPECIALS) max_freespecials = MAX_SPECIALS;
7542 				break;
7543 			case CMD_MODELSTXT_MAXATTACKS:
7544 				max_attacks = GET_INT_ARG(1);
7545 				if(max_attacks<MAX_ATTACKS) max_attacks = MAX_ATTACKS;
7546 				break;
7547 			case CMD_MODELSTXT_COMBODELAY:
7548 				combodelay = GET_INT_ARG(1);
7549 				break;
7550 			case CMD_MODELSTXT_MUSIC:
7551 				music(GET_ARG(1), 1, atol(GET_ARG(2)));
7552 				break;
7553 			case CMD_MODELSTXT_LOAD:
7554 				// Add path to cache list
7555 				modelLoadCount++;
7556 				cache_model(GET_ARG(1), GET_ARG(2), 1);
7557 				break;
7558 			case CMD_MODELSTXT_COLOURSELECT:
7559 				// 6-2-2005 if string for colourselect found
7560 				colourselect =  GET_INT_ARG(1);          //  6-2-2005
7561 				break;
7562 			case CMD_MODELSTXT_SPDIRECTION:
7563 				// Select Player Direction for select player screen
7564 				spdirection[0] =  GET_INT_ARG(1);
7565 				spdirection[1] =  GET_INT_ARG(2);
7566 				spdirection[2] =  GET_INT_ARG(3);
7567 				spdirection[3] =  GET_INT_ARG(4);
7568 				break;
7569 			case CMD_MODELSTXT_AUTOLAND:
7570 				// New flag to determine if a player auto lands when thrown by another player (2 completely disables the ability to land)
7571 				autoland = GET_INT_ARG(1);
7572 				break;
7573 			case CMD_MODELSTXT_NOLOST:
7574 				// this is use for dont lost your weapon if you grab a enemy flag it to 1 to no drop by tails
7575 				nolost = GET_INT_ARG(1);
7576 				break;
7577 			case CMD_MODELSTXT_AJSPECIAL:
7578 				// Flag to determine if a + j executes special
7579 				ajspecial = GET_INT_ARG(1);
7580 				break;
7581 			case CMD_MODELSTXT_NOCOST:
7582 				// Nocost set in models.txt
7583 				nocost = GET_INT_ARG(1);
7584 				break;
7585 			case CMD_MODELSTXT_NOCHEATS:
7586 				//disable cheat option in menu
7587 				forcecheatsoff =  GET_INT_ARG(1);
7588 				break;
7589 			case CMD_MODELSTXT_NODROPEN:
7590 				nodropen = 1;
7591 				break;
7592 			case CMD_MODELSTXT_NODROPSPAWN:
7593 				nodropspawn = 1;
7594 				break;
7595 			case CMD_MODELSTXT_KNOW:
7596 				// Just add path to cache list
7597 				cache_model(GET_ARG(1), GET_ARG(2), 0);
7598 				break;
7599 			case CMD_MODELSTXT_NOAIRCANCEL:
7600 				noaircancel = GET_INT_ARG(1);
7601 				break;
7602 			case CMD_MODELSTXT_NOMAXRUSHRESET:
7603 				nomaxrushreset[4] = GET_INT_ARG(1);
7604 				break;
7605 			case CMD_MODELSTXT_MPBLOCK:
7606 				// Take from MP first?
7607 				mpblock = GET_INT_ARG(1);
7608 				break;
7609 			case CMD_MODELSTXT_BLOCKRATIO:
7610 				// Nullify or reduce damage?
7611 				blockratio = GET_INT_ARG(1);
7612 				break;
7613 			case CMD_MODELSTXT_NOCHIPDEATH:
7614 				nochipdeath = GET_INT_ARG(1);
7615 				break;
7616 			case CMD_MODELSTXT_LIFESCORE:
7617 				lifescore =  GET_INT_ARG(1);
7618 				break;
7619 			case CMD_MODELSTXT_CREDSCORE:
7620 				// Number of points needed to earn a 1-up
7621 				credscore =  GET_INT_ARG(1);
7622 				break;
7623 			case CMD_MODELSTXT_VERSUSDAMAGE:
7624 				// Number of points needed to earn a credit
7625 				versusdamage =  GET_INT_ARG(1);
7626 				if(versusdamage == 0 || versusdamage == 1) savedata.mode = versusdamage^1;
7627 				break;
7628 			default:
7629 				printf("command %s not understood in %s, line %d\n", command, filename, line);
7630 		}
7631 
7632 		// Go to next line
7633 		pos += getNewLineStart(buf + pos);
7634 	}
7635 	// calculate max animations
7636 	max_animations += (max_attack_types - MAX_ATKS) * 6 +// multply by 5, for fall/die/pain/rise/blockpain/riseattack
7637 			(max_follows - MAX_FOLLOWS) +
7638 			(max_freespecials - MAX_SPECIALS) +
7639 			(max_attacks - MAX_ATTACKS) +
7640 			(max_idles - MAX_IDLES)+
7641 			(max_walks - MAX_WALKS)+
7642 			(max_ups - MAX_UPS)+
7643 			(max_downs - MAX_DOWNS)+
7644 			(max_backwalks - MAX_BACKWALKS);
7645 
7646 	// alloc indexed animation ids
7647 	animdowns       = (int*)malloc(sizeof(int)*max_downs);
7648 	animups         = (int*)malloc(sizeof(int)*max_ups);
7649 	animbackwalks   = (int*)malloc(sizeof(int)*max_backwalks);
7650 	animwalks       = (int*)malloc(sizeof(int)*max_walks);
7651 	animidles       = (int*)malloc(sizeof(int)*max_idles);
7652 	animpains       = (int*)malloc(sizeof(int)*max_attack_types);
7653 	animdies        = (int*)malloc(sizeof(int)*max_attack_types);
7654 	animfalls       = (int*)malloc(sizeof(int)*max_attack_types);
7655 	animrises       = (int*)malloc(sizeof(int)*max_attack_types);
7656 	animriseattacks = (int*)malloc(sizeof(int)*max_attack_types);
7657 	animblkpains    = (int*)malloc(sizeof(int)*max_attack_types);
7658 	animattacks     = (int*)malloc(sizeof(int)*max_attacks);
7659 	animfollows     = (int*)malloc(sizeof(int)*max_follows);
7660 	animspecials    = (int*)malloc(sizeof(int)*max_freespecials);
7661 
7662 	// copy default values and new animation ids
7663 	memcpy(animdowns, downs, sizeof(int)*MAX_DOWNS);
7664 	for(i=MAX_DOWNS; i<max_downs; i++) animdowns[i] = maxanim++;
7665 	memcpy(animups, ups, sizeof(int)*MAX_UPS);
7666 	for(i=MAX_UPS; i<max_ups; i++) animups[i] = maxanim++;
7667 	memcpy(animbackwalks, backwalks, sizeof(int)*MAX_BACKWALKS);
7668 	for(i=MAX_BACKWALKS; i<max_backwalks; i++) animbackwalks[i] = maxanim++;
7669 	memcpy(animwalks, walks, sizeof(int)*MAX_WALKS);
7670 	for(i=MAX_WALKS; i<max_walks; i++) animwalks[i] = maxanim++;
7671 	memcpy(animidles, idles, sizeof(int)*MAX_IDLES);
7672 	for(i=MAX_IDLES; i<max_idles; i++) animidles[i] = maxanim++;
7673 	memcpy(animspecials, freespecials,   sizeof(int)*MAX_SPECIALS);
7674 	for(i=MAX_SPECIALS; i<max_freespecials; i++) animspecials[i] = maxanim++;
7675 	memcpy(animattacks,  normal_attacks, sizeof(int)*MAX_ATTACKS);
7676 	for(i=MAX_ATTACKS; i<max_attacks; i++) animattacks[i] = maxanim++;
7677 	memcpy(animfollows,  follows,        sizeof(int)*MAX_FOLLOWS);
7678 	for(i=MAX_FOLLOWS; i<max_follows; i++) animfollows[i] = maxanim++;
7679 	memcpy(animpains,    pains,          sizeof(int)*MAX_ATKS);
7680 	for(i=MAX_ATKS; i<max_attack_types; i++) animpains[i] = maxanim++;
7681 	memcpy(animfalls,    falls,          sizeof(int)*MAX_ATKS);
7682 	for(i=MAX_ATKS; i<max_attack_types; i++) animfalls[i] = maxanim++;
7683 	memcpy(animrises,    rises,          sizeof(int)*MAX_ATKS);
7684 	for(i=MAX_ATKS; i<max_attack_types; i++) animrises[i] = maxanim++;
7685 	memcpy(animriseattacks,    riseattacks,          sizeof(int)*MAX_ATKS);
7686 	for(i=MAX_ATKS; i<max_attack_types; i++) animriseattacks[i] = maxanim++;
7687 	memcpy(animblkpains,    blkpains,    sizeof(int)*MAX_ATKS);
7688 	for(i=MAX_ATKS; i<max_attack_types; i++) animblkpains[i] = maxanim++;
7689 	memcpy(animdies,     deaths,         sizeof(int)*MAX_ATKS);
7690 	for(i=MAX_ATKS; i<max_attack_types; i++) animdies[i] = maxanim++;
7691 
7692 	// Defer load_cached_model, so you can define models after their nested model.
7693 	printf("\n");
7694 
7695 	for(i=0,pos=0; i<models_cached; i++) {
7696 		//printf("Checking '%s' '%s'\n", model_cache[i].name, model_cache[i].path);
7697 		if(model_cache[i].loadflag) {
7698 			load_cached_model(model_cache[i].name, "models.txt", 0);
7699 			update_loading(&loadingbg[0], ++pos, modelLoadCount);
7700 		}
7701 	}
7702 	printf("\nLoading models...............\tDone!\n");
7703 
7704 
7705 	if(buf)
7706 		free(buf);
7707 
7708 	return 1;
7709 }
7710 
7711 
7712 
7713 
unload_levelorder()7714 void unload_levelorder(){
7715 	int i, j;
7716 	for(j=0; j<MAX_DIFFICULTIES; j++){
7717 		for(i=0; i<MAX_LEVELS; i++){
7718 			if(levelorder[j][i] != NULL){
7719 				free(levelorder[j][i]->branchname);
7720 				levelorder[j][i]->branchname = NULL;
7721 				free(levelorder[j][i]->filename);
7722 				levelorder[j][i]->filename = NULL;
7723 				free(levelorder[j][i]);
7724 				levelorder[j][i] = NULL;
7725 			}
7726 		}
7727 		num_levels[j] = 0;
7728 		strcpy(set_names[j], "");
7729 	}
7730 	num_difficulties = 0;
7731 
7732 	if(skipselect)
7733 	{
7734 		for(i=0; i<MAX_DIFFICULTIES; i++)
7735 		{
7736 			for(j=0; j<MAX_PLAYERS; j++)
7737 			{
7738 				if((*skipselect)[i][j])
7739 				{
7740 					free((*skipselect)[i][j]);
7741 					(*skipselect)[i][j] = NULL;
7742 				}
7743 			}
7744 		}
7745 		free(skipselect);
7746 		skipselect = NULL;
7747 	}
7748 }
7749 
7750 
7751 
7752 // Add a level to the level order
add_level(char * filename,int diff)7753 void add_level(char *filename, int diff){
7754 	int len, Zs[3] = {0,0,0};
7755 
7756 	if(z_coords[0] > 0) Zs[0] = z_coords[0];
7757 	else Zs[0] = PLAYER_MIN_Z;
7758 
7759 	if(z_coords[1] > 0) Zs[1] = z_coords[1];
7760 	else Zs[1] = PLAYER_MAX_Z;
7761 
7762 	if(z_coords[2] > 0) Zs[2] = z_coords[2];
7763 	else Zs[2] = PLAYER_MIN_Z;
7764 
7765 	if(diff > MAX_DIFFICULTIES) return;
7766 	if(num_levels[diff] >= MAX_LEVELS) shutdown(1, "Too many entries in level order (max. %i)!", MAX_LEVELS);
7767 
7768 	levelorder[diff][num_levels[diff]] = malloc(sizeof(s_level_entry));
7769 	memset(levelorder[diff][num_levels[diff]], 0, sizeof(s_level_entry));
7770 
7771 	len = strlen(branch_name);
7772 	levelorder[diff][num_levels[diff]]->branchname = malloc(len + 1);
7773 	strcpy(levelorder[diff][num_levels[diff]]->branchname, branch_name);
7774 	levelorder[diff][num_levels[diff]]->branchname[len] = 0;
7775 
7776 	len = strlen(filename);
7777 	levelorder[diff][num_levels[diff]]->filename = malloc(len + 1);
7778 	strcpy(levelorder[diff][num_levels[diff]]->filename, filename);
7779 	levelorder[diff][num_levels[diff]]->filename[len] = 0;
7780 
7781 	levelorder[diff][num_levels[diff]]->z_coords[0] = Zs[0];
7782 	levelorder[diff][num_levels[diff]]->z_coords[1] = Zs[1];
7783 	levelorder[diff][num_levels[diff]]->z_coords[2] = Zs[2];
7784 	num_levels[diff]++;
7785 }
7786 
7787 
7788 
7789 // Add a scene to the level order
add_scene(char * filename,int diff)7790 void add_scene(char *filename, int diff){
7791 	int len;
7792 	if(diff > MAX_DIFFICULTIES) return;
7793 	if(num_levels[diff] >= MAX_LEVELS) shutdown(1, "Too many entries in level order (max. %i)!", MAX_LEVELS);
7794 
7795 	levelorder[diff][num_levels[diff]] = (s_level_entry*)malloc(sizeof(s_level_entry));
7796 	memset(levelorder[diff][num_levels[diff]], 0, sizeof(s_level_entry));
7797 
7798 	len = strlen(branch_name);
7799 	levelorder[diff][num_levels[diff]]->branchname = malloc(len + 1);
7800 	strcpy(levelorder[diff][num_levels[diff]]->branchname, branch_name);
7801 	levelorder[diff][num_levels[diff]]->branchname[len] = 0;
7802 
7803 	len = strlen(filename);
7804 	levelorder[diff][num_levels[diff]]->filename = malloc(len + 1);
7805 	strcpy(levelorder[diff][num_levels[diff]]->filename, filename);
7806 	levelorder[diff][num_levels[diff]]->filename[len] = 0;
7807 
7808 	levelorder[diff][num_levels[diff]]->type = cut_scene;
7809 	num_levels[diff]++;
7810 }
7811 
7812 // Add a select screen file to the level order
add_select(char * filename,int diff)7813 void add_select(char *filename, int diff){
7814 	int len;
7815 	if(diff > MAX_DIFFICULTIES) return;
7816 	if(num_levels[diff] >= MAX_LEVELS) shutdown(1, "Too many entries in level order (max. %i)!", MAX_LEVELS);
7817 
7818 	levelorder[diff][num_levels[diff]] = (s_level_entry*)malloc(sizeof(s_level_entry));
7819 	memset(levelorder[diff][num_levels[diff]], 0, sizeof(s_level_entry));
7820 
7821 	len = strlen(branch_name);
7822 	levelorder[diff][num_levels[diff]]->branchname = malloc(len + 1);
7823 	strcpy(levelorder[diff][num_levels[diff]]->branchname, branch_name);
7824 	levelorder[diff][num_levels[diff]]->branchname[len] = 0;
7825 
7826 	len = strlen(filename);
7827 	levelorder[diff][num_levels[diff]]->filename = malloc(len + 1);
7828 	strcpy(levelorder[diff][num_levels[diff]]->filename, filename);
7829 	levelorder[diff][num_levels[diff]]->filename[len] = 0;
7830 
7831 	levelorder[diff][num_levels[diff]]->type = select_screen;
7832 	num_levels[diff]++;
7833 }
7834 
_readbarstatus(char * buf,s_barstatus * pstatus)7835 static void _readbarstatus(char* buf, s_barstatus* pstatus)
7836 {
7837 	char* value;
7838 	ArgList arglist;
7839 	char argbuf[MAX_ARG_LEN+1] = "";
7840 
7841 	ParseArgs(&arglist,buf,argbuf);
7842 	if((value=GET_ARG(1))[0]) pstatus->sizex       = atoi(value);
7843 	else return;
7844 	if((value=GET_ARG(2))[0]) pstatus->sizey       = atoi(value);
7845 	else return;
7846 	if((value=GET_ARG(3))[0]) pstatus->noborder    = atoi(value);
7847 	else return;
7848 	if((value=GET_ARG(4))[0]) pstatus->type        = atoi(value);
7849 	else return;
7850 	if((value=GET_ARG(5))[0]) pstatus->orientation = atoi(value);
7851 	else return;
7852 	if((value=GET_ARG(6))[0]) pstatus->borderlayer = atoi(value);
7853 	else return;
7854 	if((value=GET_ARG(7))[0]) pstatus->shadowlayer = atoi(value);
7855 	else return;
7856 	if((value=GET_ARG(8))[0]) pstatus->barlayer    = atoi(value);
7857 	else return;
7858 	if((value=GET_ARG(9))[0]) pstatus->backlayer   = atoi(value);
7859 	else return;
7860 }
7861 
7862 // Load list of levels
load_levelorder()7863 void load_levelorder()
7864 {
7865 	static const char* defaulterr = "Error in level order: a set must be specified.";
7866 #define CHKDEF if(current_set<0) { errormessage = (char*) defaulterr; goto lCleanup; }
7867 	char filename[128] = "";
7868 	int i=0,j=0;
7869 	char *buf;
7870 	size_t size;
7871 	int pos;
7872 	int current_set;
7873 	char * command;
7874 	char* arg;
7875 	char* errormessage = NULL;
7876 	char value[128]   = {""};
7877 	int plifeUsed[2]  = {0,0};
7878 	int elifeUsed[2]  = {0,0};
7879 	int piconUsed[2]  = {0,0};
7880 	int piconwUsed[2] = {0,0};
7881 	int eiconUsed[4]  = {0,0,0,0};
7882 	int pmpUsed[4]    = {0,0,0,0};
7883 	int plifeXused[4] = {0,0,0,0};        // 4-7-2006 New custimizable variable for players 'x'
7884 	int plifeNused[4] = {0,0,0,0};        // 4-7-2006 New custimizable variable for players 'lives'
7885 	int enameused[4]  = {0,0,0,0};        // 4-7-2006 New custimizable variable for enemy names
7886 	int pnameJused[4] = {0,0,0,0};        // 1-8-2006 New custimizable variable for players name Select Hero
7887 	int pscoreUsed[4] = {0,0,0,0};        // 1-8-2006 New custimizable variable for players name Select Hero
7888 
7889 	ArgList arglist;
7890 	char argbuf[MAX_ARG_LEN+1] = "";
7891 	levelOrderCommands cmd;
7892 	int line = 0;
7893 
7894 	unload_levelorder();
7895 
7896 	if(custLevels != NULL)
7897 	{
7898 		strcpy(filename,"data/");
7899 		strcat(filename,custLevels);
7900 	}
7901 	else strcpy(filename,"data/levels.txt");
7902 
7903 	// Read file
7904 
7905 	if(buffer_pakfile(filename, &buf, &size)!=1) shutdown(1, "Error loading level list from %s", filename);
7906 
7907 	// Now interpret the contents of buf line by line
7908 	pos = 0;
7909 	current_set = -1;
7910 
7911 	// Custom lifebar/timebox/icon positioning and size
7912 	picon[0][0] = piconw[0][0] = picon[2][0] = piconw[2][0] = eicon[0][0] = eicon[2][0] = 2;
7913 	picon[1][0] = piconw[1][0] = picon[3][0] = piconw[3][0] = eicon[1][0] = eicon[3][0] = 2 + P2_STATS_DIST;
7914 	picon[0][1] = piconw[0][1] = picon[1][1] = piconw[1][1] = 2;
7915 	picon[2][1] = piconw[2][1] = picon[3][1] = piconw[3][1] = 202;
7916 	plife[0][0] = pmp[0][0] = plife[2][0] = pmp[2][0] = elife[0][0] = elife[2][0] = 20;
7917 	plife[1][0] = pmp[1][0] = plife[3][0] = pmp[3][0] = elife[1][0] = elife[3][0] = 20 + P2_STATS_DIST;
7918 	plife[0][1] = plife[1][1] = 10;
7919 	plife[2][1] = plife[3][1] = 210;
7920 	pmp[0][1] = pmp[1][1] = 18;
7921 	pmp[2][1] = pmp[3][1] = 218;
7922 
7923 	memset(psmenu, 0, sizeof(int)*4*4);
7924 
7925 	eicon[0][1] = eicon[1][1] = 19;
7926 	eicon[2][1] = eicon[3][1] = 220;
7927 	elife[0][1] = elife[1][1] = 27;
7928 	elife[2][1] = elife[3][1] = 227;
7929 
7930 	timeloc[0] = 149;
7931 	timeloc[1] = 4;
7932 	timeloc[2] = 21;
7933 	timeloc[3] = 20;
7934 	timeloc[4] = 0;
7935 
7936 	lbarstatus.sizex  = mpbarstatus.sizex = 100;
7937 	lbarstatus.sizey  = 5;
7938 	mpbarstatus.sizey = 3;
7939 	lbarstatus.noborder = mpbarstatus.noborder = 0;
7940 
7941 	// Show Complete Default Values
7942 	scomplete[0] = 75;
7943 	scomplete[1] = 60;
7944 	scomplete[2] = 0;
7945 	scomplete[3] = 0;
7946 	scomplete[4] = 0;
7947 	scomplete[5] = 0;
7948 
7949 	// Show Complete Y Values
7950 	cbonus[0] = lbonus[0] = rbonus[0] = tscore[0] = 10;
7951 	cbonus[1] = cbonus[3] = cbonus[5] = cbonus[7] = cbonus[9] = 100;
7952 	lbonus[1] = lbonus[3] = lbonus[5] = lbonus[7] = lbonus[9] = 120;
7953 	rbonus[1] = rbonus[3] = rbonus[5] = rbonus[7] = rbonus[9] = 140;
7954 	tscore[1] = tscore[3] = tscore[5] = tscore[7] = tscore[9] = 160;
7955 
7956 	// Show Complete X Values
7957 	cbonus[2] = lbonus[2] = rbonus[2] = tscore[2] = 100;
7958 	cbonus[4] = lbonus[4] = rbonus[4] = tscore[4] = 155;
7959 	cbonus[6] = lbonus[6] = rbonus[6] = tscore[6] = 210;
7960 	cbonus[8] = lbonus[8] = rbonus[8] = tscore[8] = 265;
7961 
7962 
7963 	while(pos<size){
7964 		line++;
7965 		ParseArgs(&arglist,buf+pos,argbuf);
7966 		command = GET_ARG(0);
7967 		cmd = getLevelOrderCommand(levelordercmdlist, command);
7968 		switch(cmd) {
7969 			case CMD_LEVELORDER_BLENDFX:
7970 				for(i=0; i<MAX_BLENDINGS; i++)
7971 				{
7972 					if(GET_INT_ARG(i+1)) blendfx[i] = 1;
7973 					else blendfx[i] = 0;
7974 				}
7975 				blendfx_is_set = 1;
7976 				break;
7977 			case CMD_LEVELORDER_SET:
7978 				if(num_difficulties>=MAX_DIFFICULTIES) {
7979 					errormessage = "Too many sets of levels (check MAX_DIFFICULTIES)!";
7980 					goto lCleanup;
7981 				}
7982 				++num_difficulties;
7983 				++current_set;
7984 				strncpy(set_names[current_set], GET_ARG(1), MAX_NAME_LEN);
7985 				ifcomplete[current_set] = 0;
7986 				cansave_flag[current_set] = 1; // default to 1, so the level can be saved
7987 				branch_name[0] = 0;
7988 				break;
7989 			case CMD_LEVELORDER_IFCOMPLETE:
7990 				CHKDEF;
7991 				ifcomplete[current_set] = GET_INT_ARG(1);
7992 				break;
7993 			case CMD_LEVELORDER_SKIPSELECT:
7994 				CHKDEF;
7995 				if(!skipselect) {
7996 					skipselect = malloc(sizeof(*skipselect));
7997 					memset(skipselect, 0, sizeof(*skipselect));
7998 				}
7999 
8000 				for(i=0; i<4;i++) {
8001 					if((arg=GET_ARG(i+1))[0]) {
8002 						if(!(*skipselect)[current_set][i])
8003 							(*skipselect)[current_set][i] = malloc(MAX_NAME_LEN+1);
8004 						strncpy((*skipselect)[current_set][i], arg, MAX_NAME_LEN);
8005 					}
8006 				}
8007 				break;
8008 			case CMD_LEVELORDER_FILE:
8009 				CHKDEF;
8010 				strncpy(value, GET_ARG(1), 127);
8011 				add_level(value, current_set);
8012 				break;
8013 			case CMD_LEVELORDER_SCENE:
8014 				CHKDEF;
8015 				strncpy(value, GET_ARG(1), 127);
8016 				add_scene(value, current_set);
8017 				break;
8018 			case CMD_LEVELORDER_SELECT:
8019 				CHKDEF;
8020 				strncpy(value, GET_ARG(1), 127);
8021 				add_select(value, current_set);
8022 				break;
8023 			case CMD_LEVELORDER_NEXT:
8024 				CHKDEF;
8025 				// Set 'gonext' flag of last loaded level
8026 				if(num_levels[current_set]<1) {
8027 					errormessage = "Error in level order (next before file)!";
8028 					goto lCleanup;
8029 				}
8030 				levelorder[current_set][num_levels[current_set]-1]->gonext = 1;
8031 				break;
8032 			case CMD_LEVELORDER_END:
8033 				CHKDEF;
8034 				// Set endgame flag of last loaded level
8035 				if(num_levels[current_set]<1) {
8036 					errormessage = "Error in level order (next before file)!";
8037 					goto lCleanup;
8038 				}
8039 				levelorder[current_set][num_levels[current_set]-1]->gonext = 2;
8040 				break;
8041 			case CMD_LEVELORDER_LIVES:
8042 				// 7-1-2005  credits/lives/singleplayer start here
8043 				// used to read the new # of lives/credits from the levels.txt
8044 				CHKDEF;
8045 				difflives[current_set] = GET_INT_ARG(1);
8046 				break;
8047 			case CMD_LEVELORDER_DISABLEHOF:
8048 				CHKDEF;
8049 				noshowhof[current_set] = GET_INT_ARG(1);
8050 				break;
8051 			case CMD_LEVELORDER_CANSAVE:
8052 				// 07-12-31
8053 				// 0 this set can't be saved
8054 				// 1 save level only
8055 				// 2 save player info and level, can't choose player in select menu
8056 				CHKDEF;
8057 				cansave_flag[current_set] = GET_INT_ARG(1);
8058 				break;
8059 			case CMD_LEVELORDER_Z:
8060 				//    2-10-05  adjust the walkable coordinates
8061 				CHKDEF;
8062 				z_coords[0] = GET_INT_ARG(1);
8063 				z_coords[1] = GET_INT_ARG(2);
8064 				z_coords[2] = GET_INT_ARG(3);
8065 				break;
8066 			case CMD_LEVELORDER_BRANCH:
8067 				//    2007-2-22 level branch name
8068 				CHKDEF;
8069 				strncpy(branch_name, GET_ARG(1), MAX_NAME_LEN);
8070 				break;
8071 			case CMD_LEVELORDER_P1LIFE: case CMD_LEVELORDER_P2LIFE: case CMD_LEVELORDER_P3LIFE: case CMD_LEVELORDER_P4LIFE:
8072 				switch(cmd) {
8073 					case CMD_LEVELORDER_P1LIFE: i = 0; break;
8074 					case CMD_LEVELORDER_P2LIFE: i = 1; break;
8075 					case CMD_LEVELORDER_P3LIFE: i = 2; plifeUsed[0] = 1; break;
8076 					case CMD_LEVELORDER_P4LIFE: i = 3; plifeUsed[1] = 1; break;
8077 					default: assert(0);
8078 				}
8079 				if((arg=GET_ARG(1))[0]) plife[i][0] = atoi(arg);
8080 				if((arg=GET_ARG(2))[0]) plife[i][1] = atoi(arg);
8081 				break;
8082 			case CMD_LEVELORDER_P1MP: case CMD_LEVELORDER_P2MP: case CMD_LEVELORDER_P3MP: case CMD_LEVELORDER_P4MP:
8083 				switch(cmd) {
8084 					case CMD_LEVELORDER_P1MP: i = 0; break;
8085 					case CMD_LEVELORDER_P2MP: i = 1; break;
8086 					case CMD_LEVELORDER_P3MP: i = 2; break;
8087 					case CMD_LEVELORDER_P4MP: i = 3; break;
8088 					default: assert(0);
8089 				}
8090 				if((arg=GET_ARG(1))[0]) pmp[i][0] = atoi(arg);
8091 				if((arg=GET_ARG(2))[0]) pmp[i][1] = atoi(arg);
8092 				pmpUsed[i] = 1;
8093 				break;
8094 			case CMD_LEVELORDER_P1LIFEX: case CMD_LEVELORDER_P2LIFEX: case CMD_LEVELORDER_P3LIFEX: case CMD_LEVELORDER_P4LIFEX:
8095 				switch(cmd) {
8096 					case CMD_LEVELORDER_P1LIFEX: j = 0; break;
8097 					case CMD_LEVELORDER_P2LIFEX: j = 1; break;
8098 					case CMD_LEVELORDER_P3LIFEX: j = 2; break;
8099 					case CMD_LEVELORDER_P4LIFEX: j = 3; break;
8100 					default: assert(0);
8101 				}
8102 				for(i=0; i<3; i++)
8103 					if((arg=GET_ARG(i+1))[0]) plifeX[j][i] = atoi(arg);
8104 				plifeXused[j] = 1;
8105 				break;
8106 			case CMD_LEVELORDER_P1LIFEN: case CMD_LEVELORDER_P2LIFEN: case CMD_LEVELORDER_P3LIFEN: case CMD_LEVELORDER_P4LIFEN:
8107 				switch(cmd) {
8108 					case CMD_LEVELORDER_P1LIFEN: j = 0; break;
8109 					case CMD_LEVELORDER_P2LIFEN: j = 1; break;
8110 					case CMD_LEVELORDER_P3LIFEN: j = 2; break;
8111 					case CMD_LEVELORDER_P4LIFEN: j = 3; break;
8112 					default: assert(0);
8113 				}
8114 				for(i=0; i<3; i++)
8115 					if((arg=GET_ARG(i+1))[0]) plifeN[j][i] = atoi(arg);
8116 				plifeNused[j] = 1;
8117 				break;
8118 			case CMD_LEVELORDER_E1LIFE: case CMD_LEVELORDER_E2LIFE: case CMD_LEVELORDER_E3LIFE: case CMD_LEVELORDER_E4LIFE:
8119 				switch(cmd) {
8120 					case CMD_LEVELORDER_E1LIFE: i = 0; break;
8121 					case CMD_LEVELORDER_E2LIFE: i = 1; break;
8122 					case CMD_LEVELORDER_E3LIFE: i = 2; elifeUsed[0] = 1; break;
8123 					case CMD_LEVELORDER_E4LIFE: i = 3; elifeUsed[1] = 1; break;
8124 					default: assert(0);
8125 				}
8126 				if((arg=GET_ARG(1))[0]) elife[i][0] = atoi(arg);
8127 				if((arg=GET_ARG(2))[0]) elife[i][1] = atoi(arg);
8128 				break;
8129 			case CMD_LEVELORDER_P1ICON: case CMD_LEVELORDER_P2ICON: case CMD_LEVELORDER_P3ICON: case CMD_LEVELORDER_P4ICON:
8130 				switch(cmd) {
8131 					case CMD_LEVELORDER_P1ICON: i = 0; break;
8132 					case CMD_LEVELORDER_P2ICON: i = 1; break;
8133 					case CMD_LEVELORDER_P3ICON: i = 2; piconUsed[0] = 1; break;
8134 					case CMD_LEVELORDER_P4ICON: i = 3; piconUsed[1] = 1; break;
8135 					default: assert(0);
8136 				}
8137 				if((arg=GET_ARG(1))[0]) picon[i][0] = atoi(arg);
8138 				if((arg=GET_ARG(2))[0]) picon[i][1] = atoi(arg);
8139 				break;
8140 			case CMD_LEVELORDER_P1ICONW: case CMD_LEVELORDER_P2ICONW: case CMD_LEVELORDER_P3ICONW: case CMD_LEVELORDER_P4ICONW:
8141 				switch(cmd) {
8142 					case CMD_LEVELORDER_P1ICONW: i = 0; break;
8143 					case CMD_LEVELORDER_P2ICONW: i = 1; break;
8144 					case CMD_LEVELORDER_P3ICONW: i = 2; piconwUsed[0] = 1; break;
8145 					case CMD_LEVELORDER_P4ICONW: i = 3; piconwUsed[1] = 1; break;
8146 					default: assert(0);
8147 				}
8148 				if((arg=GET_ARG(1))[0]) piconw[i][0] = atoi(arg);
8149 				if((arg=GET_ARG(2))[0]) piconw[i][1] = atoi(arg);
8150 				break;
8151 			case CMD_LEVELORDER_MP1ICON: case CMD_LEVELORDER_MP2ICON: case CMD_LEVELORDER_MP3ICON: case CMD_LEVELORDER_MP4ICON:
8152 				switch(cmd) {
8153 					case CMD_LEVELORDER_MP1ICON: i = 0; break;
8154 					case CMD_LEVELORDER_MP2ICON: i = 1; break;
8155 					case CMD_LEVELORDER_MP3ICON: i = 2; break;
8156 					case CMD_LEVELORDER_MP4ICON: i = 3; break;
8157 					default: assert(0);
8158 				}
8159 				if((arg=GET_ARG(1))[0]) mpicon[i][0] = atoi(arg);
8160 				if((arg=GET_ARG(2))[0]) mpicon[i][1] = atoi(arg);
8161 				break;
8162 			case CMD_LEVELORDER_P1NAMEJ: case CMD_LEVELORDER_P2NAMEJ: case CMD_LEVELORDER_P3NAMEJ: case CMD_LEVELORDER_P4NAMEJ:
8163 				switch(cmd) {
8164 					case CMD_LEVELORDER_P1NAMEJ: j = 0; break;
8165 					case CMD_LEVELORDER_P2NAMEJ: j = 1; break;
8166 					case CMD_LEVELORDER_P3NAMEJ: j = 2; break;
8167 					case CMD_LEVELORDER_P4NAMEJ: j = 3; break;
8168 					default: assert(0);
8169 				}
8170 				for(i=0; i<7; i++)
8171 					if((arg=GET_ARG(i+1))[0]) pnameJ[j][i] = atoi(arg);
8172 				pnameJused[j] = 1;
8173 				break;
8174 			case CMD_LEVELORDER_P1SCORE: case CMD_LEVELORDER_P2SCORE: case CMD_LEVELORDER_P3SCORE: case CMD_LEVELORDER_P4SCORE:
8175 				switch(cmd) {
8176 					case CMD_LEVELORDER_P1SCORE: j = 0; break;
8177 					case CMD_LEVELORDER_P2SCORE: j = 1; break;
8178 					case CMD_LEVELORDER_P3SCORE: j = 2; break;
8179 					case CMD_LEVELORDER_P4SCORE: j = 3; break;
8180 					default: assert(0);
8181 				}
8182 				for(i=0; i<7; i++)
8183 					if((arg=GET_ARG(i+1))[0]) pscore[j][i] = atoi(arg);
8184 				pscoreUsed[j] = 1;
8185 				break;
8186 			case CMD_LEVELORDER_P1SHOOT: case CMD_LEVELORDER_P2SHOOT: case CMD_LEVELORDER_P3SHOOT: case CMD_LEVELORDER_P4SHOOT:
8187 				switch(cmd) {
8188 					case CMD_LEVELORDER_P1SHOOT: j = 0; break;
8189 					case CMD_LEVELORDER_P2SHOOT: j = 1; break;
8190 					case CMD_LEVELORDER_P3SHOOT: j = 2; break;
8191 					case CMD_LEVELORDER_P4SHOOT: j = 3; break;
8192 					default: assert(0);
8193 				}
8194 				for(i=0; i<3; i++)
8195 					if((arg=GET_ARG(i+1))[0]) pshoot[j][i] = atoi(arg);
8196 				break;
8197 			case CMD_LEVELORDER_P1RUSH: case CMD_LEVELORDER_P2RUSH: case CMD_LEVELORDER_P3RUSH: case CMD_LEVELORDER_P4RUSH:
8198 				switch(cmd) {
8199 					case CMD_LEVELORDER_P1RUSH: j = 0; break;
8200 					case CMD_LEVELORDER_P2RUSH: j = 1; break;
8201 					case CMD_LEVELORDER_P3RUSH: j = 2; break;
8202 					case CMD_LEVELORDER_P4RUSH: j = 3; break;
8203 					default: assert(0);
8204 				}
8205 				for(i=0; i<8; i++)
8206 					if((arg=GET_ARG(i+1))[0]) prush[j][i] = atoi(arg);
8207 				break;
8208 			case CMD_LEVELORDER_E1ICON: case CMD_LEVELORDER_E2ICON: case CMD_LEVELORDER_E3ICON: case CMD_LEVELORDER_E4ICON:
8209 				switch(cmd) {
8210 					case CMD_LEVELORDER_E1ICON: i = 0; break;
8211 					case CMD_LEVELORDER_E2ICON: i = 1; break;
8212 					case CMD_LEVELORDER_E3ICON: i = 2; eiconUsed[0] = 1; break;
8213 					case CMD_LEVELORDER_E4ICON: i = 3; eiconUsed[1] = 1; break;
8214 					default: assert(0);
8215 				}
8216 				if((arg=GET_ARG(1))[0]) eicon[i][0] = atoi(arg);
8217 				if((arg=GET_ARG(2))[0]) eicon[i][1] = atoi(arg);
8218 				break;
8219 			case CMD_LEVELORDER_E1NAME: case CMD_LEVELORDER_E2NAME: case CMD_LEVELORDER_E3NAME: case CMD_LEVELORDER_E4NAME:
8220 				switch(cmd) {
8221 					case CMD_LEVELORDER_E1NAME: j = 0; break;
8222 					case CMD_LEVELORDER_E2NAME: j = 1; break;
8223 					case CMD_LEVELORDER_E3NAME: j = 2; break;
8224 					case CMD_LEVELORDER_E4NAME: j = 3; break;
8225 					default: assert(0);
8226 				}
8227 				for(i=0; i<3; i++)
8228 					if((arg=GET_ARG(i+1))[0]) ename[j][i] = atoi(arg);
8229 				enameused[j] = 1;
8230 				break;
8231 			case CMD_LEVELORDER_P1SMENU: case CMD_LEVELORDER_P2SMENU: case CMD_LEVELORDER_P3SMENU: case CMD_LEVELORDER_P4SMENU:
8232 				switch(cmd) {
8233 					case CMD_LEVELORDER_P1SMENU: j = 0; break;
8234 					case CMD_LEVELORDER_P2SMENU: j = 1; break;
8235 					case CMD_LEVELORDER_P3SMENU: j = 2; break;
8236 					case CMD_LEVELORDER_P4SMENU: j = 3; break;
8237 					default: assert(0);
8238 				}
8239 				for(i=0; i<4; i++)
8240 					if((arg=GET_ARG(i+1))[0]) psmenu[j][i] = atoi(arg);
8241 				break;
8242 			case CMD_LEVELORDER_TIMEICON:
8243    				strncpy(timeicon_path, GET_ARG(1), 127);
8244 				timeicon = loadsprite(timeicon_path,0,0,pixelformat);
8245 				if((arg=GET_ARG(2))[0]) timeicon_offsets[0] = atoi(arg);
8246 				if((arg=GET_ARG(3))[0]) timeicon_offsets[1] = atoi(arg);
8247 				break;
8248 			case CMD_LEVELORDER_BGICON:
8249 				strncpy(bgicon_path, GET_ARG(1), 127);
8250 				bgicon = loadsprite(bgicon_path,0,0,pixelformat);
8251 				if((arg=GET_ARG(2))[0]) bgicon_offsets[0] = atoi(arg);
8252 				if((arg=GET_ARG(3))[0]) bgicon_offsets[1] = atoi(arg);
8253 				if((arg=GET_ARG(4))[0]) bgicon_offsets[2] = atoi(arg);
8254 				else bgicon_offsets[2] = HUD_Z / 2;
8255 				break;
8256 			case CMD_LEVELORDER_OLICON:
8257 				strncpy(olicon_path, GET_ARG(1), 127);
8258 				olicon = loadsprite(olicon_path,0,0,pixelformat);
8259 				if((arg=GET_ARG(2))[0]) olicon_offsets[0] = atoi(arg);
8260 				if((arg=GET_ARG(3))[0]) olicon_offsets[1] = atoi(arg);
8261 				if((arg=GET_ARG(4))[0]) olicon_offsets[2] = atoi(arg);
8262 				else olicon_offsets[2] = HUD_Z * 3;
8263 				break;
8264 			case CMD_LEVELORDER_TIMELOC:
8265 				for(i=0; i<6; i++)
8266 					if((arg=GET_ARG(i+1))[0]) timeloc[i] = atoi(arg);
8267 				break;
8268 			case CMD_LEVELORDER_LBARSIZE:
8269 				_readbarstatus(buf+pos, &lbarstatus);
8270 				break;
8271 			case CMD_LEVELORDER_OLBARSIZE:
8272 				_readbarstatus(buf+pos, &olbarstatus);
8273 				break;
8274 			case CMD_LEVELORDER_MPBARSIZE:
8275 				_readbarstatus(buf+pos, &mpbarstatus);
8276 				break;
8277 			case CMD_LEVELORDER_LBARTEXT:
8278 				for(i=0; i<4; i++)
8279 					if((arg=GET_ARG(i+1))[0]) lbartext[i] = atoi(arg);
8280 				break;
8281 			case CMD_LEVELORDER_MPBARTEXT:
8282 				for(i=0; i<4; i++)
8283 					if((arg=GET_ARG(i+1))[0]) mpbartext[i] = atoi(arg);
8284 				break;
8285 			case CMD_LEVELORDER_SHOWCOMPLETE:
8286 				for(i=0; i<6; i++)
8287 					if((arg=GET_ARG(i+1))[0]) scomplete[i] = atoi(arg);
8288 				break;
8289 			case CMD_LEVELORDER_CLEARBONUS:
8290 				for(i=0; i<10; i++)
8291 					if((arg=GET_ARG(i+1))[0]) cbonus[i] = atoi(arg);
8292 				break;
8293 			case CMD_LEVELORDER_RUSHBONUS:
8294 				for(i=0; i<10; i++)
8295 					if((arg=GET_ARG(i+1))[0]) rbonus[i] = atoi(arg);
8296 				break;
8297 			case CMD_LEVELORDER_LIFEBONUS:
8298 				for(i=0; i<10; i++)
8299 					if((arg=GET_ARG(i+1))[0]) lbonus[i] = atoi(arg);
8300 				break;
8301 			case CMD_LEVELORDER_SCBONUSES:
8302 				for(i=0; i<4; i++)
8303 					if((arg=GET_ARG(i+1))[0]) scbonuses[i] = atoi(arg);
8304 				break;
8305 			case CMD_LEVELORDER_TOTALSCORE:
8306 				for(i=0; i<10; i++)
8307 					if((arg=GET_ARG(i+1))[0]) tscore[i] = atoi(arg);
8308 				break;
8309 			case CMD_LEVELORDER_MUSICOVERLAP:
8310 				CHKDEF;
8311 				diffoverlap[current_set] = GET_INT_ARG(1);
8312 				break;
8313 			case CMD_LEVELORDER_SHOWRUSHBONUS:
8314 				showrushbonus = 1;
8315 				break;
8316 			case CMD_LEVELORDER_NOSLOWFX:
8317 				noslowfx = 1;
8318 				break;
8319 			case CMD_LEVELORDER_EQUALAIRPAUSE:
8320 				equalairpause = 1;
8321 				break;
8322 			case CMD_LEVELORDER_HISCOREBG:
8323 				hiscorebg = 1;
8324 				break;
8325 			case CMD_LEVELORDER_COMPLETEBG:
8326 				completebg = 1;
8327 				break;
8328 			case CMD_LEVELORDER_LOADINGBG:
8329 				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));
8330 				if(errormessage) goto lCleanup;
8331 				break;
8332 			case CMD_LEVELORDER_LOADINGBG2:
8333 				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));
8334 				if(errormessage) goto lCleanup;
8335 				break;
8336 			case CMD_LEVELORDER_LOADINGMUSIC:
8337 				loadingmusic = GET_INT_ARG(1);
8338 				break;
8339 			case CMD_LEVELORDER_UNLOCKBG:
8340 				unlockbg = 1;
8341 				break;
8342 			case CMD_LEVELORDER_NOSHARE:
8343 				noshare = 1;
8344 				break;
8345 			case CMD_LEVELORDER_CUSTFADE:
8346 				//8-2-2005 custom fade
8347 				CHKDEF;
8348 				custfade[current_set] = GET_INT_ARG(1);
8349 				break;
8350 			case CMD_LEVELORDER_CONTINUESCORE:
8351 				//8-2-2005 custom fade end
8352 				//continuescore
8353 				CHKDEF;
8354 				continuescore[current_set] = GET_INT_ARG(1);
8355 				break;
8356 			case CMD_LEVELORDER_CREDITS:
8357 				CHKDEF;
8358 				diffcreds[current_set] = GET_INT_ARG(1);
8359 				break;
8360 			case CMD_LEVELORDER_TYPEMP:
8361 				//typemp for change for mp restored by time (0) to by enemys (1) or no restore (2) by tails
8362 				CHKDEF;
8363 				typemp[current_set] = GET_INT_ARG(1);
8364 				break;
8365 			case CMD_LEVELORDER_SINGLE:
8366 				if(current_set<0) {
8367 					for(i=0; i<MAX_DIFFICULTIES; i++)
8368 						maxplayers[i] = ctrlmaxplayers[i] = 1;
8369 				} else {
8370 					maxplayers[current_set] = ctrlmaxplayers[current_set] = 1;
8371 				}
8372 				break;
8373 			case CMD_LEVELORDER_MAXPLAYERS:
8374 				// 7-1-2005  credits/lives/singleplayer end here
8375 				if(current_set<0) {
8376 					maxplayers[0] = GET_INT_ARG(1);
8377 					for(i=0; i<MAX_DIFFICULTIES; i++)
8378 						maxplayers[i] = ctrlmaxplayers[i] = maxplayers[0];
8379 				} else {
8380 					maxplayers[current_set] = ctrlmaxplayers[current_set] = GET_INT_ARG(1);
8381 				}
8382 				break;
8383 			case CMD_LEVELORDER_NOSAME:
8384 				CHKDEF;
8385 				same[current_set] = GET_INT_ARG(1);
8386 				break;
8387 			case CMD_LEVELORDER_RUSH:
8388 				rush[0] = GET_INT_ARG(1);
8389 				rush[1] = GET_INT_ARG(2);
8390 				strncpy(rush_names[0], GET_ARG(3), MAX_NAME_LEN);
8391 				rush[2] = GET_INT_ARG(4);
8392 				rush[3] = GET_INT_ARG(5);
8393 				strncpy(rush_names[1], GET_ARG(6), MAX_NAME_LEN);
8394 				rush[4] = GET_INT_ARG(7);
8395 				rush[5] = GET_INT_ARG(8);
8396 				break;
8397 			case CMD_LEVELORDER_MAXWALLHEIGHT:
8398 				MAX_WALL_HEIGHT = GET_INT_ARG(1);
8399 				if(MAX_WALL_HEIGHT < 0) MAX_WALL_HEIGHT = 1000;
8400 				break;
8401 			case CMD_LEVELORDER_SCOREFORMAT:
8402 				scoreformat = GET_INT_ARG(1);
8403 				break;
8404 			default:
8405 				if (command && command[0])
8406 					printf("Command '%s' not understood in level order!", command);
8407 		}
8408 
8409 		// Go to next line
8410 		pos+=getNewLineStart(buf + pos);
8411 	}
8412 
8413 #undef CHKDEF
8414 
8415 	// Variables without defaults will be auto populated.
8416 	if(olbarstatus.sizex==0) {olbarstatus = lbarstatus;}
8417 
8418 	if(!plifeUsed[0]){ plife[2][0] = plife[0][0]; plife[2][1] = plife[2][1] + (plife[0][1] - 10); }
8419 	if(!plifeUsed[1]){ plife[3][0] = plife[1][0]; plife[3][1] = plife[3][1] + (plife[1][1] - 10); }
8420 
8421 	if(!elifeUsed[0]){ elife[2][0] = elife[0][0]; elife[2][1] = elife[2][1] + (elife[0][1] - 27); }
8422 	if(!elifeUsed[1]){ elife[3][0] = elife[1][0]; elife[3][1] = elife[3][1] + (elife[1][1] - 27); }
8423 
8424 	if(!piconUsed[0]){ picon[2][0] = picon[0][0]; picon[2][1] = picon[2][1] + (picon[0][1] - 2); }
8425 	if(!piconUsed[1]){ picon[3][0] = picon[1][0]; picon[3][1] = picon[3][1] + (picon[1][1] - 2); }
8426 
8427 	if(!piconwUsed[0]){ piconw[2][0] = piconw[0][0]; piconw[2][1] = piconw[2][1] + (piconw[0][1] - 2); }
8428 	if(!piconwUsed[1]){ piconw[3][0] = piconw[1][0]; piconw[3][1] = piconw[3][1] + (piconw[1][1] - 2); }
8429 
8430 	if(!eiconUsed[0]){ eicon[2][0] = eicon[0][0]; eicon[2][1] = eicon[2][1] + (eicon[0][1] - 19); }
8431 	if(!eiconUsed[1]){ eicon[3][0] = eicon[1][0]; eicon[3][1] = eicon[3][1] + (eicon[1][1] - 19); }
8432 
8433 	if(!pmpUsed[0]){ pmp[0][0] = plife[0][0]; pmp[0][1] = plife[0][1] + 8; }
8434 	if(!pmpUsed[1]){ pmp[1][0] = plife[1][0]; pmp[1][1] = plife[1][1] + 8; }
8435 	if(!pmpUsed[2]){ pmp[2][0] = pmp[0][0]; pmp[2][1] = pmp[2][1] + (pmp[0][1] - 18); }
8436 	if(!pmpUsed[3]){ pmp[3][0] = pmp[1][0]; pmp[3][1] = pmp[1][1] + (pmp[1][1] - 18); }
8437 
8438 	if(!plifeXused[0]){ plifeX[0][0] = plife[0][0] + lbarstatus.sizex + 4; plifeX[0][1] = picon[0][1] + 7; }
8439 	if(!plifeXused[1]){ plifeX[1][0] = plife[1][0] + lbarstatus.sizex + 4; plifeX[1][1] = picon[1][1] + 7; }
8440 	if(!plifeXused[2]){ plifeX[2][0] = plife[2][0] + lbarstatus.sizex + 4; plifeX[2][1] = picon[2][1] + 7; }
8441 	if(!plifeXused[3]){ plifeX[3][0] = plife[3][0] + lbarstatus.sizex + 4; plifeX[3][1] = picon[3][1] + 7; }
8442 	for(i=0; i<4; i++) if(plifeX[i][2] == -1) plifeX[i][2] = 0;
8443 
8444 	if(!plifeNused[0]){ plifeN[0][0] = plife[0][0] + lbarstatus.sizex + 11; plifeN[0][1] = picon[0][1]; }
8445 	if(!plifeNused[1]){ plifeN[1][0] = plife[1][0] + lbarstatus.sizex + 11; plifeN[1][1] = picon[1][1]; }
8446 	if(!plifeNused[2]){ plifeN[2][0] = plifeN[0][0]; plifeN[2][1] = picon[2][1]; }
8447 	if(!plifeNused[3]){ plifeN[3][0] = plifeN[1][0]; plifeN[3][1] = picon[3][1]; }
8448 	for(i=0; i<4; i++) if(plifeN[i][2] == -1) plifeN[i][2] = 3;
8449 
8450 	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]; }
8451 	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]; }
8452 	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]; }
8453 	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]; }
8454 	for(i=0; i<4; i++) if(pnameJ[i][6] == -1) pnameJ[i][6] = 0;
8455 
8456 	if(!pscoreUsed[0]){ pscore[0][0] = plife[0][0] + 1; pscore[0][1] = picon[0][1]; }
8457 	if(!pscoreUsed[1]){ pscore[1][0] = plife[1][0] + 1; pscore[1][1] = picon[1][1]; }
8458 	if(!pscoreUsed[2]){ pscore[2][0] = plife[2][0] + 1; pscore[2][1] = picon[2][1]; }
8459 	if(!pscoreUsed[3]){ pscore[3][0] = plife[3][0] + 1; pscore[3][1] = picon[3][1]; }
8460 	for(i=0; i<4; i++) if(pscore[i][6] == -1) pscore[i][6] = 0;
8461 
8462 	if(!enameused[0]){ ename[0][0] = elife[0][0] + 1; ename[0][1] = eicon[0][1]; }
8463 	if(!enameused[1]){ ename[1][0] = elife[1][0] + 1; ename[1][1] = eicon[1][1]; }
8464 	if(!enameused[2]){ ename[2][0] = ename[0][0]; ename[2][1] = eicon[2][1]; }
8465 	if(!enameused[3]){ ename[3][0] = ename[1][0]; ename[3][1] = eicon[3][1]; }
8466 	for(i=0; i<4; i++) if(ename[i][2] == -1) ename[i][2] = 0;
8467 
8468 	branch_name[0] = 0; //clear up branch name, so we can use it in game
8469 
8470 	for(i=0; i<4; i++) if(pshoot[i][2] == -1) pshoot[i][2] = 2;
8471 	if(timeloc[5] == -1) timeloc[5] = 3;
8472 
8473 	if(current_set<0)
8474 		errormessage = "No levels were loaded!";
8475 
8476 	lCleanup:
8477 
8478 	if(buf)
8479 		free(buf);
8480 
8481 	if(errormessage)
8482 		shutdown(1, "load_levelorder ERROR in %s at %d, msg: %s\n", filename, line, errormessage);
8483 }
8484 
8485 
free_level(s_level * lv)8486 void free_level(s_level* lv)
8487 {
8488 	int i, j;
8489 	s_spawn_script_list_node* templistnode;
8490 	s_spawn_script_list_node* templistnode2;
8491 	s_spawn_script_cache_node* tempnode;
8492 	s_spawn_script_cache_node* tempnode2;
8493 	if(!lv) return;
8494 	//offload blending tables
8495 	for(i=0; i<LEVEL_MAX_PALETTES; i++)
8496 	{
8497 		for(j=0; j<MAX_BLENDINGS; j++)
8498 		{
8499 			if(lv->blendings[i][j]) free(lv->blendings[i][j]);
8500 			lv->blendings[i][j] = NULL;
8501 		}
8502 	}
8503 	//offload bglayers
8504 	for(i=1; i<lv->numbglayers; i++)
8505 	{
8506 		if(lv->bglayers[i].handle)
8507 		{
8508 			free(lv->bglayers[i].handle);
8509 			lv->bglayers[i].handle = NULL;
8510 		}
8511 	}
8512 		//offload fglayers
8513 	for(i=0; i<lv->numfglayers; i++)
8514 	{
8515 		if(lv->fglayers[i].handle)
8516 		{
8517 			free(lv->fglayers[i].handle);
8518 			lv->fglayers[i].handle = NULL;
8519 		}
8520 	}
8521 
8522 	//offload textobjs
8523 	for(i=0; i<LEVEL_MAX_TEXTOBJS; i++)
8524 	{
8525 		if(lv->textobjs[i].text)
8526 		{
8527 			free(lv->textobjs[i].text);
8528 			lv->textobjs[i].text = NULL;
8529 		}
8530 	}
8531 
8532 	for(i=0; i<LEVEL_MAX_FILESTREAMS; i++)
8533 	{
8534 		if(lv->filestreams[i].buf)
8535 		{
8536 			free(lv->filestreams[i].buf);
8537 			lv->filestreams[i].buf = NULL;
8538 		}
8539 	}
8540 
8541 	//offload scripts
8542 	Script_Clear(&(lv->update_script), 2);
8543 	Script_Clear(&(lv->updated_script), 2);
8544 	Script_Clear(&(lv->key_script), 2);
8545 	Script_Clear(&(lv->level_script), 2);
8546 	Script_Clear(&(lv->endlevel_script), 2);
8547 
8548 	for(i=0; i<LEVEL_MAX_SPAWNS; i++)
8549 	{
8550 		if(lv->spawnpoints[i].spawn_script_list_head)
8551 		{
8552 			templistnode = lv->spawnpoints[i].spawn_script_list_head;
8553 			lv->spawnpoints[i].spawn_script_list_head = NULL;
8554 			while(templistnode)
8555 			{
8556 				templistnode2 = templistnode->next;
8557 				templistnode->next = NULL;
8558 				templistnode->spawn_script = NULL;
8559 				free(templistnode);
8560 				templistnode = templistnode2;
8561 		    }
8562 		}
8563 	}
8564 
8565 	tempnode = lv->spawn_script_cache_head;
8566 	lv->spawn_script_cache_head = NULL;
8567 	while(tempnode)
8568 	{
8569 		tempnode2 = tempnode->next;
8570 		Script_Clear(tempnode->cached_spawn_script, 2);
8571 		free(tempnode->cached_spawn_script);
8572 		tempnode->cached_spawn_script = NULL;
8573 		free(tempnode->filename);
8574 		tempnode->filename = NULL;
8575 		tempnode->next = NULL;
8576 		free(tempnode);
8577 		tempnode = tempnode2;
8578 	}
8579 
8580 	free(lv);
8581 	lv = NULL;
8582 }
8583 
8584 
unload_level()8585 void unload_level(){
8586 	s_model* temp;
8587 	unload_background();
8588 	freepanels();
8589 	freescreen(&bgbuffer);
8590 
8591 	if(level){
8592 
8593 		level->pos = 0;
8594 		level->advancetime = 0;
8595 		level->quake = 0;
8596 		level->quaketime = 0;
8597 		level->waiting = 0;
8598 
8599 		printf("Level Unloading: '%s'\n", level->name);
8600 		getRamStatus(BYTES);
8601 		free(level->name);
8602 		level->name = NULL;
8603 		free_level(level);
8604 		level = NULL;
8605 		temp = getFirstModel();
8606 		do {
8607 			if(!temp) break;
8608 			if(temp->unload) {
8609 				free_model(temp);
8610 				temp = getCurrentModel();
8611 			} else
8612 				temp = getNextModel();
8613 		} while(temp);
8614 		printf("Done.\n");
8615 		getRamStatus(BYTES);
8616 
8617 
8618 	}
8619 
8620 	advancex = 0;
8621 	advancey = 0;
8622 	nojoin = 0;
8623 	current_spawn = 0;
8624 	groupmin = 100;
8625 	groupmax = 100;
8626 	scrollminz = 0;
8627 	scrollmaxz = 0;
8628 	blockade = 0;
8629 	level_completed = 0;
8630 	tospeedup = 0;    // Reset so it sets to normal speed for the next level
8631 	reached[0] = reached[1] = reached[2] = reached[3] = 0;    // TYPE_ENDLEVEL values reset after level completed //4player
8632 	showtimeover = 0;
8633 	pause = 0;
8634 	endgame = 0;
8635 	go_time = 0;
8636 	neon_time = 0;
8637 	time = 0;
8638 	cameratype = 0;
8639 	light[0] = 128;
8640 	light[1] = 64;
8641 	gfx_y_offset = 0;    // Added so select screen graphics display correctly
8642 }
8643 
llHandleCommandSpawnscript(ArgList * arglist,s_spawn_entry * next)8644 char* llHandleCommandSpawnscript(ArgList* arglist, s_spawn_entry* next) {
8645 	char* result = NULL;
8646 	char* value;
8647 	size_t len;
8648 
8649 	s_spawn_script_cache_node* tempnode;
8650 	s_spawn_script_cache_node* tempnode2;
8651 	s_spawn_script_list_node* templistnode;
8652 
8653 	value = GET_ARGP(1);
8654 
8655 	tempnode = level->spawn_script_cache_head;
8656 	if(!next->spawn_script_list_head) next->spawn_script_list_head = NULL;
8657 	templistnode = next->spawn_script_list_head;
8658 	if(templistnode) {
8659 		while(templistnode->next)
8660 		{
8661 			templistnode = templistnode->next;
8662 		}
8663 		templistnode->next = malloc(sizeof(s_spawn_script_list_node));
8664 		templistnode = templistnode->next;
8665 	} else	{
8666 		next->spawn_script_list_head = malloc(sizeof(s_spawn_script_list_node));
8667 		templistnode = next->spawn_script_list_head;
8668 	}
8669 	templistnode->spawn_script = NULL;
8670 	templistnode->next = NULL;
8671 	if(tempnode) {
8672 		while(1) {
8673 			if(stricmp(value, tempnode->filename)==0) {
8674 				templistnode->spawn_script = tempnode->cached_spawn_script;
8675 				break;
8676 			} else {
8677 				if(tempnode->next)
8678 					tempnode = tempnode->next;
8679 				else
8680 					break;
8681 			}
8682 		}
8683 	}
8684 	if(!templistnode->spawn_script) {
8685 		templistnode->spawn_script = alloc_script();
8686 		if(!Script_IsInitialized(templistnode->spawn_script))
8687 			Script_Init(templistnode->spawn_script, GET_ARGP(0), 0);
8688 		else {
8689 			result = "Multiple spawn entry script!";
8690 			goto lCleanup;
8691 		}
8692 
8693 		if(load_script(templistnode->spawn_script, value)) {
8694 			Script_Compile(templistnode->spawn_script);
8695 			len = strlen(value);
8696 
8697 			if(tempnode) {
8698 				tempnode2 = malloc(sizeof(s_spawn_script_cache_node));
8699 				tempnode2->cached_spawn_script = templistnode->spawn_script;
8700 				tempnode2->filename = malloc(len + 1);
8701 				strcpy(tempnode2->filename, value);
8702 				tempnode2->filename[len] = 0;
8703 				tempnode2->next = NULL;
8704 				tempnode->next = tempnode2;
8705 			} else {
8706 				level->spawn_script_cache_head = malloc(sizeof(s_spawn_script_cache_node));
8707 				level->spawn_script_cache_head->cached_spawn_script = templistnode->spawn_script;
8708 				level->spawn_script_cache_head->filename = malloc(len + 1);
8709 				level->spawn_script_cache_head->next = NULL;
8710 				strcpy(level->spawn_script_cache_head->filename, value);
8711 				level->spawn_script_cache_head->filename[len] = 0;
8712 			}
8713 		} else {
8714 			result = "Failed loading spawn entry script!";
8715 			goto lCleanup;
8716 		}
8717 	}
8718 	lCleanup:
8719 	return result;
8720 }
8721 
8722 
load_level(char * filename)8723 void load_level(char *filename){
8724 	char *buf = NULL;
8725 	size_t size, len;
8726 	ptrdiff_t pos, oldpos;
8727 	char *command;
8728 	char *value;
8729 	char string[128] = {""};
8730 	s_spawn_entry next;
8731 	s_model *tempmodel, *cached_model;
8732 
8733 	int i = 0, j = 0, crlf = 0;
8734 	int usemap[MAX_BLENDINGS];
8735 	char bgPath[128] = {""};
8736 	s_loadingbar bgPosi = {0, 0, 0, 0, 0, 0, 0};
8737 	char musicPath[128] = {""};
8738 	u32 musicOffset = 0;
8739 
8740 	ArgList arglist;
8741 	char argbuf[MAX_ARG_LEN+1] = "";
8742 
8743 	ArgList arglist2;
8744 	char argbuf2[MAX_ARG_LEN+1] = "";
8745 
8746 	levelCommands cmd;
8747 	levelCommands cmd2;
8748 	int line = 0;
8749 	char* errormessage = NULL;
8750 	char* scriptname = NULL;
8751 	Script* tempscript = NULL;
8752 	s_drawmethod* dm;
8753 
8754 	unload_level();
8755 
8756 	printf("Level Loading:   '%s'\n", filename);
8757 
8758 
8759 
8760 	getRamStatus(BYTES);
8761 
8762 	if(isLoadingScreenTypeBg(loadingbg[1].set)) {
8763 		if(custBkgrds) {
8764 			strcpy(string, custBkgrds);
8765 			strcat(string, "loading2");
8766 			load_background(string, 0);
8767 		} else {
8768 			load_cached_background("data/bgs/loading2", 0);
8769 		}
8770 		clearscreen(vscreen);
8771 		spriteq_clear();
8772 		standard_palette(1);
8773 	}
8774 
8775 	if(isLoadingScreenTypeBar(loadingbg[1].set)) {
8776 	    lifebar_colors();
8777 	    init_colourtable();
8778 	}
8779 
8780 	update_loading(&loadingbg[1], -1, 1); // initialize the update screen
8781 
8782 	memset(&next, 0, sizeof(s_spawn_entry));
8783 
8784 	level = calloc(1,sizeof(s_level));
8785 	if(!level) {
8786 		errormessage = "load_level() #1 FATAL: Out of memory!";
8787 		goto lCleanup;
8788 	}
8789 	len = strlen(filename);
8790 	level->name = malloc(len + 1);
8791 
8792 	if(!level->name) {
8793 		errormessage = "load_level() #1 FATAL: Out of memory!";
8794 		goto lCleanup;
8795 	}
8796 	strcpy(level->name, filename);
8797 
8798 	if(buffer_pakfile(filename, &buf, &size)!=1) {
8799 		errormessage = "Unable to load level file!";
8800 		goto lCleanup;
8801 	}
8802 
8803 	level->settime = 100;    // Feb 25, 2005 - Default time limit set to 100
8804 	level->nospecial = 0;    // Default set to specials can be used during bonus levels
8805 	level->nohurt = 0;    // Default set to players can hurt each other during bonus levels
8806 	level->nohit = 0;    // Default able to hit the other player
8807 	level->spawn[0][2] = level->spawn[1][2] = level->spawn[2][2] = level->spawn[3][2] = 300;    // Set the default spawn a to 300
8808 	level->setweap = 0;
8809 	level->maxtossspeed = 100;
8810 	level->maxfallspeed = -6;
8811 	level->gravity = (float)-0.1;
8812 	level->scrolldir = SCROLL_RIGHT;
8813 	level->scrollspeed = 1;
8814 	level->cameraxoffset = 0;
8815 	level->camerazoffset = 0;
8816 	level->bosses = 0;
8817 	blendfx[BLEND_MULTIPLY] = 1;
8818 	bgtravelled = 0;
8819 	traveltime = 0;
8820 	texttime = 0;
8821 	nopause = 0;
8822 	noscreenshot = 0;
8823 
8824 	reset_playable_list(1);
8825 
8826 	// Now interpret the contents of buf line by line
8827 	pos = 0;
8828 	while(pos<size){
8829 		line++;
8830 		ParseArgs(&arglist,buf+pos,argbuf);
8831 		command = GET_ARG(0);
8832 		cmd = getLevelCommand(levelcmdlist, command);
8833 		switch(cmd) {
8834 			case CMD_LEVEL_LOADINGBG:
8835 				load_background(GET_ARG(1), 0);
8836 				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));
8837 				if (errormessage) goto lCleanup;
8838 				standard_palette(1);
8839 				lifebar_colors();
8840 				init_colourtable();
8841 				update_loading(&bgPosi, -1, 1); // initialize the update screen
8842 				break;
8843 			case CMD_LEVEL_MUSICFADE:
8844 				memset(&next,0,sizeof(s_spawn_entry));
8845 				next.musicfade = GET_FLOAT_ARG(1);
8846 				break;
8847 			case CMD_LEVEL_MUSIC:
8848 				value = GET_ARG(1);
8849 				strncpy(string, value, 128);
8850 				musicOffset = atol(GET_ARG(2));
8851 				if(loadingmusic) {
8852 					music(string, 1, musicOffset);
8853 					musicPath[0] = 0;
8854 				} else {
8855 					oldpos = pos;
8856 					// Go to next line
8857 					pos += getNewLineStart(buf + pos);
8858 					#define GET_ARG2(z) arglist2.count > z ? arglist2.args[z] : ""
8859 					if(pos<size) {
8860 						ParseArgs(&arglist2,buf+pos,argbuf2);
8861 						command = GET_ARG2(0);
8862 						cmd2 = getLevelCommand(levelcmdlist, command);
8863 					} else
8864 						cmd2 = (levelCommands) 0;
8865 
8866 					if(cmd2 == CMD_LEVEL_AT) {
8867 						if(next.musicfade == 0) memset(&next,0,sizeof(s_spawn_entry));
8868 						strncpy(next.music, string, 128);
8869 						next.musicoffset = musicOffset;
8870 					} else {
8871 						strncpy(musicPath, string, 128);
8872 					}
8873 					pos = oldpos;
8874 					#undef GET_ARG2
8875 				}
8876 				break;
8877 			case CMD_LEVEL_ALLOWSELECT:
8878 				load_playable_list(buf+pos);
8879 				break;
8880 			case CMD_LEVEL_LOAD:
8881 				#ifdef DEBUG
8882 				printf("load_level: load %s, %s\n", GET_ARG(1), filename);
8883 				#endif
8884 				tempmodel = findmodel(GET_ARG(1));
8885 				if (!tempmodel)
8886 					load_cached_model(GET_ARG(1), filename, GET_INT_ARG(2));
8887 				else
8888 					update_model_loadflag(tempmodel, GET_INT_ARG(2));
8889 				break;
8890 			case CMD_LEVEL_BACKGROUND:
8891 				value = GET_ARG(1);
8892 				strncpy(bgPath, value, strlen(value)+1);
8893 
8894 				dm = &(level->bglayers[0].drawmethod);
8895 				*dm = plainmethod;
8896 
8897 				level->bglayers[0].type = bg_screen;
8898 				level->bglayers[0].bgspeedratio = 1;
8899 
8900 				level->bglayers[0].xratio = GET_FLOAT_ARG(2); // x ratio
8901 				level->bglayers[0].zratio = GET_FLOAT_ARG(3); // z ratio
8902 				level->bglayers[0].xoffset = GET_INT_ARG(4); // x start
8903 				level->bglayers[0].zoffset = GET_INT_ARG(5); // z start
8904 				level->bglayers[0].xspacing = GET_INT_ARG(6); // x spacing
8905 				level->bglayers[0].zspacing = GET_INT_ARG(7); // z spacing
8906 				level->bglayers[0].xrepeat = GET_INT_ARG(8); // x repeat
8907 				level->bglayers[0].zrepeat = GET_INT_ARG(9); // z repeat
8908 				// unused
8909 				dm->transbg = GET_INT_ARG(10); // transparency
8910 				dm->alpha = GET_INT_ARG(11); // alpha
8911 				dm->water.watermode = GET_INT_ARG(12); // amplitude
8912 				if(dm->water.watermode==3){
8913 					dm->water.beginsize = GET_FLOAT_ARG(13); // beginsize
8914 					dm->water.endsize = GET_FLOAT_ARG(14); // endsize
8915 					dm->water.perspective = GET_INT_ARG(15); // waterspeed
8916 				}else{
8917 					dm->water.amplitude = GET_INT_ARG(13); // amplitude
8918 					dm->water.wavelength = GET_INT_ARG(14); // wavelength
8919 					dm->water.wavespeed = GET_FLOAT_ARG(15); // waterspeed
8920 				}
8921 				level->bglayers[0].enabled = 1; // enabled
8922 
8923 				if((value=GET_ARG(2))[0]==0) level->bglayers[0].xratio = 0.5;
8924 				if((value=GET_ARG(3))[0]==0) level->bglayers[0].zratio = 0.5;
8925 
8926 				if((value=GET_ARG(8))[0]==0) level->bglayers[0].xrepeat = -1;
8927 				if((value=GET_ARG(9))[0]==0) level->bglayers[0].zrepeat = -1;
8928 
8929 				if(level->numbglayers==0) level->numbglayers = 1;
8930 				break;
8931 			case CMD_LEVEL_BGLAYER:
8932 				if(level->numbglayers >= LEVEL_MAX_BGLAYERS) {
8933 					errormessage = "Too many bg layers in level (check LEVEL_MAX_BGLAYERS)!";
8934 					goto lCleanup;
8935 				}
8936 				if(level->numbglayers==0) level->numbglayers = 1; // reserve for background
8937 
8938 				dm = &(level->bglayers[level->numbglayers].drawmethod);
8939 				*dm = plainmethod;
8940 
8941 				level->bglayers[level->numbglayers].xratio = GET_FLOAT_ARG(2); // x ratio
8942 				level->bglayers[level->numbglayers].zratio = GET_FLOAT_ARG(3); // z ratio
8943 				level->bglayers[level->numbglayers].xoffset = GET_INT_ARG(4); // x start
8944 				level->bglayers[level->numbglayers].zoffset = GET_INT_ARG(5); // z start
8945 				level->bglayers[level->numbglayers].xspacing = GET_INT_ARG(6); // x spacing
8946 				level->bglayers[level->numbglayers].zspacing = GET_INT_ARG(7); // z spacing
8947 				level->bglayers[level->numbglayers].xrepeat = GET_INT_ARG(8); // x repeat
8948 				level->bglayers[level->numbglayers].zrepeat = GET_INT_ARG(9); // z repeat
8949 				dm->transbg = GET_INT_ARG(10); // transparency
8950 				dm->alpha = GET_INT_ARG(11); // alpha
8951 				dm->water.watermode = GET_INT_ARG(12); // amplitude
8952 				if(dm->water.watermode==3){
8953 					dm->water.beginsize = GET_FLOAT_ARG(13); // beginsize
8954 					dm->water.endsize = GET_FLOAT_ARG(14); // endsize
8955 					dm->water.perspective = GET_INT_ARG(15); // amplitude
8956 				}else{
8957 					dm->water.amplitude = GET_INT_ARG(13); // amplitude
8958 					dm->water.wavelength = GET_INT_ARG(14); // wavelength
8959 					dm->water.wavespeed = GET_FLOAT_ARG(15); // waterspeed
8960 				}
8961 				level->bglayers[level->numbglayers].bgspeedratio = GET_FLOAT_ARG(16); // moving
8962 				level->bglayers[level->numbglayers].enabled = 1; // enabled
8963 
8964 				if((value=GET_ARG(2))[0]==0) level->bglayers[level->numbglayers].xratio = 0.5;
8965 				if((value=GET_ARG(3))[0]==0) level->bglayers[level->numbglayers].zratio = 0.5;
8966 
8967 				if((value=GET_ARG(8))[0]==0) level->bglayers[level->numbglayers].xrepeat = -1;
8968 				if((value=GET_ARG(9))[0]==0) level->bglayers[level->numbglayers].zrepeat = -1;
8969 
8970 				if(blendfx_is_set==0 && dm->alpha) blendfx[dm->alpha-1] = 1;
8971 
8972 				load_bglayer(GET_ARG(1), level->numbglayers);
8973 				level->numbglayers++;
8974 				break;
8975 			case CMD_LEVEL_FGLAYER:
8976 				if(level->numfglayers >= LEVEL_MAX_FGLAYERS) {
8977 					errormessage = "Too many bg layers in level (check LEVEL_MAX_FGLAYERS)!";
8978 					goto lCleanup;
8979 				}
8980 
8981 				dm = &(level->fglayers[level->numfglayers].drawmethod);
8982 				*dm = plainmethod;
8983 
8984 				level->fglayers[level->numfglayers].z = GET_INT_ARG(2); // z
8985 				level->fglayers[level->numfglayers].xratio = GET_FLOAT_ARG(3); // x ratio
8986 				level->fglayers[level->numfglayers].zratio = GET_FLOAT_ARG(4); // z ratio
8987 				level->fglayers[level->numfglayers].xoffset = GET_INT_ARG(5); // x start
8988 				level->fglayers[level->numfglayers].zoffset = GET_INT_ARG(6); // z start
8989 				level->fglayers[level->numfglayers].xspacing = GET_INT_ARG(7); // x spacing
8990 				level->fglayers[level->numfglayers].zspacing = GET_INT_ARG(8); // z spacing
8991 				level->fglayers[level->numfglayers].xrepeat = GET_INT_ARG(9); // x repeat
8992 
8993 				level->fglayers[level->numfglayers].zrepeat = GET_INT_ARG(10); // z repeat
8994 				dm->transbg = GET_INT_ARG(11); // transparency
8995 				dm->alpha = GET_INT_ARG(12); // alpha
8996 				dm->water.watermode = GET_INT_ARG(13); // watermode
8997 				if(dm->water.watermode==3){
8998 					dm->water.beginsize = GET_FLOAT_ARG(14); // beginsize
8999 					dm->water.endsize = GET_FLOAT_ARG(15); // endsize
9000 					dm->water.perspective = GET_INT_ARG(16); // amplitude
9001 				}else{
9002 					dm->water.amplitude = GET_INT_ARG(14); // amplitude
9003 					dm->water.wavelength = GET_INT_ARG(15); // wavelength
9004 					dm->water.wavespeed = GET_FLOAT_ARG(16); // waterspeed
9005 				}
9006 				level->fglayers[level->numfglayers].bgspeedratio = GET_FLOAT_ARG(17); // moving
9007 				level->fglayers[level->numfglayers].enabled = 1;
9008 
9009 				if((value=GET_ARG(2))[0]==0) level->fglayers[level->numfglayers].xratio = 1.5;
9010 				if((value=GET_ARG(3))[0]==0) level->fglayers[level->numfglayers].zratio = 1.5;
9011 
9012 				if((value=GET_ARG(8))[0]==0) level->fglayers[level->numfglayers].xrepeat = -1;
9013 				if((value=GET_ARG(9))[0]==0) level->fglayers[level->numfglayers].zrepeat = -1;
9014 
9015 				if(blendfx_is_set==0 && dm->alpha) blendfx[dm->alpha-1] = 1;
9016 
9017 				load_fglayer(GET_ARG(1), level->numfglayers);
9018 				level->numfglayers++;
9019 				break;
9020 			case CMD_LEVEL_WATER:
9021 				if(level->numbglayers >= LEVEL_MAX_BGLAYERS) {
9022 					errormessage = "Too many bg layers in level (check LEVEL_MAX_BGLAYERS)!";
9023 					goto lCleanup;
9024 				}
9025 				if(level->numbglayers==0) level->numbglayers = 1; // reserve for background
9026 				dm = &(level->bglayers[level->numbglayers].drawmethod);
9027 				*dm = plainmethod;
9028 
9029 				level->bglayers[level->numbglayers].xratio = 0.5; // x ratio
9030 				level->bglayers[level->numbglayers].zratio = 0.5; // z ratio
9031 				level->bglayers[level->numbglayers].xoffset = 0; // x start
9032 				level->bglayers[level->numbglayers].zoffset = 1234567890; // z start
9033 				level->bglayers[level->numbglayers].xspacing = 0; // x spacing
9034 				level->bglayers[level->numbglayers].zspacing = 0; // z spacing
9035 				level->bglayers[level->numbglayers].xrepeat = -1; // x repeat
9036 				level->bglayers[level->numbglayers].zrepeat = 1; // z repeat
9037 				dm->transbg = 0; // transparency
9038 				dm->alpha = 0; // alpha
9039 				dm->water.watermode = 2; // amplitude
9040 				dm->water.amplitude = GET_INT_ARG(2); // amplitude
9041 				dm->water.wavelength = 40; // wavelength
9042 				dm->water.wavespeed = 1.0; // waterspeed
9043 				level->bglayers[level->numbglayers].bgspeedratio = 0; // moving
9044 				level->bglayers[level->numbglayers].enabled = 1; // enabled
9045 
9046 				if(dm->water.amplitude<1)dm->water.amplitude = 1;
9047 
9048 				load_bglayer(GET_ARG(1), level->numbglayers);
9049 				level->numbglayers++;
9050 				break;
9051 			case CMD_LEVEL_DIRECTION:
9052 				value = GET_ARG(1);
9053 				if(stricmp(value, "up")==0) level->scrolldir = SCROLL_UP;
9054 				else if(stricmp(value, "down")==0) level->scrolldir = SCROLL_DOWN;
9055 				else if(stricmp(value, "left")==0) level->scrolldir = SCROLL_LEFT;
9056 				else if(stricmp(value, "both")==0 || stricmp(value, "rightleft")==0) level->scrolldir = SCROLL_BOTH;
9057 				else if(stricmp(value, "leftright")==0) level->scrolldir = SCROLL_LEFTRIGHT;
9058 				else if(stricmp(value, "right")==0) level->scrolldir = SCROLL_RIGHT;
9059 				else if(stricmp(value, "in")==0) level->scrolldir = SCROLL_INWARD;
9060 				else if(stricmp(value, "out")==0) level->scrolldir = SCROLL_OUTWARD;
9061 				else if(stricmp(value, "inout")==0) level->scrolldir = SCROLL_INOUT;
9062 				else if(stricmp(value, "outin")==0) level->scrolldir = SCROLL_OUTIN;
9063 				break;
9064 			case CMD_LEVEL_FACING:
9065 				level->facing = GET_INT_ARG(1);
9066 				break;
9067 			case CMD_LEVEL_ROCK:
9068 				level->rocking = GET_INT_ARG(1);
9069 				break;
9070 			case CMD_LEVEL_BGSPEED:
9071 				level->bgspeed = GET_FLOAT_ARG(1);
9072 				if(GET_INT_ARG(2))level->bgspeed*=-1;
9073 				break;
9074 			case CMD_LEVEL_SCROLLSPEED:
9075 				level->scrollspeed = GET_FLOAT_ARG(1);
9076 				break;
9077 			case CMD_LEVEL_MIRROR:
9078 				level->mirror = GET_INT_ARG(1);
9079 				break;
9080 			case CMD_LEVEL_BOSSMUSIC:
9081 				strncpy(level->bossmusic, GET_ARG(1), 255);
9082 				level->bossmusic_offset = atol(GET_ARG(2));
9083 				break;
9084 			case CMD_LEVEL_NOPAUSE:
9085 				nopause = GET_INT_ARG(1);
9086 				break;
9087 			case CMD_LEVEL_NOSCREENSHOT:
9088 				noscreenshot = GET_INT_ARG(1);
9089 				break;
9090 			case CMD_LEVEL_SETTIME:
9091 				// If settime is found, overwrite the default 100 for time limit
9092 				level->settime = GET_INT_ARG(1);
9093 				if(level->settime > 100 || level->settime < 0) level->settime = 100;
9094 				// Feb 25, 2005 - Time limit loaded from individual .txt file
9095 				break;
9096 			case CMD_LEVEL_SETWEAP:
9097 				// Specify a weapon for each level
9098 				level->setweap = GET_INT_ARG(1);
9099 				break;
9100 			case CMD_LEVEL_NOTIME:
9101 				// Flag to if the time should be displayed 1 = no, else yes
9102 				level->notime = GET_INT_ARG(1);
9103 				break;
9104 			case CMD_LEVEL_NORESET:
9105 				// Flag to if the time should be reset when players respawn 1 = no, else yes
9106 				level->noreset = GET_INT_ARG(1);
9107 				break;
9108 			case CMD_LEVEL_NOSLOW:
9109 				// If set, level will not slow down when bosses are defeated
9110 				level->noslow = GET_INT_ARG(1);
9111 				break;
9112 			case CMD_LEVEL_TYPE:
9113 				level->type = GET_INT_ARG(1);    // Level type - 1 = bonus, else regular
9114 				level->nospecial = GET_INT_ARG(2);    // Can use specials during bonus levels (default 0 - yes)
9115 				level->nohurt = GET_INT_ARG(3);    // Can hurt other players during bonus levels (default 0 - yes)
9116 				break;
9117 			case CMD_LEVEL_NOHIT:
9118 				level->nohit = GET_INT_ARG(1);
9119 				break;
9120 			case CMD_LEVEL_GRAVITY:
9121 				level->gravity = GET_FLOAT_ARG(1);
9122 				level->gravity /= 100;
9123 				break;
9124 			case CMD_LEVEL_MAXFALLSPEED:
9125 				level->maxfallspeed = GET_FLOAT_ARG(1);
9126 				level->maxfallspeed /= 10;
9127 				break;
9128 			case CMD_LEVEL_MAXTOSSSPEED:
9129 				level->maxtossspeed = GET_FLOAT_ARG(1);
9130 				level->maxtossspeed /= 10;
9131 				break;
9132 			case CMD_LEVEL_CAMERATYPE:
9133 				cameratype = GET_INT_ARG(1);
9134 				break;
9135 			case CMD_LEVEL_CAMERAOFFSET:
9136 				level->cameraxoffset = GET_INT_ARG(1);
9137 				level->camerazoffset = GET_INT_ARG(2);
9138 				break;
9139 			case CMD_LEVEL_SPAWN1: case CMD_LEVEL_SPAWN2: case CMD_LEVEL_SPAWN3: case CMD_LEVEL_SPAWN4:
9140 				switch(cmd) {
9141 					case CMD_LEVEL_SPAWN1: i = 0; break;
9142 					case CMD_LEVEL_SPAWN2: i = 1; break;
9143 					case CMD_LEVEL_SPAWN3: i = 2; break;
9144 					case CMD_LEVEL_SPAWN4: i = 3; break;
9145 					default:
9146 						assert(0);
9147 				}
9148 				level->spawn[i][0] = GET_INT_ARG(1);
9149 				level->spawn[i][1] = GET_INT_ARG(2);
9150 				level->spawn[i][2] = GET_INT_ARG(3);
9151 
9152 				if(level->spawn[i][1] > 232 || level->spawn[i][1] < 0) level->spawn[i][1] = 232;
9153 				if(level->spawn[i][2] < 0) level->spawn[i][2] = 300;
9154 				break;
9155 			case CMD_LEVEL_FRONTPANEL:
9156 				value = GET_ARG(1);
9157 				if(!loadfrontpanel(value)) shutdown(1, "Unable to load '%s'!", value);
9158 				break;
9159 			case CMD_LEVEL_PANEL:
9160 				if(!loadpanel(GET_ARG(1), GET_ARG(2), GET_ARG(3)))  {
9161 					printf("loadpanel :%s :%s :%s failed\n", GET_ARG(1), GET_ARG(2), GET_ARG(3));
9162 					errormessage = "Panel load error!";
9163 					goto lCleanup;
9164 				}
9165 				break;
9166 			case CMD_LEVEL_STAGENUMBER:
9167 				current_stage = GET_INT_ARG(1);
9168 				break;
9169 			case CMD_LEVEL_ORDER:
9170 				// Append to order
9171 				if(panels_loaded<1) {
9172 					errormessage = "You must load the panels before entering the level layout!";
9173 					goto lCleanup;
9174 				}
9175 
9176 				value = GET_ARG(1);
9177 				i = 0;
9178 				while(value[i] && level->numpanels < LEVEL_MAX_PANELS){
9179 					j = value[i];
9180 					// WTF ?
9181 					if(j>='A' && j<='Z') j-='A';
9182 					else if(j>='a' && j<='z') j-='a';
9183 					else {
9184 						errormessage = "Illegal character in panel order!";
9185 						goto lCleanup;
9186 					}
9187 
9188 					if(j >= panels_loaded) {
9189 						errormessage = "Illegal panel index, index is bigger than number of loaded panels.";
9190 						goto lCleanup;
9191 					}
9192 
9193 					level->order[level->numpanels] = j;
9194 					level->numpanels++;
9195 					i++;
9196 				}
9197 				break;
9198 			case CMD_LEVEL_HOLE:
9199 				value = GET_ARG(1);    // ltb    1-18-05  adjustable hole sprites
9200 
9201 				if(holesprite < 0) {
9202 					if(testpackfile(value, packfile) >= 0) holesprite = loadsprite(value,0,0,pixelformat);// ltb 1-18-05  load new hole sprite
9203 					else holesprite = loadsprite("data/sprites/hole",0,0,pixelformat);    // ltb 1-18-05  no new sprite load the default
9204 				}
9205 
9206 				if(level->numholes >= LEVEL_MAX_HOLES) {
9207 					errormessage = "Too many holes in level (check LEVEL_MAX_HOLES)!";
9208 					goto lCleanup;
9209 				}
9210 				level->holes[level->numholes][0] = GET_FLOAT_ARG(1);
9211 				level->holes[level->numholes][1] = GET_FLOAT_ARG(2);
9212 				level->holes[level->numholes][2] = GET_FLOAT_ARG(3);
9213 				level->holes[level->numholes][3] = GET_FLOAT_ARG(4);
9214 				level->holes[level->numholes][4] = GET_FLOAT_ARG(5);
9215 				level->holes[level->numholes][5] = GET_FLOAT_ARG(6);
9216 				level->holes[level->numholes][6] = GET_FLOAT_ARG(7);
9217 
9218 				if(!level->holes[level->numholes][1]) level->holes[level->numholes][1] = 240;
9219 				if(!level->holes[level->numholes][2]) level->holes[level->numholes][2] = 12;
9220 				if(!level->holes[level->numholes][3]) level->holes[level->numholes][3] = 1;
9221 				if(!level->holes[level->numholes][4]) level->holes[level->numholes][4] = 200;
9222 				if(!level->holes[level->numholes][5]) level->holes[level->numholes][5] = 287;
9223 				if(!level->holes[level->numholes][6]) level->holes[level->numholes][6] = 45;
9224 				level->numholes++;
9225 				break;
9226 			case CMD_LEVEL_WALL:
9227 				if(level->numwalls >= LEVEL_MAX_WALLS) {
9228 					errormessage = "Too many walls in level (check LEVEL_MAX_WALLS)!";
9229 					goto lCleanup;
9230 				}
9231 				level->walls[level->numwalls][0] = GET_FLOAT_ARG(1);
9232 				level->walls[level->numwalls][1] = GET_FLOAT_ARG(2);
9233 				level->walls[level->numwalls][2] = GET_FLOAT_ARG(3);
9234 				level->walls[level->numwalls][3] = GET_FLOAT_ARG(4);
9235 				level->walls[level->numwalls][4] = GET_FLOAT_ARG(5);
9236 				level->walls[level->numwalls][5] = GET_FLOAT_ARG(6);
9237 				level->walls[level->numwalls][6] = GET_FLOAT_ARG(7);
9238 				level->walls[level->numwalls][7] = GET_FLOAT_ARG(8);
9239 				level->numwalls++;
9240 				break;
9241 			case CMD_LEVEL_PALETTE:
9242 				if(level->numpalettes >= LEVEL_MAX_PALETTES) {
9243 					errormessage = "Too many palettes in level (check LEVEL_MAX_PALETTES)!";
9244 					goto lCleanup;
9245 				}
9246 				for(i=0; i<MAX_BLENDINGS; i++)
9247 				usemap[i] = GET_INT_ARG(i+2);
9248 				if(!load_palette(level->palettes[level->numpalettes], GET_ARG(1)) ||
9249 				!create_blending_tables(level->palettes[level->numpalettes], level->blendings[level->numpalettes], usemap))
9250 				{
9251 					errormessage = "Failed to create colour conversion tables for level! (Out of memory?)";
9252 					goto lCleanup;
9253 				}
9254 				level->numpalettes++;
9255 				break;
9256 			case CMD_LEVEL_UPDATESCRIPT: case CMD_LEVEL_UPDATEDSCRIPT: case CMD_LEVEL_KEYSCRIPT:
9257 			case CMD_LEVEL_LEVELSCRIPT: case CMD_LEVEL_ENDLEVELSCRIPT:
9258 				switch(cmd) {
9259 					case CMD_LEVEL_UPDATESCRIPT:
9260 						tempscript = &(level->update_script);
9261 						scriptname = "levelupdatescript";
9262 						break;
9263 					case CMD_LEVEL_UPDATEDSCRIPT:
9264 						tempscript = &(level->updated_script);
9265 						scriptname = "levelupdatedscript";
9266 						break;
9267 					case CMD_LEVEL_KEYSCRIPT:
9268 						tempscript = &(level->key_script);
9269 						scriptname = "levelkeyscript";
9270 						break;
9271 					case CMD_LEVEL_LEVELSCRIPT:
9272 						tempscript = &(level->level_script);
9273 						scriptname = command;
9274 						break;
9275 					case CMD_LEVEL_ENDLEVELSCRIPT:
9276 						tempscript = &(level->endlevel_script);
9277 						scriptname = command;
9278 						break;
9279 					default:
9280 						assert(0);
9281 
9282 				}
9283 				value = GET_ARG(1);
9284 				if(!Script_IsInitialized(tempscript))
9285 					Script_Init(tempscript, scriptname, 1);
9286 				else {
9287 					errormessage = "Multiple level script!";
9288 					goto lCleanup;
9289 				}
9290 				if(load_script(tempscript, value))
9291 					Script_Compile(tempscript);
9292 				else {
9293 					errormessage = "Failed loading script!";
9294 					goto lCleanup;
9295 				}
9296 				break;
9297 			case CMD_LEVEL_BLOCKED:
9298 				level->exit_blocked = GET_INT_ARG(1);
9299 				break;
9300 			case CMD_LEVEL_ENDHOLE:
9301 				level->exit_hole = GET_INT_ARG(1);
9302 				break;
9303 			case CMD_LEVEL_WAIT:
9304 				// Clear spawn thing, set wait state instead
9305 				memset(&next,0,sizeof(s_spawn_entry));
9306 				next.wait = 1;
9307 				break;
9308 			case CMD_LEVEL_NOJOIN: case CMD_LEVEL_CANJOIN:
9309 				// Clear spawn thing, set nojoin state instead
9310 				memset(&next,0,sizeof(s_spawn_entry));
9311 				next.nojoin = 1;
9312 				break;
9313 			case CMD_LEVEL_SHADOWCOLOR:
9314 				memset(&next,0,sizeof(s_spawn_entry));
9315 				next.shadowcolor = GET_INT_ARG(1);
9316 				break;
9317 			case CMD_LEVEL_SHADOWALPHA:
9318 				memset(&next,0,sizeof(s_spawn_entry));
9319 				next.shadowalpha = GET_INT_ARG(1);
9320 				if(blendfx_is_set==0 && next.shadowalpha>0) blendfx[next.shadowalpha-1] = 1;
9321 				break;
9322 			case CMD_LEVEL_LIGHT:
9323 				memset(&next,0,sizeof(s_spawn_entry));
9324 				next.light[0] = GET_INT_ARG(1);
9325 				next.light[1] = GET_INT_ARG(2);
9326 				if(next.light[1] == 0) next.light[1] = 64;
9327 				break;
9328 			case CMD_LEVEL_SCROLLZ: case CMD_LEVEL_SCROLLX:
9329 				// now z scroll can be limited by this
9330 				// if the level is vertical, use scrollx, only different in name ..., but makes more sense
9331 				memset(&next,0,sizeof(s_spawn_entry));
9332 				next.scrollminz = GET_INT_ARG(1);
9333 				next.scrollmaxz = GET_INT_ARG(2);
9334 				if(next.scrollminz <= 0) next.scrollminz = 4;
9335 				if(next.scrollmaxz <= 0) next.scrollmaxz = 4;
9336 				break;
9337 			case CMD_LEVEL_BLOCKADE:
9338 				// now x scroll can be limited by this
9339 				memset(&next,0,sizeof(s_spawn_entry));
9340 				next.blockade = GET_INT_ARG(1);
9341 				if(next.blockade==0) next.blockade = -1;
9342 				break;
9343 			case CMD_LEVEL_SETPALETTE:
9344 				// change system palette
9345 				memset(&next,0,sizeof(s_spawn_entry));
9346 				next.palette = GET_INT_ARG(1);
9347 				break;
9348 			case CMD_LEVEL_GROUP:
9349 				// Clear spawn thing, set group instead
9350 				memset(&next,0,sizeof(s_spawn_entry));
9351 				next.groupmin = GET_INT_ARG(1);
9352 				next.groupmax = GET_INT_ARG(2);
9353 				if(next.groupmax < 1) next.groupmax = 1;
9354 				if(next.groupmin < 1) next.groupmin = 100;
9355 				break;
9356 			case CMD_LEVEL_SPAWN:
9357 				// Back to defaults
9358 				next.spawnplayer_count = 0;
9359 				memset(&next,0,sizeof(s_spawn_entry));
9360 				next.index = next.itemindex = next.weaponindex = -1;
9361 				// Name of entry to be spawned
9362 				// Load model (if not loaded already)
9363 				cached_model = findmodel(GET_ARG(1));
9364 				#ifdef DEBUG
9365 				printf("load_level: spawn %s, %s, cached: %p\n", GET_ARG(1), filename, cached_model);
9366 				#endif
9367 				if(cached_model) tempmodel = cached_model;
9368 				else tempmodel = load_cached_model(GET_ARG(1), filename, 0);
9369 				if(tempmodel)
9370 				{
9371 					next.name = tempmodel->name;
9372 					next.index = get_cached_model_index(next.name);
9373 					next.spawntype = 1;     //2011_03_23, DC; Spawntype 1 (level spawn).
9374 					crlf = 1;
9375 				}
9376 				break;
9377 			case CMD_LEVEL_2PSPAWN:
9378 				// Entity only for 2p game
9379 				next.spawnplayer_count = 1;
9380 				break;
9381 			case CMD_LEVEL_3PSPAWN:
9382 				// Entity only for 3p game
9383 				next.spawnplayer_count = 2;
9384 				break;
9385 			case CMD_LEVEL_4PSPAWN:
9386 				// Entity only for 4p game
9387 				next.spawnplayer_count = 3;
9388 				break;
9389 			case CMD_LEVEL_BOSS:
9390 				next.boss = GET_INT_ARG(1);
9391 				level->bosses += next.boss ? 1 : 0;
9392 				break;
9393 			case CMD_LEVEL_FLIP:
9394 				next.flip = GET_INT_ARG(1);
9395 				break;
9396 			case CMD_LEVEL_HEALTH:
9397 				next.health[0] = next.health[1] = next.health[2] = next.health[3] = GET_INT_ARG(1);
9398 				break;
9399 			case CMD_LEVEL_2PHEALTH:
9400 				// Health the spawned entity will have if 2 people are playing
9401 				next.health[1] = next.health[2] = next.health[3] = GET_INT_ARG(1);
9402 				break;
9403 			case CMD_LEVEL_3PHEALTH:
9404 				// Health the spawned entity will have if 2 people are playing
9405 				next.health[2] = next.health[3] = GET_INT_ARG(1);  //4player
9406 				break;
9407 			case CMD_LEVEL_4PHEALTH:
9408 				// Health the spawned entity will have if 2 people are playing
9409 				next.health[3] = GET_INT_ARG(1);  //4player
9410 				break;
9411 			case CMD_LEVEL_MP:
9412 				// mp values to put max mp for player by tails
9413 				next.mp = GET_INT_ARG(1);
9414 				break;
9415 			case CMD_LEVEL_SCORE:
9416 				// So score can be overriden in the levels .txt file
9417 				next.score = GET_INT_ARG(1);
9418 				if(next.score < 0) next.score = 0;    // So negative values cannot be added
9419 				next.multiple = GET_INT_ARG(2);
9420 				if(next.multiple < 0) next.multiple = 0;    // So negative values cannot be added
9421 				break;
9422 			case CMD_LEVEL_NOLIFE:
9423 				// Flag to determine if entity life is shown when hit
9424 				next.nolife = GET_INT_ARG(1);
9425 				break;
9426 			case CMD_LEVEL_ALIAS:
9427 				// Alias (name displayed) of entry to be spawned
9428 				strncpy(next.alias, GET_ARG(1), MAX_NAME_LEN);
9429 				break;
9430 			case CMD_LEVEL_MAP:
9431 				// Colourmap for new entry
9432 				next.colourmap = GET_INT_ARG(1);
9433 				break;
9434 			case CMD_LEVEL_ALPHA:
9435 				// Item to be contained by new entry
9436 				next.alpha = GET_INT_ARG(1);
9437 				if(blendfx_is_set==0 && next.alpha) blendfx[next.alpha-1] = 1;
9438 				break;
9439 			case CMD_LEVEL_DYING:
9440 				// Used to store which remake corresponds with the dying flash
9441 				next.dying = GET_INT_ARG(1);
9442 				next.per1 = GET_INT_ARG(2);
9443 				next.per2 = GET_INT_ARG(3);
9444 				break;
9445 			case CMD_LEVEL_ITEM: case CMD_LEVEL_2PITEM: case CMD_LEVEL_3PITEM: case CMD_LEVEL_4PITEM:
9446 				switch(cmd) {
9447 					// Item to be contained by new entry
9448 					case CMD_LEVEL_ITEM:   next.itemplayer_count = 0; break;
9449 					case CMD_LEVEL_2PITEM: next.itemplayer_count = 1; break;
9450 					case CMD_LEVEL_3PITEM: next.itemplayer_count = 2; break;
9451 					case CMD_LEVEL_4PITEM: next.itemplayer_count = 3; break;
9452 					default: assert(0);
9453 				}
9454 				// Load model (if not loaded already)
9455 				cached_model = findmodel(GET_ARG(1));
9456 				if(cached_model)
9457 					tempmodel = cached_model;
9458 				else
9459 					tempmodel = load_cached_model(GET_ARG(1), filename, 0);
9460 				if(tempmodel) {
9461 					next.item = tempmodel->name;
9462 					next.itemindex = get_cached_model_index(next.item);
9463 				}
9464 				break;
9465 			case CMD_LEVEL_ITEMMAP:
9466 				next.itemmap = GET_INT_ARG(1);
9467 				break;
9468 			case CMD_LEVEL_ITEMHEALTH:
9469 				next.itemhealth = GET_INT_ARG(1);
9470 				break;
9471 			case CMD_LEVEL_ITEMALIAS:
9472 				strncpy(next.itemalias, GET_ARG(1), MAX_NAME_LEN);
9473 				break;
9474 			case CMD_LEVEL_WEAPON:
9475 				//spawn with a weapon 2007-2-12 by UTunnels
9476 				// Load model (if not loaded already)
9477 				cached_model = findmodel(GET_ARG(1));
9478 				if(cached_model) tempmodel = cached_model;
9479 				else tempmodel = load_cached_model(GET_ARG(1), filename, 0);
9480 				if(tempmodel) {
9481 					next.weapon = tempmodel->name;
9482 					next.weaponindex = get_cached_model_index(next.weapon);
9483 				}
9484 				break;
9485 			case CMD_LEVEL_AGGRESSION:
9486 				// Aggression can be set per spawn.
9487 				next.aggression = next.aggression + GET_INT_ARG(1);
9488 				break;
9489 			case CMD_LEVEL_CREDIT:
9490 				next.credit = GET_INT_ARG(1);
9491 				break;
9492 			case CMD_LEVEL_ITEMTRANS: case CMD_LEVEL_ITEMALPHA:
9493 				next.itemtrans = GET_INT_ARG(1);
9494 				break;
9495 			case CMD_LEVEL_COORDS:
9496 				next.x = GET_FLOAT_ARG(1);
9497 				next.z = GET_FLOAT_ARG(2);
9498 				next.a = GET_FLOAT_ARG(3);
9499 				break;
9500 			case CMD_LEVEL_SPAWNSCRIPT:
9501 				errormessage = llHandleCommandSpawnscript(&arglist, &next);
9502 				if (errormessage)
9503 					goto lCleanup;
9504 				break;
9505 			case CMD_LEVEL_AT:
9506 				// Place entry on queue
9507 				next.at = GET_INT_ARG(1);
9508 
9509 				if(level->numspawns >= LEVEL_MAX_SPAWNS) {
9510 					errormessage = "too many spawn entries (see LEVEL_MAX_SPAWNS)";
9511 					goto lCleanup;
9512 				}
9513 
9514 				memcpy(&level->spawnpoints[level->numspawns], &next, sizeof(s_spawn_entry));
9515 				level->numspawns++;
9516 
9517 				// And clear...
9518 				memset(&next,0,sizeof(s_spawn_entry));
9519 				break;
9520 			default:
9521 				if(command && command[0])
9522 					printf("Command '%s' not understood!", command);
9523 		}
9524 
9525 		// Go to next line
9526 		pos += getNewLineStart(buf + pos);
9527 
9528 		if(isLoadingScreenTypeBar(bgPosi.set) || isLoadingScreenTypeBg(bgPosi.set))
9529 			update_loading(&bgPosi, pos, size);
9530 			//update_loading(bgPosi[0]+videomodes.hShift, bgPosi[1]+videomodes.vShift, bgPosi[2], bgPosi[3]+videomodes.hShift, bgPosi[4]+videomodes.vShift, pos, size, bgPosi[5]);
9531 		else
9532 			update_loading(&loadingbg[1], pos, size);
9533 	}
9534 
9535 	if(level->numpanels < 1) {
9536 		errormessage = "Level error: level has no panels";
9537 		goto lCleanup;
9538 	}
9539 
9540 	if(bgPath[0])
9541 	{
9542 		clearscreen(vscreen);
9543 		spriteq_clear();
9544 		load_background(bgPath, 1);
9545 		level->bglayers[0].screen=background;
9546 		level->bglayers[0].width=background->width;
9547 		//if(!level->bglayers[0].xoffset && level->bglayers[0].xrepeat<5000)level->bglayers[0].xoffset=-background->width;
9548 		level->bglayers[0].height=background->height;
9549 	}
9550 	else
9551 	{
9552 		if(level->numbglayers>1)
9553 			level->bglayers[0] = level->bglayers[--level->numbglayers];
9554 		else
9555 			level->numbglayers = 0;
9556 
9557 		if(background) unload_background();
9558 	}
9559 
9560 	if(level->numbglayers) {
9561 		load_bglayer(NULL, 0); // initialize background height and width and looping
9562 
9563 		for(i=1; i<level->numbglayers; i++){
9564 			if(level->bglayers[i].zoffset == 1234567890){ // default water hack
9565 				level->bglayers[i].zoffset = level->bglayers[0].height;
9566 				dm = &(level->bglayers[i].drawmethod);
9567 				if(level->rocking) {
9568 					dm->water.watermode =3;
9569 					dm->water.beginsize = 1.0;
9570 					dm->water.endsize = 1 + level->bglayers[0].height/11.0;
9571 					dm->water.perspective = 0;
9572 					level->bglayers[i].bgspeedratio =2;
9573 				}
9574 			}
9575 		}
9576 
9577 	}
9578 
9579 	if(pixelformat==PIXEL_x8)
9580 	{
9581 			if(level->numbglayers>0) bgbuffer = allocscreen(videomodes.hRes, videomodes.vRes, screenformat);
9582 	}
9583 	bgbuffer_updated = 0;
9584 	if(musicPath[0]) music(musicPath, 1, musicOffset);
9585 
9586 	timeleft = level->settime * COUNTER_SPEED;    // Feb 24, 2005 - This line moved here to set custom time
9587 	level->width = level->numpanels * panel_width;
9588 
9589 	if(level->width<videomodes.hRes) level->width = videomodes.hRes;
9590 
9591 	if(level->scrolldir&SCROLL_LEFT)
9592 		advancex = (float)(level->width-videomodes.hRes);
9593 	else if(level->scrolldir&SCROLL_INWARD)
9594 		advancey = (float)(panel_height-videomodes.vRes);
9595 
9596 	if(crlf) printf("\n");
9597 	printf("Level Loaded:    '%s'\n", level->name);
9598 	totalram = getSystemRam(BYTES); freeram = getFreeRam(BYTES); usedram = getUsedRam(BYTES);
9599 	printf("Total Ram: %"PRIu64" Bytes\n Free Ram: %"PRIu64" Bytes\n Used Ram: %"PRIu64" Bytes\n\n", totalram, freeram, usedram);
9600 
9601 	lCleanup:
9602 
9603 	if(buf != NULL)
9604 		free(buf);
9605 
9606 	if(errormessage)
9607 		shutdown(1, "ERROR: load_level, file %s, line %d, message: %s", filename, line, errormessage);
9608 }
9609 
9610 
9611 
9612 
9613 
9614 /////////////////////////////////////////////////////////////////////////////
9615 //  Status                                                                  //
9616 /////////////////////////////////////////////////////////////////////////////
bar(int x,int y,int value,int maxvalue,s_barstatus * pstatus)9617 void bar(int x, int y, int value, int maxvalue, s_barstatus* pstatus)
9618 {
9619 	int max = 100, len, alphabg=0, bgindex, colourindex;
9620 	int forex, forey, forew,foreh, bkw, bkh;
9621 
9622 	x += pstatus->offsetx;
9623 	y += pstatus->offsety;
9624 
9625 	if(pstatus->orientation==horizontalbar)    max = pstatus->sizex;
9626 	else if(pstatus->orientation==verticalbar) max = pstatus->sizey;
9627 	else return;
9628 
9629 	if (value < 0) value = 0;
9630 	if (value > maxvalue) value = maxvalue;
9631 
9632 	if(pstatus->type==valuebar)
9633 	{
9634 		if(max>maxvalue) max = maxvalue;
9635 		if(colorbars)
9636 		{
9637 			if(value<=max/4) {bgindex = 0; colourindex = 1;}
9638 			else if(value<=max/2) {bgindex=0; colourindex = 2;}
9639 			else if(value<=max) {bgindex=0; colourindex = 3;}
9640 			else {colourindex = value/(max+1) + 3; bgindex = colourindex-1;}
9641 			if(colourindex>10) colourindex = bgindex = 10;
9642 		}
9643 		else
9644 		{
9645 			colourindex = 2;
9646 			bgindex = value>max? 5:1;
9647 		}
9648 
9649 		len = value%max;
9650 		if(!len && value) len = max;
9651 		alphabg = value>max?0:(BLEND_MULTIPLY+1);
9652 	}
9653 	else if(pstatus->type==percentagebar)
9654 	{
9655 		colourindex = colorbars?(value*5/maxvalue+1):2;
9656 		bgindex = colorbars?8:1;
9657 		len = value * max / maxvalue;
9658 		if(!len && value) len = 1;
9659 		alphabg = BLEND_MULTIPLY+1;
9660 	}
9661 	else return;
9662 
9663 	if(pstatus->orientation==horizontalbar)
9664 	{
9665 		forex = pstatus->direction?(x + max - len):x;
9666 		forey = y;
9667 		forew = len; bkw = max;
9668 		bkh = foreh = pstatus->sizey;
9669 	}
9670 	else if(pstatus->orientation==verticalbar)
9671 	{
9672 		forex = x;
9673 		forey = pstatus->direction?y:(y + max - len);
9674 		bkw = forew = pstatus->sizex;
9675 		foreh = len; bkh = max;
9676 	}
9677 	else return;
9678 
9679 	if(!pstatus->colourtable) pstatus->colourtable = &hpcolourtable;
9680 
9681 	spriteq_add_box(x+1, y+1, bkw, bkh, HUD_Z+1+pstatus->backlayer, (*pstatus->colourtable)[bgindex], alphabg);
9682 	spriteq_add_box(forex+1, forey+1, forew, foreh, HUD_Z+2+pstatus->barlayer, (*pstatus->colourtable)[colourindex], 0);
9683 
9684 	if(pstatus->noborder==0)
9685 	{
9686 		spriteq_add_line(x, y, x+bkw+1, y, HUD_Z+3+pstatus->borderlayer, color_white, 0); //Top border.
9687 		spriteq_add_line(x, y+bkh+1, x+bkw+1, y+bkh+1, HUD_Z+3+pstatus->borderlayer, color_white, 0); //Bottom border.
9688 		spriteq_add_line(x, y+1, x, y+bkh, HUD_Z+3+pstatus->borderlayer, color_white, 0); //Left border.
9689 		spriteq_add_line(x+bkw+1, y+1, x+bkw+1, y+bkh, HUD_Z+3+pstatus->borderlayer, color_white, 0); //Right border.
9690 		spriteq_add_line(x, y+bkh+2, x+bkw+1, y+bkh+2, HUD_Z+pstatus->borderlayer, color_black, 0); //Bottom shadow.
9691 		spriteq_add_line(x+bkw+2, y+1, x+bkw+2, y+bkh+2, HUD_Z+pstatus->borderlayer, color_black, 0); //Right shadow.
9692 	}
9693 }
9694 
9695 
pausemenu()9696 void pausemenu()
9697 {
9698 	int pauselector = 0;
9699 	int quit = 0;
9700 
9701 	pause = 2;
9702 	bothnewkeys = 0;
9703 	while(!quit)
9704 	{
9705 		_menutextm(3, -2, 0, "Pause");
9706 		_menutextm((pauselector==0), -1, 0, "Continue");
9707 		_menutextm((pauselector==1), 0, 0, "End Game");
9708 
9709 		update(1,0);
9710 
9711 		if(bothnewkeys & (FLAG_MOVEUP|FLAG_MOVEDOWN)){
9712 			pauselector ^= 1;
9713 			sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
9714 		}
9715 		if(bothnewkeys & FLAG_START){
9716 			if(pauselector){
9717 				player[0].lives = player[1].lives = player[2].lives = player[3].lives = 0; //4player
9718 				endgame = 1;
9719 			}
9720 			quit = 1;
9721 			sound_pause_music(0);
9722 			sound_pause_sample(0);
9723 			sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
9724 			pauselector = 0;
9725 		}
9726 		if(bothnewkeys & FLAG_ESC){
9727 			quit = 1;
9728 			sound_pause_music(0);
9729 			sound_pause_sample(0);
9730 			sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
9731 			pauselector = 0;
9732 		}
9733 		if(bothnewkeys & FLAG_SCREENSHOT){
9734 			pause = 1;
9735 			sound_pause_music(1);
9736 			sound_pause_sample(1);
9737 			sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
9738 			options();
9739 		}
9740 	}
9741 	pause = 0;
9742 	bothnewkeys = 0;
9743 	spriteq_unlock();
9744 }
9745 
getFPS(void)9746 unsigned getFPS(void)
9747 {
9748 	static unsigned lasttick=0,framerate = 0;
9749 	unsigned curtick = timer_gettick();
9750 	if(lasttick > curtick) lasttick = curtick;
9751 	framerate = (framerate + (curtick-lasttick))/2;
9752 	lasttick = curtick;
9753 	if(!framerate) return 0;
9754 #ifdef PSP
9755 	return ((10000000/framerate)+9)/10;
9756 #else
9757 	return ((10000000/framerate)+9)/10000;
9758 #endif
9759 }
9760 
predrawstatus()9761 void predrawstatus(){
9762 
9763 	int dt;
9764 	int tperror=0;
9765 	int icon = 0;
9766 	int i,x;
9767 	unsigned long tmp;
9768 
9769 	s_model * model = NULL;
9770 	s_drawmethod drawmethod = plainmethod;
9771 
9772 	if(bgicon >= 0) spriteq_add_sprite(videomodes.hShift+bgicon_offsets[0],savedata.windowpos+bgicon_offsets[1], bgicon_offsets[2], bgicon, NULL, 0);
9773 	if(olicon >= 0) spriteq_add_sprite(videomodes.hShift+olicon_offsets[0],savedata.windowpos+olicon_offsets[1], olicon_offsets[2], olicon, NULL, 0);
9774 
9775 	for(i=0; i<maxplayers[current_set]; i++)
9776 	{
9777 		if(player[i].ent)
9778 		{
9779 		tmp = player[i].score; //work around issue on 64bit where sizeof(long) != sizeof(int)
9780 			if(!pscore[i][2] && !pscore[i][3] && !pscore[i][4] && !pscore[i][5])
9781 		    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);
9782 			else
9783 			{
9784 				font_printf(videomodes.shiftpos[i]+pscore[i][0], savedata.windowpos+pscore[i][1], pscore[i][6], 0, "%s", player[i].ent->name);
9785 				font_printf(videomodes.shiftpos[i]+pscore[i][2], savedata.windowpos+pscore[i][3], pscore[i][6], 0, "-");
9786 				font_printf(videomodes.shiftpos[i]+pscore[i][4], savedata.windowpos+pscore[i][5], pscore[i][6], 0, (scoreformat ? "%09lu" : "%lu"), tmp);
9787 			}
9788 
9789 			if(player[i].ent->health <= 0) icon = player[i].ent->modeldata.icon.die;
9790 			else if(player[i].ent->inpain) icon = player[i].ent->modeldata.icon.pain;
9791 			else if(player[i].ent->getting) icon = player[i].ent->modeldata.icon.get;
9792 			else icon = player[i].ent->modeldata.icon.def;
9793 
9794 			if(icon>=0)
9795 			{
9796 				drawmethod.table = player[i].ent->colourmap;
9797 				spriteq_add_sprite(videomodes.shiftpos[i]+picon[i][0],savedata.windowpos+picon[i][1],10000, icon, &drawmethod, 0);
9798 			}
9799 
9800 			if(player[i].ent->weapent)
9801 			{
9802 				if(player[i].ent->weapent->modeldata.icon.weapon >= 0)
9803 				{
9804 					drawmethod.table = player[i].ent->weapent->colourmap;
9805 					spriteq_add_sprite(videomodes.shiftpos[i]+piconw[i][0],savedata.windowpos+piconw[i][1],10000, player[i].ent->weapent->modeldata.icon.weapon, &drawmethod, 0);
9806 				}
9807 
9808 				if(player[i].ent->weapent->modeldata.typeshot && player[i].ent->weapent->modeldata.shootnum)
9809 					font_printf(videomodes.shiftpos[i]+pshoot[i][0], savedata.windowpos+pshoot[i][1], pshoot[i][2], 0, "%u", player[i].ent->weapent->modeldata.shootnum);
9810 			}
9811 
9812 			if(player[i].ent->modeldata.mp)
9813 			{
9814 				if(player[i].ent->modeldata.icon.mphigh > 0 && (player[i].ent->oldmp >= (player[i].ent->modeldata.mp * .66))){
9815 					drawmethod.table = player[i].ent->colourmap;
9816 					spriteq_add_sprite(videomodes.shiftpos[i]+mpicon[i][0],savedata.windowpos+mpicon[i][1],10000, player[i].ent->modeldata.icon.mphigh, &drawmethod, 0);
9817 				}
9818 				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))){
9819 					drawmethod.table = player[i].ent->colourmap;
9820 					spriteq_add_sprite(videomodes.shiftpos[i]+mpicon[i][0],savedata.windowpos+mpicon[i][1],10000, player[i].ent->modeldata.icon.mpmed, &drawmethod, 0);
9821 				}
9822 				else if(player[i].ent->modeldata.icon.mplow > 0 && (player[i].ent->oldmp >= 0 && player[i].ent->oldmp < (player[i].ent->modeldata.mp * .33))){
9823 					drawmethod.table = player[i].ent->colourmap;
9824 					spriteq_add_sprite(videomodes.shiftpos[i]+mpicon[i][0],savedata.windowpos+mpicon[i][1],10000, player[i].ent->modeldata.icon.mplow, &drawmethod, 0);
9825 				}
9826 				else if(player[i].ent->modeldata.icon.mphigh > 0 && player[i].ent->modeldata.icon.mpmed == -1 && player[i].ent->modeldata.icon.mplow == -1){
9827 					drawmethod.table = player[i].ent->colourmap;
9828 					spriteq_add_sprite(videomodes.shiftpos[i]+mpicon[i][0],savedata.windowpos+mpicon[i][1],10000, player[i].ent->modeldata.icon.mphigh, &drawmethod, 0);
9829 				}
9830 			}
9831 
9832 			font_printf(videomodes.shiftpos[i]+plifeX[i][0],savedata.windowpos+plifeX[i][1], plifeX[i][2], 0, "x");
9833 			font_printf(videomodes.shiftpos[i]+plifeN[i][0],savedata.windowpos+plifeN[i][1], plifeN[i][2], 0, "%i", player[i].lives);
9834 
9835 			if(rush[0] && player[i].ent->rush[0] > 1 && time <= player[i].ent->rushtime)
9836 			{
9837 				font_printf(videomodes.shiftpos[i]+prush[i][0],prush[i][1], rush[2], 0, "%s", rush_names[0]);
9838 				font_printf(videomodes.shiftpos[i]+prush[i][2],prush[i][3], rush[3], 0, "%i", player[i].ent->rush[0]);
9839 
9840 				if(rush[0] != 2){
9841 					font_printf(videomodes.shiftpos[i]+prush[i][4],prush[i][5], rush[4], 0, "%s", rush_names[1]);
9842 					font_printf(videomodes.shiftpos[i]+prush[i][6],prush[i][7], rush[5], 0, "%i", player[i].ent->rush[1]);
9843 				}
9844 			}
9845 
9846 			if(rush[0] == 2)
9847 			{
9848 				font_printf(videomodes.shiftpos[i]+prush[i][4],prush[i][5], rush[4], 0, "%s", rush_names[1]);
9849 				font_printf(videomodes.shiftpos[i]+prush[i][6],prush[i][7], rush[5], 0, "%i", player[i].ent->rush[1]);
9850 			}
9851 
9852 			if(player[i].ent->opponent && !player[i].ent->opponent->modeldata.nolife)
9853 			{    // Displays life unless overridden by flag
9854 				font_printf(videomodes.shiftpos[i]+ename[i][0], savedata.windowpos+ename[i][1], ename[i][2], 0, player[i].ent->opponent->name);
9855 				if(player[i].ent->opponent->health <= 0) icon = player[i].ent->opponent->modeldata.icon.die;
9856 				else if(player[i].ent->opponent->inpain) icon = player[i].ent->opponent->modeldata.icon.pain;
9857 				else if(player[i].ent->opponent->getting) icon = player[i].ent->opponent->modeldata.icon.get;
9858 				else icon = player[i].ent->opponent->modeldata.icon.def;
9859 
9860 				if(icon>=0)
9861 				{
9862 					drawmethod.table = player[i].ent->opponent->colourmap;
9863 					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
9864 				}
9865 			}
9866 		}
9867 		else if(player[i].joining && player[i].name[0])
9868 		{
9869 			model = findmodel(player[i].name);
9870 			font_printf(videomodes.shiftpos[i]+pnameJ[i][0], savedata.windowpos+pnameJ[i][1], pnameJ[i][6], 0, player[i].name);
9871 			if(nojoin) font_printf(videomodes.shiftpos[i]+pnameJ[i][2], savedata.windowpos+pnameJ[i][3], pnameJ[i][6], 0, "Please Wait");
9872 			else font_printf(videomodes.shiftpos[i]+pnameJ[i][2], savedata.windowpos+pnameJ[i][3], pnameJ[i][6], 0, "Select Hero");
9873 			icon = model->icon.def;
9874 
9875 			if(icon>=0 && !player[i].colourmap){
9876 				spriteq_add_sprite(videomodes.shiftpos[i]+picon[i][0],picon[i][1],10000, icon, NULL, 0);
9877 			}
9878 			else if(icon>=0)
9879 			{
9880 				drawmethod.table = model->colourmap[player[i].colourmap - 1];
9881 				spriteq_add_sprite(videomodes.shiftpos[i]+picon[i][0],picon[i][1], 10000, icon, &drawmethod, 0);
9882 			}
9883 
9884 
9885 			if((player[i].playkeys & FLAG_ANYBUTTON || (skipselect&&(*skipselect)[current_set][i])) && !freezeall && !nojoin)    // Can't join while animations are frozen
9886 			{
9887 				// reports error if players try to use the same character and sameplay mode is off
9888 				if(sameplayer){
9889 					for(x=0; x<maxplayers[current_set]; x++){
9890 						if((strncmp(player[i].name,player[x].name,strlen(player[i].name)) == 0) && (i != x)){
9891 							tperror = i+1;
9892 							break;
9893 						}
9894 					}
9895 				}
9896 
9897 				if (!tperror){    // Fixed so players can be selected if other player is no longer va //4player                        player[i].playkeys = player[i].newkeys = 0;
9898 					player[i].lives = PLAYER_LIVES;            // to address new lives settings
9899 					player[i].joining = 0;
9900 					player[i].hasplayed = 1;
9901 					player[i].spawnhealth = model->health;
9902 					player[i].spawnmp = model->mp;
9903 					spawnplayer(i);
9904 					execute_join_script(i);
9905 
9906 					player[i].playkeys = player[i].newkeys = player[i].releasekeys = 0;
9907 
9908 					if(!nodropen) drop_all_enemies();   //27-12-2004  If drop enemies is on, drop all enemies
9909 
9910 					if(!level->noreset) timeleft = level->settime * COUNTER_SPEED;    // Feb 24, 2005 - This line moved here to set custom time
9911 				}
9912 
9913 			}
9914 			else if(player[i].playkeys & FLAG_MOVELEFT)
9915 			{
9916 				player[i].colourmap = i;
9917 				model = prevplayermodel(model);
9918 				strcpy(player[i].name, model->name);
9919 
9920 				while(   // Keep looping until a non-hmap is found
9921 					((model->maps.hide_start) && (model->maps.hide_end) &&
9922 					player[i].colourmap >= model->maps.hide_start &&
9923 					player[i].colourmap <= model->maps.hide_end)
9924 					)
9925 					{
9926 						player[i].colourmap++;
9927 						if(player[i].colourmap > model->maps_loaded) player[i].colourmap = 0;
9928 					}
9929 
9930 				player[i].playkeys = 0;
9931 			}
9932 			else if(player[i].playkeys & FLAG_MOVERIGHT)
9933 			{
9934 				player[i].colourmap = i;
9935 				model = nextplayermodel(model);
9936 				strcpy(player[i].name, model->name);
9937 
9938 				while(   // Keep looping until a non-hmap is found
9939 					((model->maps.hide_start) && (model->maps.hide_end) &&
9940 					player[i].colourmap >= model->maps.hide_start &&
9941 					player[i].colourmap <= model->maps.hide_end)
9942 					)
9943 					{
9944 						player[i].colourmap++;
9945 						if(player[i].colourmap > model->maps_loaded) player[i].colourmap = 0;
9946 					}
9947 
9948 				player[i].playkeys = 0;
9949 
9950 			}
9951 			// don't like a characters color try a new one!
9952 			else if(player[i].playkeys & FLAG_MOVEUP && colourselect)
9953 			{
9954 
9955 				do{
9956 					player[i].colourmap++;
9957 
9958 					if(player[i].colourmap > model->maps_loaded) player[i].colourmap = 0;
9959 				}
9960 				while(    // Keep looping until a non frozen map is found
9961 					(model->maps.frozen &&
9962 					player[i].colourmap - 1 == model->maps.frozen - 1) ||
9963 					((model->maps.hide_start) && (model->maps.hide_end) &&
9964 					player[i].colourmap - 1 >= model->maps.hide_start - 1 &&
9965 					player[i].colourmap - 1 <= model->maps.hide_end - 1)
9966 					);
9967 
9968 					player[i].playkeys = 0;
9969 			}
9970 			else if(player[i].playkeys & FLAG_MOVEDOWN && colourselect)
9971 			{
9972 
9973 				do{
9974 					player[i].colourmap--;
9975 
9976 					if(player[i].colourmap < 0) player[i].colourmap = model->maps_loaded;
9977 				}
9978 				while(    // Keep looping until a non frozen map is found
9979 					(model->maps.frozen &&
9980 					player[i].colourmap - 1 == model->maps.frozen - 1) ||
9981 					((model->maps.hide_start) && (model->maps.hide_end) &&
9982 					player[i].colourmap - 1 >= model->maps.hide_start - 1 &&
9983 					player[i].colourmap - 1 <= model->maps.hide_end - 1)
9984 					);
9985 
9986 					player[i].playkeys = 0;
9987 			}
9988 		}
9989 		else if(player[i].credits || credits || (!player[i].hasplayed && noshare))
9990 		{
9991 			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);
9992 			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);
9993 			else if(nojoin) font_printf(videomodes.shiftpos[i]+pnameJ[i][4], savedata.windowpos+pnameJ[i][5], pnameJ[i][6], 0, "Please Wait");
9994 			else font_printf(videomodes.shiftpos[i]+pnameJ[i][4], savedata.windowpos+pnameJ[i][5], pnameJ[i][6], 0, "Press Start");
9995 
9996 			if(player[i].playkeys & FLAG_START)
9997 			{
9998 				player[i].lives = 0;
9999 				model = (skipselect&&(*skipselect)[current_set][i])?findmodel((*skipselect)[current_set][i]):nextplayermodel(NULL);
10000 				strncpy(player[i].name, model->name, MAX_NAME_LEN);
10001 				player[i].colourmap = i;
10002 				 // Keep looping until a non-hmap is found
10003 				while(model->maps.hide_start && model->maps.hide_end && player[i].colourmap >= model->maps.hide_start && player[i].colourmap <= model->maps.hide_end)
10004 				{
10005 					player[i].colourmap++;
10006 					if(player[i].colourmap > model->maps_loaded) player[i].colourmap = 0;
10007 				}
10008 
10009 				player[i].joining = 1;
10010 				player[i].playkeys = player[i].newkeys = player[i].releasekeys = 0;
10011 
10012 				if(!level->noreset) timeleft = level->settime * COUNTER_SPEED;    // Feb 24, 2005 - This line moved here to set custom time
10013 
10014 				if(!player[i].hasplayed && noshare) player[i].credits = CONTINUES;
10015 
10016 				if(!creditscheat)
10017 				{
10018 					if(noshare) --player[i].credits;
10019 					else --credits;
10020 					if(continuescore[current_set] == 1)player[i].score = 0;
10021 					if(continuescore[current_set] == 2)player[i].score = player[i].score+1;
10022 				}
10023 			}
10024 		}
10025 		else
10026 		{
10027 			font_printf(videomodes.shiftpos[i]+pnameJ[i][4], savedata.windowpos+pnameJ[i][5], pnameJ[i][6], 0, "GAME OVER");
10028 		}
10029 	}// end of for
10030 
10031 	if(savedata.debuginfo)
10032 	{
10033 		spriteq_add_box(0, videomodes.dOffset-12, videomodes.hRes, videomodes.dOffset+12, 0x0FFFFFFE, 0, 0);
10034 		font_printf(2,                   videomodes.dOffset-10, 0, 0, "FPS: %02d", getFPS());
10035 		font_printf(videomodes.hRes / 2, videomodes.dOffset-10, 0, 0, "Free Ram: %s KBytes", commaprint(freeram/1000));
10036 		font_printf(2,                   videomodes.dOffset,    0, 0, "Total Ram: %s KBytes", commaprint(totalram/1000));
10037 		font_printf(videomodes.hRes / 2, videomodes.dOffset,    0, 0, "Used Ram: %s KBytes", commaprint(usedram/1000));
10038 	}
10039 
10040 	dt = timeleft/COUNTER_SPEED;
10041 	if(dt>=99)
10042 	{
10043 		dt      = 99;
10044 
10045 		oldtime = 99;
10046 	}
10047 	if(dt<=0)
10048 	{
10049 		dt      = 0;
10050 		oldtime = 99;
10051 	}
10052 
10053 	if(dt < oldtime || oldtime == 0)
10054 	{
10055 		execute_timetick_script(dt, go_time);
10056 		oldtime = dt;
10057 	}
10058 
10059 	if(timeicon >= 0) spriteq_add_sprite(videomodes.hShift+timeicon_offsets[0], savedata.windowpos+timeicon_offsets[1],10000, timeicon, NULL, 0);
10060 	if(!level->notime) font_printf(videomodes.hShift+timeloc[0]+2, savedata.windowpos+timeloc[1]+2, timeloc[5], 0, "%02i", dt);
10061 	if(showtimeover) font_printf(videomodes.hShift+113, videomodes.vShift+savedata.windowpos+110, timeloc[5], 0, "TIME OVER");
10062 
10063 	if(dt<99) showtimeover = 0;
10064 
10065 	if(go_time>time)
10066 	{
10067 		dt = (go_time-time)%GAME_SPEED;
10068 
10069 		if(dt < GAME_SPEED/2){
10070 			if(level->scrolldir&SCROLL_LEFT){ //TODO: upward and downward go
10071 
10072 				if(golsprite >= 0) spriteq_add_sprite(40,60+videomodes.vShift,10000, golsprite, NULL, 0); // new sprite for left direction
10073 				else
10074 				{
10075 					drawmethod.table = 0;
10076 					drawmethod.flipx = 1;
10077 					spriteq_add_sprite(40,60+videomodes.vShift,10000, gosprite, &drawmethod, 0);
10078 				}
10079 
10080 				if(gosound == 0 ){
10081 
10082 					if(SAMPLE_GO >= 0) sound_play_sample(SAMPLE_GO, 0, savedata.effectvol,savedata.effectvol, 100);// 26-12-2004 Play go sample as arrow flashes
10083 
10084 					gosound = 1;                // 26-12-2004 Sets sample as already played - stops sample repeating too much
10085 				}
10086 			}
10087 			else if(level->scrolldir&SCROLL_RIGHT){
10088 				spriteq_add_sprite(videomodes.hRes-40,60+videomodes.vShift,10000, gosprite, NULL, 0);
10089 
10090 				if(gosound == 0 ){
10091 
10092 					if(SAMPLE_GO >= 0) sound_play_sample(SAMPLE_GO, 0, savedata.effectvol,savedata.effectvol, 100); // 26-12-2004 Play go sample as arrow flashes
10093 
10094 					gosound = 1;  // 26-12-2004 Sets sample as already played - stops sample repeating too much
10095 				}
10096 			}
10097 		}
10098 		else gosound = 0;    //26-12-2004 Resets go sample after loop so it can be played again next time
10099 	}
10100 
10101 }
10102 
10103 // draw boss status on screen
drawenemystatus(entity * ent)10104 void drawenemystatus(entity* ent)
10105 {
10106 	s_drawmethod drawmethod;
10107 	int icon;
10108 
10109 	if(ent->modeldata.namex>-1000 && ent->modeldata.namey>-1000) font_printf(ent->modeldata.namex, ent->modeldata.namey, 0, 0, "%s", ent->name);
10110 
10111 	if(ent->modeldata.icon.x>-1000 &&  ent->modeldata.icon.y>-1000)
10112 	{
10113 		if(ent->health <= 0) icon = ent->modeldata.icon.die;
10114 		else if(ent->inpain) icon = ent->modeldata.icon.pain;
10115 		else if(ent->getting) icon = ent->modeldata.icon.get;
10116 		else icon = ent->modeldata.icon.def;
10117 
10118 		if(icon>=0)
10119 		{
10120 			drawmethod = plainmethod;
10121 			drawmethod.table = ent->colourmap;
10122 			spriteq_add_sprite(ent->modeldata.icon.x, ent->modeldata.icon.y, HUD_Z, icon, &drawmethod, 0);
10123 		}
10124 	}
10125 
10126 	if(ent->modeldata.health && ent->modeldata.hpx>-1000 && ent->modeldata.hpy>-1000)
10127 		bar(ent->modeldata.hpx, ent->modeldata.hpy, ent->oldhealth, ent->modeldata.health, &(ent->modeldata.hpbarstatus));
10128 }
10129 
10130 
drawstatus()10131 void drawstatus(){
10132 	int i;
10133 
10134 	for(i=0; i < MAX_PLAYERS; i++)
10135 	{
10136 		if(player[i].ent)
10137 		{
10138 			// Health bars
10139 			bar(videomodes.shiftpos[i]+plife[i][0],savedata.windowpos+plife[i][1], player[i].ent->oldhealth, player[i].ent->modeldata.health, &lbarstatus);
10140 			if(player[i].ent->opponent && !player[i].ent->opponent->modeldata.nolife && player[i].ent->opponent->modeldata.health)
10141 				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
10142 			// Draw mpbar
10143 			if(player[i].ent->modeldata.mp)
10144 			{
10145 				bar(videomodes.shiftpos[i]+pmp[i][0], savedata.windowpos+pmp[i][1], player[i].ent->oldmp, player[i].ent->modeldata.mp, &mpbarstatus);
10146 			}
10147 		}
10148 	}
10149 
10150 	// Time box
10151 	if(!level->notime && !timeloc[4])    // Only draw if notime is set to 0 or not specified
10152 	{
10153 		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);
10154 		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);
10155 		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);
10156 		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);
10157 		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);
10158 		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);
10159 		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);
10160 		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);
10161 	}
10162 }
10163 
update_loading(s_loadingbar * s,int value,int max)10164 void update_loading(s_loadingbar* s,  int value, int max) {
10165 	static unsigned int lasttick = 0;
10166 	static unsigned int soundtick = 0;
10167 	static unsigned int keybtick = 0;
10168 	int pos_x = s->bx + videomodes.hShift;
10169 	int pos_y = s->by + videomodes.vShift;
10170 	int size_x = s->bsize;
10171 	int text_x = s->tx + videomodes.hShift;
10172 	int text_y = s->ty + videomodes.vShift;
10173 	unsigned int ticks = timer_gettick();
10174 
10175 	if(ticks - soundtick > 20) {
10176 		sound_update_music();
10177 		soundtick = ticks;
10178 	}
10179 
10180 	if(ticks - keybtick > 250) {
10181 		control_update(playercontrolpointers, 1); // Respond to exit and/or fullscreen requests from user/OS
10182 		keybtick = ticks;
10183 	}
10184 
10185 
10186 	if(ticks - lasttick > s->refreshMs || value < 0 || value == max) { // Negative value forces a repaint. used when only bg is drawn for the first time
10187 		spriteq_clear();
10188 		execute_loading_script(value, max);
10189 		if(s->set) {
10190 			if (value < 0) value = 0;
10191 			if(isLoadingScreenTypeBar(s->set)) {
10192 				loadingbarstatus.sizex = size_x;
10193 				bar(pos_x, pos_y, value, max, &loadingbarstatus);
10194 			}
10195 			font_printf(text_x, text_y, s->tf, 0, "Loading...");
10196 			if(isLoadingScreenTypeBg(s->set)) {
10197 				if(background)
10198 					putscreen(vscreen, background, 0, 0, NULL);
10199 				else
10200 					clearscreen(vscreen);
10201 			}
10202 			spriteq_draw(vscreen, 0, MIN_INT, MAX_INT);
10203 			video_copy_screen(vscreen);
10204 			spriteq_clear();
10205 		}
10206 		else if(value < 0) { // Original BOR v1.0029 used this method.  Since loadingbg is optional, we should print this one again.
10207 			clearscreen(vscreen);
10208 			font_printf(120 + videomodes.hShift, 110 + videomodes.vShift, 0, 0, "Loading...");
10209 			spriteq_draw(vscreen, 0, MIN_INT, MAX_INT);
10210 			video_copy_screen(vscreen);
10211 			spriteq_clear();
10212 		}
10213 		lasttick = ticks;
10214 	}
10215 }
10216 
addscore(int playerindex,int add)10217 void addscore(int playerindex, int add){
10218 	unsigned int s = player[playerindex&3].score;
10219 	unsigned int next1up;
10220 	ScriptVariant var; // used for execute script
10221 	Script* ptempscript = pcurrentscript;
10222 
10223 	if(playerindex < 0) return;//dont score if <0, e.g., npc damage enemy, enemy damage enemy
10224 
10225 	playerindex &= 3;
10226 
10227 	next1up = ((s/lifescore)+1) * lifescore;
10228 
10229 	s += add;
10230 	if(s>999999999) s=999999999;
10231 
10232 	while(s>next1up){
10233 
10234 		if(SAMPLE_1UP >= 0) sound_play_sample(SAMPLE_1UP, 0, savedata.effectvol,savedata.effectvol, 100);
10235 
10236 		player[playerindex].lives++;
10237 		next1up += lifescore;
10238 	}
10239 
10240 	player[playerindex].score = s;
10241 
10242 	//execute a script then
10243 	if(Script_IsInitialized(score_script + playerindex))
10244 	{
10245 		ScriptVariant_Clear(&var);
10246 		ScriptVariant_ChangeType(&var, VT_INTEGER);
10247 		var.lVal = (LONG)add;
10248 		Script_Set_Local_Variant("score", &var);
10249 		Script_Execute(score_script+playerindex);
10250 		ScriptVariant_Clear(&var);
10251 		Script_Set_Local_Variant("score", &var);
10252 	}
10253 	pcurrentscript=ptempscript;
10254 }
10255 
10256 
10257 
10258 
10259 // ---------------------------- Object handling ------------------------------
10260 
free_ent(entity * e)10261 void free_ent(entity* e)
10262 {
10263 	int i;
10264 	if(!e) return;
10265 	clear_all_scripts(&e->scripts,2);
10266 	free_all_scripts(&e->scripts);
10267 
10268 	if(e->defense_factors){         free(e->defense_factors);          e->defense_factors          = NULL; }
10269 	if(e->defense_pain){            free(e->defense_pain);             e->defense_pain             = NULL; }
10270 	if(e->defense_knockdown){       free(e->defense_knockdown);        e->defense_knockdown        = NULL; }
10271 	if(e->defense_blockpower){      free(e->defense_blockpower);       e->defense_blockpower       = NULL; }
10272 	if(e->defense_blockthreshold){  free(e->defense_blockthreshold);   e->defense_blockthreshold   = NULL; }
10273 	if(e->defense_blockratio){      free(e->defense_blockratio);       e->defense_blockratio       = NULL; }
10274 	if(e->defense_blocktype){       free(e->defense_blocktype);        e->defense_blocktype        = NULL; }
10275 	if(e->offense_factors){         free(e->offense_factors);          e->offense_factors          = NULL; }
10276 	if(e->entvars)
10277 	{
10278 		// Although free_ent will be only called once when the engine is shutting down,
10279 		// just clear those in case we forget something
10280 		for(i=0; i<max_entity_vars; i++)
10281 		{
10282 			ScriptVariant_Clear(e->entvars+i);
10283 		}
10284 		free(e->entvars); e->entvars = NULL;
10285 	}
10286 	free(e);
10287 	e = NULL;
10288 }
10289 
free_ents()10290 void free_ents()
10291 {
10292 	int i;
10293 	for(i=0; i<MAX_ENTS; i++) free_ent(ent_list[i]);
10294 }
10295 
alloc_ent()10296 entity* alloc_ent()
10297 {
10298 	entity* ent = (entity*)malloc(sizeof(entity));
10299 	if(!ent) return NULL;
10300 	memset(ent, 0, sizeof(entity));
10301 	ent->defense_factors        = (float*)malloc(sizeof(float)*max_attack_types);
10302 	memset(ent->defense_factors,        0, sizeof(float)*max_attack_types);
10303 	ent->defense_pain           = (float*)malloc(sizeof(float)*max_attack_types);
10304 	memset(ent->defense_pain,           0, sizeof(float)*max_attack_types);
10305 	ent->defense_knockdown      = (float*)malloc(sizeof(float)*max_attack_types);
10306 	memset(ent->defense_knockdown,      0, sizeof(float)*max_attack_types);
10307 	ent->defense_blockpower     = (float*)malloc(sizeof(float)*max_attack_types);
10308 	memset(ent->defense_blockpower,     0, sizeof(float)*max_attack_types);
10309 	ent->defense_blockthreshold = (float*)malloc(sizeof(float)*max_attack_types);
10310 	memset(ent->defense_blockthreshold, 0, sizeof(float)*max_attack_types);
10311 	ent->defense_blockratio     = (float*)malloc(sizeof(float)*max_attack_types);
10312 	memset(ent->defense_blockratio,     0, sizeof(float)*max_attack_types);
10313 	ent->defense_blocktype      = (float*)malloc(sizeof(float)*max_attack_types);
10314 	memset(ent->defense_blocktype,      0, sizeof(float)*max_attack_types);
10315 	ent->offense_factors        = (float*)malloc(sizeof(float)*max_attack_types);
10316 	memset(ent->offense_factors,        0, sizeof(float)*max_attack_types);
10317 	if(max_entity_vars>0)
10318 	{
10319 		ent->entvars = (ScriptVariant*)malloc(sizeof(ScriptVariant)*max_entity_vars);
10320 		// memset should be OK by know, because VT_EMPTY is zero by value, or else we should use ScriptVariant_Init
10321 		memset(ent->entvars, 0, sizeof(ScriptVariant)*max_entity_vars);
10322 	}
10323 	alloc_all_scripts(&ent->scripts);
10324 	return ent;
10325 }
10326 
10327 
alloc_ents()10328 int alloc_ents()
10329 {
10330 	int i;
10331 	for(i=0; i<MAX_ENTS; i++)
10332 	{
10333 		ent_list[i] = alloc_ent();
10334 		if(!ent_list[i])
10335 		{
10336 			free_ents();
10337 			return 0;
10338 		}
10339 		ent_list[i]->sortid = i*100;
10340 	}
10341 	ent_count = ent_max = 0;
10342 	return 1;
10343 }
10344 
10345 // this method initialize an entity's A.I. behaviors
ent_default_init(entity * e)10346 void ent_default_init(entity* e)
10347 {
10348 	int dodrop;
10349 	int wall;
10350 	entity *other;
10351 
10352 	if(!e) return;
10353 
10354 	if((!selectScreen && !time) || e->modeldata.type != TYPE_PLAYER )
10355 	{
10356 		if( validanim(e,ANI_SPAWN)) ent_set_anim(e, ANI_SPAWN, 0); // use new playerselect spawn anim
10357 		//else set_idle(e);
10358 	}
10359 	else if(!selectScreen && time && e->modeldata.type == TYPE_PLAYER) // mid-level respawn
10360 	{
10361 		if( validanim(e,ANI_RESPAWN)) ent_set_anim(e, ANI_RESPAWN, 0);
10362 		else if( validanim(e,ANI_SPAWN)) ent_set_anim(e, ANI_SPAWN, 0);
10363 		//else set_idle(e);
10364 	}
10365 	else if(selectScreen && validanim(e,ANI_SELECT)) ent_set_anim(e, ANI_SELECT, 0);
10366 	//else set_idle(e);
10367 
10368 	if(!level)
10369 	{
10370 		if(!e->animation) set_idle(e);
10371 		return;
10372 	}
10373 
10374 	switch(e->modeldata.type){
10375 		case TYPE_ENDLEVEL:
10376 		case TYPE_ITEM:
10377 			e->nograb = 1;
10378 			break;
10379 
10380 		case TYPE_PLAYER:
10381 			//e->direction = (level->scrolldir != SCROLL_LEFT);
10382 			e->takedamage = player_takedamage;
10383 			e->think = player_think;
10384 			e->trymove = player_trymove;
10385 
10386 			if(validanim(e,ANI_SPAWN) || validanim(e,ANI_RESPAWN))
10387 			{
10388 				e->takeaction = common_spawn;
10389 			}
10390 			else if(!e->animation)
10391 			{
10392 				if(time && level->spawn[(int)e->playerindex][2] > e->a)
10393 				{
10394 					e->a = (float)level->spawn[(int)e->playerindex][2];
10395 					if(validanim(e, ANI_JUMP))
10396 					ent_set_anim(e, ANI_JUMP, 0);
10397 					e->takeaction = common_drop;
10398 				}
10399 			}
10400 			if(time && e->modeldata.makeinv)
10401 			{
10402 						// Spawn invincible code
10403 				e->invincible = 1;
10404 				e->blink = (e->modeldata.makeinv > 0);
10405 				e->invinctime = time + ABS(e->modeldata.makeinv);
10406 				e->arrowon = 1;    // Display the image above the player
10407 			}
10408 			break;
10409 		case TYPE_NPC: // use NPC(or A.I. player) instread of an enemy subtype or trap subtype, for further A.I. use
10410 			if(e->modeldata.multiple ==0) e->modeldata.multiple = -1;
10411 
10412 		case TYPE_ENEMY:
10413 			e->think = common_think;
10414 			if(e->modeldata.subtype == SUBTYPE_BIKER)
10415 			{
10416 				e->nograb = 1;
10417 				e->attacking = 1;
10418 				//e->direction = (e->x<0);
10419 				if(e->modeldata.speed)
10420 					e->xdir = (e->direction)?(e->modeldata.speed):(-e->modeldata.speed);
10421 				else
10422 					e->xdir = (e->direction)?(1.7 + randf((float)0.6)):(-(1.7 + randf((float)0.6)));
10423 				e->takedamage = biker_takedamage;
10424 				break;
10425 			}
10426 			// define new subtypes
10427 			else if(e->modeldata.subtype == SUBTYPE_ARROW)
10428 			{
10429 				e->health = 1;
10430 				if(!e->modeldata.speed && !e->modeldata.nomove)
10431 					e->modeldata.speed = 2;    // Set default speed to 2 for arrows
10432 				else if(e->modeldata.nomove)
10433 					e->modeldata.speed = 0;
10434 				if(e->ptype)
10435 					e->base = 0;
10436 				else
10437 					e->base = e->a;
10438 				e->nograb = 1;
10439 				e->attacking = 1;
10440 				e->takedamage = arrow_takedamage;
10441 				break;
10442 			}
10443 			else
10444 			{
10445 				e->trymove = common_trymove;
10446 				// Must just be a regular enemy, set defaults accordingly
10447 				if(!e->modeldata.speed && !e->modeldata.nomove)
10448 					e->modeldata.speed = 1;
10449 				else if(e->modeldata.nomove)
10450 					e->modeldata.speed = 0;
10451 				if(e->modeldata.multiple==0)
10452 					e->modeldata.multiple = 5;
10453 				e->takedamage = common_takedamage;//enemy_takedamage;
10454 			}
10455 
10456 			if(e->modeldata.subtype == SUBTYPE_NOTGRAB) e->nograb = 1;
10457 
10458 			if(validanim(e,ANI_SPAWN) /*|| validanim(e,ANI_RESPAWN)*/)
10459 			{
10460 				e->takeaction = common_spawn;
10461 			}
10462 			else
10463 			{
10464 				dodrop = (e->modeldata.subtype != SUBTYPE_ARROW && level && (level->scrolldir==SCROLL_UP || level->scrolldir==SCROLL_DOWN));
10465 
10466 				if(!nodropspawn && (dodrop || (e->x > advancex-30 && e->x < advancex + videomodes.hRes+30 && e->a == 0)) )
10467 				{
10468 					e->a += videomodes.vRes + randf(40);
10469 				}
10470 				if(inair(e)){
10471 					e->takeaction = common_drop;//enemy_drop;
10472 					if(validanim(e, ANI_JUMP)) ent_set_anim(e, ANI_JUMP, 0);
10473 				}
10474 			}
10475 			break;
10476 		// define trap type
10477 		case TYPE_TRAP:
10478 			e->think = trap_think;
10479 			e->takedamage =  common_takedamage;//enemy_takedamage;
10480 			break;
10481 		case TYPE_OBSTACLE:
10482 			e->nograb = 1;
10483 			if(e->health<=0)
10484 				e->dead = 1; // so it won't get hit
10485 			e->takedamage = obstacle_takedamage;//obstacle_takedamage;
10486 			break;
10487 		case TYPE_STEAMER:
10488 			e->nograb = 1;
10489 			e->think = steamer_think;
10490 			e->base = e->a;
10491 			break;
10492 		case TYPE_TEXTBOX:    // New type for displaying text purposes
10493 			e->nograb = 1;
10494 			e->think = text_think;
10495 			break;
10496 		case TYPE_SHOT:
10497 			e->health = 1;
10498 			e->nograb = 1;
10499 			e->think = common_think;
10500 			e->takedamage = arrow_takedamage;
10501 			e->attacking = 1;
10502 			if(!e->model->speed && !e->modeldata.nomove)
10503 				e->modeldata.speed = 2;    // Set default speed to 2 for arrows
10504 			else if(e->modeldata.nomove)
10505 				e->modeldata.speed = 0;
10506 			if(e->ptype)
10507 				e->base = 0;
10508 			else
10509 				e->base = e->a;
10510 			break;
10511 		case TYPE_NONE:
10512 			e->nograb = 1;
10513 			if(e->modeldata.subject_to_gravity<0) e->modeldata.subject_to_gravity = 1;
10514 			//e->base=e->a; //complained?
10515 			if(e->modeldata.no_adjust_base<0) e->modeldata.no_adjust_base= 1;
10516 
10517 			if(validanim(e,ANI_WALK))
10518 			{
10519 				if(e->direction) e->xdir = e->modeldata.speed;
10520 				else e->xdir = -(e->modeldata.speed);
10521 				e->think = anything_walk;
10522 
10523 				common_walk_anim(e);
10524 				//ent_set_anim(e, ANI_WALK, 0);
10525 			}
10526 			break;
10527 		case TYPE_PANEL:
10528 			e->nograb = 1;
10529 			break;
10530 	}
10531 	if(!e->animation){
10532 		set_idle(e);
10533 	}
10534 
10535 	if(e->modeldata.multiple < 0)
10536 		e->modeldata.multiple = 0;
10537 
10538 	if(e->modeldata.subject_to_platform>0 && (other=check_platform_below(e->x, e->z, e->a, e)))
10539 		e->base += other->a + other->animation->platform[other->animpos][7];
10540 	else if(e->modeldata.subject_to_wall>0 && (wall=checkwall_below(e->x, e->z, 9999999)) >= 0)
10541 		e->base += level->walls[wall][7];
10542 }
10543 
ent_spawn_ent(entity * ent)10544 void ent_spawn_ent(entity* ent)
10545 {
10546 	entity* s_ent = NULL;
10547 	float* spawnframe = ent->animation->spawnframe;
10548 	// spawn point relative to current entity
10549 	if(spawnframe[4] == 0)
10550 		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);
10551 	//relative to screen position
10552 	else if(spawnframe[4] == 1)
10553 	{
10554 		if(level && !(level->scrolldir&SCROLL_UP) && !(level->scrolldir&SCROLL_DOWN))
10555 			s_ent = spawn(advancex+spawnframe[1], advancey+spawnframe[2], spawnframe[3], 0, NULL, ent->animation->subentity, NULL);
10556 		else
10557 			s_ent = spawn(advancex+spawnframe[1], spawnframe[2], spawnframe[3], 0, NULL, ent->animation->subentity, NULL);
10558 	}
10559 	//absolute position in level
10560 	else s_ent = spawn(spawnframe[1], spawnframe[2], spawnframe[3]+0.001, 0, NULL, ent->animation->subentity, NULL);
10561 
10562 	if(s_ent)
10563 	{
10564 		//ent_default_init(s_ent);
10565 		if(s_ent->modeldata.type & TYPE_SHOT) s_ent->playerindex = ent->playerindex;
10566 		if(s_ent->modeldata.subtype == SUBTYPE_ARROW) s_ent->owner = ent;
10567 		s_ent->parent = ent;  //maybe used by A.I.
10568 		execute_onspawn_script(s_ent);
10569 	}
10570 }
10571 
ent_summon_ent(entity * ent)10572 void ent_summon_ent(entity* ent){
10573 	entity* s_ent = NULL;
10574 	float* spawnframe = ent->animation->summonframe;
10575 	// spawn point relative to current entity
10576 	if(spawnframe[4] == 0)
10577 		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);
10578 	//relative to screen position
10579 	else if(spawnframe[4] == 1)
10580 	{
10581 		if(level && !(level->scrolldir&SCROLL_UP) && !(level->scrolldir&SCROLL_DOWN))
10582 			s_ent = spawn(advancex+spawnframe[1], advancey+spawnframe[2], spawnframe[3], 0, NULL, ent->animation->subentity, NULL);
10583 		else
10584 			s_ent = spawn(advancex+spawnframe[1], spawnframe[2], spawnframe[3], 0, NULL, ent->animation->subentity, NULL);
10585 	}
10586 	//absolute position in level
10587 	else
10588 		s_ent = spawn(spawnframe[1], spawnframe[2], spawnframe[3], 0, NULL, ent->animation->subentity, NULL);
10589 
10590 	if(s_ent)
10591 	{
10592 		if(!spawnframe[4])
10593 			s_ent->direction = ent->direction;
10594 		//ent_default_init(s_ent);
10595 		if(s_ent->modeldata.type & TYPE_SHOT)
10596 			s_ent->playerindex = ent->playerindex;
10597 		if(s_ent->modeldata.subtype == SUBTYPE_ARROW)
10598 			s_ent->owner = ent;
10599 		//maybe used by A.I.
10600 		s_ent->parent = ent;
10601 		ent->subentity = s_ent;
10602 		execute_onspawn_script(s_ent);
10603 	}
10604 }
10605 
10606 // move here to prevent some duplicated code in ent_sent_anim and update_ents
update_frame(entity * ent,int f)10607 void update_frame(entity* ent, int f)
10608 {
10609 	entity* tempself;
10610 	entity* dust;
10611 	s_attack attack;
10612 	float move, movez, movea;
10613 	int iDelay, iED_Mode, iED_Capmin, iED_CapMax, iED_RangeMin, iED_RangeMax;
10614 	float fED_Factor;
10615 
10616 	if(f >= ent->animation->numframes) // prevent a crash with invalid frame index.
10617 		return;
10618 
10619 	//important!
10620 	tempself = self;
10621 	self = ent;
10622 
10623 	self->animpos = f;
10624 	//self->currentsprite = self->animation->sprite[f];
10625 
10626 	if(self->animating){
10627 		iDelay          = self->animation->delay[f];
10628 		iED_Mode        = self->modeldata.edelay.mode;
10629 		fED_Factor      = self->modeldata.edelay.factor;
10630 		iED_Capmin      = self->modeldata.edelay.cap_min;
10631 		iED_CapMax      = self->modeldata.edelay.cap_max;
10632 		iED_RangeMin    = self->modeldata.edelay.range_min;
10633 		iED_RangeMax    = self->modeldata.edelay.range_max;
10634 
10635 		if (iDelay >= iED_RangeMin && iDelay <= iED_RangeMax) //Regular delay within ignore ranges?
10636 		{
10637 			switch(iED_Mode)
10638 			{
10639 				case 1:
10640 					iDelay = (int)(iDelay * fED_Factor);
10641 					break;
10642 				default:
10643 					iDelay += (int)fED_Factor;
10644 					break;
10645 			}
10646 
10647 			if (iED_Capmin && iDelay < iED_Capmin){ iDelay = iED_Capmin; }
10648 			if (iED_CapMax && iDelay > iED_CapMax){ iDelay = iED_CapMax; }
10649 		}
10650 
10651 		self->nextanim = time + iDelay;
10652 		execute_animation_script(self);
10653 	}
10654 
10655 	if(level && (self->animation->move || self->animation->movez))
10656 	{
10657 		move = (float)(self->animation->move?self->animation->move[f]:0);
10658 		movez = (float)(self->animation->movez?self->animation->movez[f]:0);
10659 		if(self->direction==0) move = -move;
10660 		if(movez || move)
10661 		{
10662 			if(self->trymove)
10663 			{
10664 				self->trymove(move, movez);
10665 			}
10666 			else
10667 			{
10668 				self->x += move;
10669 				self->z += movez;
10670 			}
10671 		}
10672 	}
10673 
10674 	if(self->animation->seta && self->animation->seta[0] >= 0 && self->base <= 0)
10675 		ent->base = (float)ent->animation->seta[0];
10676 	else if(!self->animation->seta || self->animation->seta[0] < 0)
10677 	{
10678 		movea = (float)(self->animation->movea?self->animation->movea[f]:0);
10679 		self->base += movea;
10680 		if(movea!=0) self->altbase += movea;
10681 		else self->altbase = 0;
10682 	}
10683 
10684 	if(self->animation->flipframe == f) self->direction = !self->direction;
10685 
10686 	if(self->animation->weaponframe && self->animation->weaponframe[0] == f)
10687 	{
10688 		dropweapon(2);
10689 		set_weapon(self, self->animation->weaponframe[1], 0);
10690 		self->idling = 1;
10691 	}
10692 
10693 	if(self->animation->quakeframe.framestart+self->animation->quakeframe.cnt == f)
10694 	{
10695 		if(level) {
10696 			if(self->animation->quakeframe.cnt%2 || self->animation->quakeframe.v > 0) level->quake = self->animation->quakeframe.v;
10697 			else level->quake = self->animation->quakeframe.v * -1;
10698 		}
10699 		if((self->animation->quakeframe.repeat-self->animation->quakeframe.cnt) > 1) self->animation->quakeframe.cnt++;
10700 		else self->animation->quakeframe.cnt = 0;
10701 	}
10702 
10703 	//spawn / summon /unsummon features
10704 	if(self->animation->spawnframe && self->animation->spawnframe[0] == f && self->animation->subentity) ent_spawn_ent(self);
10705 
10706 	if(self->animation->summonframe && self->animation->summonframe[0] == f && self->animation->subentity)
10707 	{
10708 		//subentity is dead
10709 		if(!self->subentity || self->subentity->dead) ent_summon_ent(self);
10710 	}
10711 
10712 	if(self->animation->unsummonframe == f)
10713 	{
10714 		if(self->subentity)
10715 		{
10716 			self = self->subentity;
10717 			attack = emptyattack;
10718 			attack.dropv[0] = (float)3; attack.dropv[1] = (float)1.2; attack.dropv[2] = (float)0;
10719 			attack.attack_force = self->health;
10720 			attack.attack_type = max_attack_types;
10721 			if(self->takedamage) self->takedamage(self, &attack);
10722 			else kill(self);
10723 			self = ent; // lol ...
10724 			self->subentity = NULL;
10725 		}
10726 	}
10727 
10728 	if(self->animation->soundtoplay && self->animation->soundtoplay[f] >= 0)
10729 		sound_play_sample(self->animation->soundtoplay[f], 0, savedata.effectvol,savedata.effectvol, 100);
10730 
10731 	if(self->animation->jumpframe.f == f)
10732 	{
10733 		// Set custom jumpheight for jumpframes
10734 		/*if(self->animation->jumpframe.v > 0)*/ toss(self, self->animation->jumpframe.v);
10735 		self->xdir = self->direction?self->animation->jumpframe.x:-self->animation->jumpframe.x;
10736 		self->zdir = self->animation->jumpframe.z;
10737 
10738 		if(self->animation->jumpframe.ent>=0)
10739 		{
10740 			dust = spawn(self->x, self->z, self->a, self->direction, NULL, self->animation->jumpframe.ent, NULL);
10741 			if(dust){
10742 				dust->base = self->a;
10743 				dust->autokill = 1;
10744 				execute_onspawn_script(dust);
10745 			}
10746 		}
10747 	}
10748 
10749 	if(self->animation->throwframe == f)
10750 	{
10751 		// For backward compatible thing
10752 		// throw stars in the air, hmm, strange
10753 		// custstar custknife in animation should be checked first
10754 		// then if the entiti is jumping, check star first, if failed, try knife instead
10755 		// well, try knife at last, if still failed, try star, or just let if shutdown?
10756 #define __trystar star_spawn(self->x + (self->direction ? 56 : -56), self->z, self->a+67, self->direction)
10757 #define __tryknife knife_spawn(NULL, -1, self->x, self->z, self->a + self->animation->throwa, self->direction, 0, 0)
10758 		if(self->animation->custknife>=0 || self->animation->custpshotno>=0)
10759 			__tryknife;
10760 		else if(self->animation->custstar>=0)
10761 			__trystar;
10762 		else if(self->jumping) {
10763 			if(!__trystar)
10764 				__tryknife;
10765 		}
10766 		else if(!__tryknife)
10767 			__trystar;
10768 		self->reactive=1;
10769 	}
10770 
10771 	if(self->animation->shootframe == f)
10772 	{
10773 		knife_spawn(NULL, -1, self->x, self->z, self->a, self->direction, 1, 0);
10774 		self->reactive=1;
10775 	}
10776 
10777 	if(self->animation->tossframe == f)
10778 	{
10779 		bomb_spawn(NULL, -1, self->x, self->z, self->a + self->animation->throwa, self->direction, 0);
10780 		self->reactive=1;
10781 	}
10782 
10783 	//important!
10784 	self = tempself;
10785 }
10786 
10787 
ent_set_anim(entity * ent,int aninum,int resetable)10788 void ent_set_anim(entity *ent, int aninum, int resetable)
10789 {
10790 	s_anim *ani = NULL;
10791 
10792 	if(!ent) {
10793 		printf("FATAL: tried to set animation with invalid address (no such object)");
10794 		return;
10795 	}
10796 
10797 	if(aninum<0 || aninum>=max_animations) {
10798 		printf("FATAL: tried to set animation with invalid index (%s, %i)", ent->name, aninum);
10799 		return;
10800 	}
10801 
10802 	if(!validanim(ent, aninum)) {
10803 		printf("FATAL: tried to set animation with invalid address (%s, %i)", ent->name, aninum);
10804 		return;
10805 	}
10806 
10807 	ani = ent->modeldata.animation[aninum];
10808 
10809 	if(!resetable && ent->animation == ani)
10810 		return;
10811 
10812 	if(ani->numframes == 0)
10813 		return;
10814 
10815 	if(aninum!=ANI_SLEEP)
10816 		ent->sleeptime = time + ent->modeldata.sleepwait;
10817 	ent->animation = ani;
10818 	ent->animnum = aninum;    // Stored for nocost usage
10819 	ent->animation->animhits = 0;
10820 
10821 	if(!resetable)
10822 		ent->lastanimpos = -1;
10823 	ent->animating = 1;
10824 	ent->lasthit = ent->grabbing;
10825 	ent->altbase = 0;
10826 
10827 	update_frame(ent, 0);
10828 }
10829 
10830 
10831 
10832 // 0 = none, 1+ = alternative
ent_set_colourmap(entity * ent,unsigned int which)10833 void ent_set_colourmap(entity *ent, unsigned int which)
10834 {
10835 	if(which>MAX_COLOUR_MAPS) which = 0;
10836 	if(which==0)
10837 		ent->colourmap = ent->modeldata.palette;
10838 	else
10839 		ent->colourmap = ent->modeldata.colourmap[which-1];
10840 	ent->map = which;
10841 }
10842 
10843 // used by ent_set_model
ent_copy_uninit(entity * ent,s_model * oldmodel)10844 void ent_copy_uninit(entity* ent, s_model* oldmodel)
10845 {
10846 	if(ent->modeldata.multiple<0)
10847 		ent->modeldata.multiple             = oldmodel->multiple;
10848 	if(ent->modeldata.subject_to_wall<0)
10849 		ent->modeldata.subject_to_wall      = oldmodel->subject_to_wall;
10850 	if(ent->modeldata.subject_to_platform<0)
10851 		ent->modeldata.subject_to_platform  = oldmodel->subject_to_platform;
10852 	if(ent->modeldata.subject_to_obstacle<0)
10853 		ent->modeldata.subject_to_obstacle  = oldmodel->subject_to_obstacle;
10854 	if(ent->modeldata.subject_to_hole<0)
10855 		ent->modeldata.subject_to_hole      = oldmodel->subject_to_hole;
10856 	if(ent->modeldata.subject_to_gravity<0)
10857 		ent->modeldata.subject_to_gravity   = oldmodel->subject_to_gravity;
10858 	if(ent->modeldata.subject_to_screen<0)
10859 		ent->modeldata.subject_to_screen    = oldmodel->subject_to_screen;
10860 	if(ent->modeldata.subject_to_minz<0)
10861 		ent->modeldata.subject_to_minz      = oldmodel->subject_to_minz;
10862 	if(ent->modeldata.subject_to_maxz<0)
10863 		ent->modeldata.subject_to_maxz      = oldmodel->subject_to_maxz;
10864 	if(ent->modeldata.no_adjust_base<0)
10865 		ent->modeldata.no_adjust_base       = oldmodel->no_adjust_base;
10866 	if(ent->modeldata.aimove<0)
10867 		ent->modeldata.aimove               = oldmodel->aimove;
10868 	if(ent->modeldata.aiattack<0)
10869 		ent->modeldata.aiattack             = oldmodel->aiattack;
10870 	if(ent->modeldata.hostile<0)
10871 		ent->modeldata.hostile              = oldmodel->hostile;
10872 	if(ent->modeldata.candamage<0)
10873 		ent->modeldata.candamage            = oldmodel->candamage;
10874 	if(ent->modeldata.projectilehit<0)
10875 		ent->modeldata.projectilehit        = oldmodel->projectilehit;
10876 	if(!ent->modeldata.health)
10877 		ent->modeldata.health               = oldmodel->health;
10878 	if(!ent->modeldata.mp)
10879 		ent->modeldata.mp                   = oldmodel->mp;
10880 	if(ent->modeldata.risetime[0]==-1)
10881 		ent->modeldata.risetime[0]          = oldmodel->risetime[0];
10882 	/*
10883 	if(!ent->modeldata.antigrab)
10884 		ent->modeldata.antigrab             = oldmodel->antigrab;
10885 	if(!ent->modeldata.grabforce)
10886 		ent->modeldata.grabforce            = oldmodel->grabforce;
10887 	if(!ent->modeldata.paingrab)
10888 		ent->modeldata.paingrab             = oldmodel->paingrab;*/
10889 
10890 	if(ent->health>ent->modeldata.health)
10891 		ent->health = ent->modeldata.health;
10892 	if(ent->mp>ent->modeldata.mp)
10893 		ent->mp = ent->modeldata.mp;
10894 }
10895 
10896 
ent_set_model(entity * ent,char * modelname)10897 void ent_set_model(entity * ent, char * modelname)
10898 {
10899 	s_model *m = NULL;
10900 	s_model oldmodel;
10901 	if(ent==NULL) shutdown(1, "FATAL: tried to change model of invalid object");
10902 	m = findmodel(modelname);
10903 	if(m==NULL) shutdown(1, "Model not found: '%s'", modelname);
10904 	oldmodel = ent->modeldata;
10905 	ent->model = m;
10906 	ent->modeldata = *m;
10907 	ent_copy_uninit(ent, &oldmodel);
10908 	ent_set_colourmap(ent, ent->map);
10909 	if((!selectScreen && !time) || ent->modeldata.type != TYPE_PLAYER)
10910 	{
10911 		// use new playerselect spawn anim
10912 		if( validanim(ent,ANI_SPAWN))
10913 			ent_set_anim(ent, ANI_SPAWN, 0);
10914 		else
10915 			ent_set_anim(ent, ANI_IDLE, 0);
10916 	}
10917 	else if(!selectScreen && time && ent->modeldata.type == TYPE_PLAYER)
10918 	{
10919 		// mid-level respawn
10920 		if( validanim(ent, ANI_RESPAWN))
10921 			ent_set_anim(ent, ANI_RESPAWN, 0);
10922 		else if( validanim(ent, ANI_SPAWN))
10923 			ent_set_anim(ent, ANI_SPAWN, 0);
10924 		else
10925 			ent_set_anim(ent, ANI_IDLE, 0);
10926 	}
10927 	else if(selectScreen && validanim(ent, ANI_SELECT))
10928 		ent_set_anim(ent, ANI_SELECT, 0);
10929 	else
10930 		ent_set_anim(ent, ANI_IDLE, 0);
10931 }
10932 
10933 
spawn(float x,float z,float a,int direction,char * name,int index,s_model * model)10934 entity * spawn(float x, float z, float a, int direction, char * name, int index, s_model* model)
10935 {
10936 	entity *e = NULL;
10937 	int i, id;
10938 	float *dfs, *dfsp, *dfsk, *dfsbp, *dfsbt, *dfsbr, *dfsbe, *ofs;
10939 	ScriptVariant* vars;
10940 	Script* pas, *pus, *pts, *pks, *pds, *pan, *pfs, *bls, *blw, *blo, *blz, *bla, *mox, *moz, *moa, *pis, *pkl, *phs, *osp, *pbs, *ocs;
10941 
10942 	if(!model)
10943 	{
10944 		if(index>=0)
10945 			model = model_cache[index].model;
10946 		else if(name)
10947 			model = findmodel(name);
10948 	}
10949 
10950 	// Be a bit more tolerant...
10951 	if(model==NULL)
10952 	{
10953 		if(index>=0)
10954 			printf("FATAL: attempt to spawn object with invalid model cache id (%d)!\n", index);
10955 		else if(name)
10956 			printf("FATAL: attempt to spawn object with invalid model name (%s)!\n", name);
10957 		return NULL;
10958 	}
10959 
10960 	for(i=0; i<MAX_ENTS; i++)
10961 	{
10962 		if(!ent_list[i]->exists)
10963 		{
10964 			e = ent_list[i];
10965 			// save these values, or they will loss when memset called
10966 			id      = e->sortid;
10967 			dfs     = e->defense_factors;
10968 			dfsp    = e->defense_pain;
10969 			dfsk    = e->defense_knockdown;
10970 			dfsbp   = e->defense_blockpower;
10971 			dfsbt   = e->defense_blockthreshold;
10972 			dfsbr   = e->defense_blockratio;
10973 			dfsbe   = e->defense_blocktype;
10974 			ofs     = e->offense_factors;
10975 			vars    = e->entvars;
10976 			memset(dfs,     0, sizeof(float)*max_attack_types);
10977 			memset(dfsp,    0, sizeof(float)*max_attack_types);
10978 			memset(dfsk,    0, sizeof(float)*max_attack_types);
10979 			memset(dfsbp,   0, sizeof(float)*max_attack_types);
10980 			memset(dfsbt,   0, sizeof(float)*max_attack_types);
10981 			memset(dfsbr,   0, sizeof(float)*max_attack_types);
10982 			memset(dfsbe,   0, sizeof(float)*max_attack_types);
10983 			memset(ofs,     0, sizeof(float)*max_attack_types);
10984 			// clear up
10985 			clear_all_scripts(&e->scripts, 1);
10986 
10987 			pas = e->scripts.animation_script;
10988 			pus = e->scripts.update_script;
10989 			pts = e->scripts.think_script;
10990 			pds = e->scripts.takedamage_script;
10991 			pfs = e->scripts.onfall_script;
10992 			pan = e->scripts.onpain_script;
10993 			bls = e->scripts.onblocks_script;
10994 			blw = e->scripts.onblockw_script;
10995 			blo = e->scripts.onblocko_script;
10996 			blz = e->scripts.onblockz_script;
10997 			bla = e->scripts.onblocka_script;
10998 			mox = e->scripts.onmovex_script;
10999 			moz = e->scripts.onmovez_script;
11000 			moa = e->scripts.onmovea_script;
11001 			pis = e->scripts.ondeath_script;
11002 			pkl = e->scripts.onkill_script;
11003 			pbs = e->scripts.didblock_script;
11004 			ocs = e->scripts.ondoattack_script;
11005 			phs = e->scripts.didhit_script;
11006 			osp = e->scripts.onspawn_script;
11007 			pks = e->scripts.key_script;
11008 			memset(e, 0, sizeof(entity));
11009 
11010 			// add to list and count current entities
11011 			e->exists = 1;
11012 			ent_count++;
11013 
11014 			e->modeldata = *model; // copy the entir model data here
11015 			e->model = model;
11016 			e->defaultmodel = model;
11017 
11018 			e->scripts.animation_script     = pas;
11019 			e->scripts.update_script        = pus;
11020 			e->scripts.think_script         = pts;
11021 			e->scripts.takedamage_script    = pds;
11022 			e->scripts.onfall_script        = pfs;
11023 			e->scripts.onpain_script        = pan;
11024 			e->scripts.onblocks_script      = bls;
11025 			e->scripts.onblockw_script      = blw;
11026 			e->scripts.onblocko_script      = blo;
11027 			e->scripts.onblockz_script      = blz;
11028 			e->scripts.onblocka_script      = bla;
11029 			e->scripts.onmovex_script       = mox;
11030 			e->scripts.onmovez_script       = moz;
11031 			e->scripts.onmovea_script       = moa;
11032 			e->scripts.ondeath_script       = pis;
11033 			e->scripts.onkill_script        = pkl;
11034 			e->scripts.didblock_script      = pbs;
11035 			e->scripts.ondoattack_script    = ocs;
11036 			e->scripts.didhit_script        = phs;
11037 			e->scripts.onspawn_script       = osp;
11038 			e->scripts.key_script           = pks;
11039 			// copy from model a fresh script
11040 
11041 			copy_all_scripts(&model->scripts, &e->scripts, 1);
11042 
11043 			if(ent_count>ent_max) ent_max=ent_count;
11044 			e->timestamp = time; // log time so update function will ignore it if it is new
11045 
11046 			e->health = e->modeldata.health;
11047 			e->mp = e->modeldata.mp;
11048 			e->knockdowncount = e->modeldata.knockdowncount;
11049 			e->x = x;
11050 			e->z = z;
11051 			e->a = a;
11052 			e->direction = direction;
11053 			e->nextthink = time + 1;
11054 			ent_set_colourmap(e, 0);
11055 			e->lifespancountdown = model->lifespan; // new life span countdown
11056 			if((e->modeldata.type & (TYPE_PLAYER|TYPE_SHOT)) && level && (level->nohit || savedata.mode)) e->modeldata.hostile &= ~TYPE_PLAYER;
11057 			if(e->modeldata.type==TYPE_PLAYER) e->playerindex = currentspawnplayer;
11058 
11059 			if(e->modeldata.type == TYPE_TEXTBOX) textbox = e;
11060 
11061 			strncpy(e->name, e->modeldata.name, MAX_NAME_LEN);
11062 			// copy back the value
11063 			e->sortid = id;
11064 			e->defense_factors = dfs;
11065 			e->defense_pain = dfsp;
11066 			e->defense_knockdown = dfsk;
11067 			e->defense_blockpower = dfsbp;
11068 			e->defense_blockthreshold = dfsbt;
11069 			e->defense_blockratio = dfsbr;
11070 			e->defense_blocktype = dfsbe;
11071 			e->offense_factors = ofs;
11072 			e->entvars = vars;
11073 
11074 			ent_default_init(e);
11075 			return e;
11076 		}
11077 	}
11078 	return NULL;
11079 }
11080 
11081 
11082 
11083 // Break the link an entity has with another one
ent_unlink(entity * e)11084 void ent_unlink(entity *e) {
11085 	if(e->link){
11086 		e->link->link = NULL;
11087 		e->link->grabbing = NULL;
11088 	}
11089 	e->link = NULL;
11090 	e->grabbing = NULL;
11091 }
11092 
11093 
11094 
11095 // Link two entities together
ents_link(entity * e1,entity * e2)11096 void ents_link(entity *e1, entity *e2)
11097 {
11098 	ent_unlink(e1);
11099 	ent_unlink(e2);
11100 	e1->grabbing = e2;    // Added for platform layering
11101 	e1->link = e2;
11102 	e2->link = e1;
11103 }
11104 
11105 
11106 
kill(entity * victim)11107 void kill(entity *victim)
11108 {
11109 	int i = 0;
11110 	s_attack attack;
11111 	entity* tempent = self;
11112 
11113 	execute_onkill_script(victim);
11114 
11115 	if(!victim || !victim->exists)
11116 		return;
11117 
11118 	if(victim->modeldata.type == TYPE_SHOT && player[(int)victim->playerindex].ent)
11119 		player[(int)victim->playerindex].ent->cantfire = 0;
11120 
11121 	ent_unlink(victim);
11122 	victim->weapent = NULL;
11123 	victim->health = 0;
11124 	victim->exists = 0;
11125 	ent_count--;
11126 
11127 	clear_all_scripts(&victim->scripts, 1);
11128 
11129 	if(victim->parent && victim->parent->subentity == victim) victim->parent->subentity = NULL;
11130 	victim->parent = NULL;
11131 	if(victim->modeldata.summonkill)
11132 	{
11133 		attack = emptyattack;
11134 		attack.attack_type = max_attack_types;
11135 		attack.dropv[0] = (float)3; attack.dropv[1] = (float)1.2; attack.dropv[2] = (float)0;
11136 	}
11137 	// kill minions
11138 	if(victim->modeldata.summonkill == 1 && victim->subentity)
11139 	{
11140 		// kill only summoned one
11141 		victim->subentity->parent = NULL;
11142 		self = victim->subentity;
11143 		attack.attack_force = self->health;
11144 		if(self->takedamage && !level_completed)
11145 			self->takedamage(self, &attack);
11146 		else
11147 			kill(self);
11148 	}
11149 	victim->subentity = NULL;
11150 
11151 	if(victim==player[0].ent) player[0].ent = NULL;
11152 	else if(victim==player[1].ent) player[1].ent = NULL;
11153 	else if(victim==player[2].ent) player[2].ent = NULL;
11154 	else if(victim==player[3].ent) player[3].ent = NULL;
11155 
11156 	if(victim == smartbomber) smartbomber = NULL;
11157 	if(victim == textbox)  textbox = NULL;
11158 
11159 	for(i=0; i<ent_max; i++)
11160 	{
11161 		if(ent_list[i]->exists)
11162 		{
11163 			// kill all minions
11164 			self = ent_list[i];
11165 			if(self->parent == victim)
11166 			{
11167 				self->parent = NULL;
11168 				if(victim->modeldata.summonkill == 2)
11169 				{
11170 					attack.attack_force = self->health;
11171 					if(self->takedamage && !level_completed) self->takedamage(self, &attack);
11172 					else kill(self);
11173 				}
11174 			}
11175 			if(self->owner == victim)
11176 			{
11177 				self->owner = victim->owner;
11178 			}
11179 			if(self->opponent == victim) self->opponent = NULL;
11180 			if(self->bound == victim) self->bound = NULL;
11181 			if(self->landed_on_platform == victim) self->landed_on_platform = NULL;
11182 			if(self->hithead == victim) self->hithead = NULL;
11183 			if(!textbox && self->modeldata.type == TYPE_TEXTBOX)
11184 			textbox = self;
11185 		}
11186 	}
11187 	self = tempent;
11188 }
11189 
11190 
kill_all()11191 void kill_all()
11192 {
11193 	int i;
11194 	entity *e = NULL;
11195 	for(i=0; i<ent_max; i++)
11196 	{
11197 		e = ent_list[i];
11198 		if (e && e->exists){
11199 			execute_onkill_script(e);
11200 			clear_all_scripts(&e->scripts, 1);
11201 		}
11202 		e->exists = 0; // well, no need to use kill function
11203 	}
11204 	textbox = smartbomber = NULL;
11205 	ent_max = ent_count = 0;
11206 	time = 0;
11207 }
11208 
11209 
checkhit(entity * attacker,entity * target,int counter)11210 int checkhit(entity *attacker, entity *target, int counter)
11211 {
11212 	short *coords1;
11213 	short *coords2;
11214 	int x1, x2, y1, y2;
11215 	float medx, medy;
11216 	int debug_coords[2][4];
11217 	int topleast, bottomleast, leftleast, rightleast;
11218 	float zdist = 0;
11219 
11220 	if(attacker == target || !target->animation->bbox_coords ||
11221 	!attacker->animation->attacks || !target->animation->vulnerable[target->animpos] ||
11222 	((attacker->modeldata.type == TYPE_PLAYER && target->modeldata.type == TYPE_PLAYER) && savedata.mode)) return 0;
11223 
11224 
11225 	coords1 = attacker->animation->attacks[attacker->animpos]->attack_coords;
11226 
11227 	if(!counter)
11228 		coords2 = target->animation->bbox_coords[target->animpos];
11229 	else if((target->animation->attacks && target->animation->attacks[target->animpos]) && target->animation->attacks[target->animpos]->counterattack <= attacker->animation->attacks[attacker->animpos]->counterattack)
11230 		coords2 = target->animation->attacks[target->animpos]->attack_coords;
11231 	else return 0;
11232 
11233 	if(coords1[4])
11234 		zdist += coords1[4];
11235 	else
11236 		zdist += attacker->modeldata.grabdistance/3;
11237 	if(coords2[4])
11238 		zdist += coords2[4];
11239 
11240 	if(diff(attacker->z,target->z) > zdist)
11241 		return 0;
11242 
11243 	x1 = (int)(attacker->x);
11244 	y1 = (int)(attacker->z - attacker->a);
11245 	x2 = (int)(target->x);
11246 	y2 = (int)(target->z - target->a);
11247 
11248 
11249 	if(attacker->direction==0){
11250 		debug_coords[0][0] = x1-coords1[2];
11251 		debug_coords[0][1] = y1+coords1[1];
11252 		debug_coords[0][2] = x1-coords1[0];
11253 		debug_coords[0][3] = y1+coords1[3];
11254 	}
11255 	else{
11256 		debug_coords[0][0] = x1+coords1[0];
11257 		debug_coords[0][1] = y1+coords1[1];
11258 		debug_coords[0][2] = x1+coords1[2];
11259 		debug_coords[0][3] = y1+coords1[3];
11260 	}
11261 	if(target->direction==0){
11262 		debug_coords[1][0] = x2-coords2[2];
11263 		debug_coords[1][1] = y2+coords2[1];
11264 		debug_coords[1][2] = x2-coords2[0];
11265 		debug_coords[1][3] = y2+coords2[3];
11266 	} else {
11267 		debug_coords[1][0] = x2+coords2[0];
11268 		debug_coords[1][1] = y2+coords2[1];
11269 		debug_coords[1][2] = x2+coords2[2];
11270 		debug_coords[1][3] = y2+coords2[3];
11271 	}
11272 
11273 	if(debug_coords[0][0] > debug_coords[1][2]) return 0;
11274 	if(debug_coords[1][0] > debug_coords[0][2]) return 0;
11275 	if(debug_coords[0][1] > debug_coords[1][3]) return 0;
11276 	if(debug_coords[1][1] > debug_coords[0][3]) return 0;
11277 
11278 
11279 	// Find center of attack area
11280 	leftleast = debug_coords[0][0];
11281 	if(leftleast < debug_coords[1][0])
11282 		leftleast = debug_coords[1][0];
11283 	topleast = debug_coords[0][1];
11284 	if(topleast < debug_coords[1][1])
11285 		topleast = debug_coords[1][1];
11286 	rightleast = debug_coords[0][2];
11287 	if(rightleast > debug_coords[1][2])
11288 		rightleast = debug_coords[1][2];
11289 	bottomleast = debug_coords[0][3];
11290 	if(bottomleast > debug_coords[1][3])
11291 		bottomleast = debug_coords[1][3];
11292 
11293 	medx = (float)(leftleast + rightleast) / 2;
11294 	medy = (float)(topleast + bottomleast) / 2;
11295 
11296 	// Now convert these coords to 3D
11297 	lasthitx = medx;
11298 
11299 	if(attacker->z > target->z)
11300 		lasthitz = attacker->z + 1;    // Changed so flashes always spawn in front
11301 	else
11302 		lasthitz = target->z + 1;
11303 
11304 	lasthita = lasthitz - medy;
11305 	lasthitt = attacker->animation->attacks[attacker->animpos]->attack_type;
11306 	lasthitc = 1;
11307 	return 1;
11308 }
11309 
11310 
11311 
11312 /*
11313 Calculates the coef relative to the bottom left point. This is done by figuring out how far the entity is from
11314 the bottom of the platform and multiplying the result by the difference of the bottom left point and the top
11315 left point divided by depth of the platform. The same is done for the right side, and checks to see if they are
11316 within the bottom/top and the left/right area.
11317 */
testhole(int hole,float x,float z)11318 int testhole(int hole, float x, float z)
11319 {
11320 	float coef1, coef2;
11321 	if(z < level->holes[hole][1] && z > level->holes[hole][1] - level->holes[hole][6])
11322 	{
11323 		coef1 = (level->holes[hole][1] - z) * ((level->holes[hole][2] - level->holes[hole][3]) / level->holes[hole][6]);
11324 		coef2 = (level->holes[hole][1] - z) * ((level->holes[hole][4] - level->holes[hole][5]) / level->holes[hole][6]);
11325 		if(x > level->holes[hole][0] + level->holes[hole][3] + coef1 && x < level->holes[hole][0] + level->holes[hole][5] + coef2)
11326 			return 1;
11327 	}
11328 	return 0;
11329 }
11330 
11331 /// find all holes here and return the count
checkholes(float x,float z)11332 int checkholes(float x, float z)
11333 {
11334 	int i, c;
11335 
11336 	for(i=0, c=0; i<level->numholes; i++)
11337 		c += (level->holesfound[i] =  testhole(i, x, z));
11338 
11339 	return c;
11340 }
11341 
11342 // find the 1st hole here
checkhole(float x,float z)11343 int checkhole(float x, float z)
11344 {
11345 	int i;
11346 
11347 	if(level==NULL) return 0;
11348 
11349 	if(level->exit_hole){
11350 		if(x > level->width-(PLAYER_MAX_Z-z)) return 2;
11351 	}
11352 
11353 	for(i=0; i<level->numholes; i++)
11354 	{
11355 		if(testhole(i, x, z))
11356 		{
11357 			holez = i;
11358 			return 1;
11359 		}
11360 	}
11361 	return 0;
11362 }
11363 
11364 /*
11365 Calculates the coef relative to the bottom left point. This is done by figuring out how far the entity is from
11366 the bottom of the platform and multiplying the result by the difference of the bottom left point and the top
11367 left point divided by depth of the platform. The same is done for the right side, and checks to see if they are
11368 within the bottom/top and the left/right area.
11369 */
testwall(int wall,float x,float z)11370 int testwall(int wall, float x, float z)
11371 {
11372 	float coef1, coef2;
11373 //    if(wall >= level->numwalls || wall < 0) return 0;
11374 	if(z < level->walls[wall][1] && z > level->walls[wall][1] - level->walls[wall][6])
11375 	{
11376 		coef1 = (level->walls[wall][1] - z) * ((level->walls[wall][2] - level->walls[wall][3]) / level->walls[wall][6]);
11377 		coef2 = (level->walls[wall][1] - z) * ((level->walls[wall][4] - level->walls[wall][5]) / level->walls[wall][6]);
11378 		if(x > level->walls[wall][0] + level->walls[wall][3] + coef1 && x < level->walls[wall][0] + level->walls[wall][5] + coef2) return 1;
11379 	}
11380 
11381 	return 0;
11382 }
11383 
11384 // find all walls here within altitude1 and 2, return the count
checkwalls(float x,float z,float a1,float a2)11385 int checkwalls(float x, float z, float a1, float a2)
11386 {
11387 	int i, c;
11388 
11389 	for(i=0, c=0; i<level->numwalls; i++)
11390 		c += (level->wallsfound[i] =  (testwall(i, x, z) && level->walls[i][7] >= a1 && level->walls[i][7] <= a2));
11391 
11392 	return c;
11393 }
11394 
11395 // get a highest wall below this altitude
checkwall_below(float x,float z,float a)11396 int checkwall_below(float x, float z, float a)
11397 {
11398 	float maxa;
11399 	int i, ind;
11400 
11401 	if(level==NULL) return -1;
11402 
11403 	maxa = 0;
11404 	ind = -1;
11405 	for(i=0; i<level->numwalls; i++)
11406 	{
11407 		if(testwall(i, x, z) && level->walls[i][7] <= a && level->walls[i][7] > maxa)
11408 		{
11409 			maxa = level->walls[i][7];
11410 			ind = i;
11411 		}
11412 	}
11413 
11414 	return ind;
11415 }
11416 
11417 // return the 1st wall found here
checkwall(float x,float z)11418 int checkwall(float x, float z)
11419 {
11420 	int i;
11421 	if(level==NULL) return -1;
11422 
11423 	for(i=0; i<level->numwalls; i++)
11424 		if(testwall(i, x, z)) return i;
11425 
11426 	return -1;
11427 }
11428 
11429 /*
11430 Calculates the coef relative to the bottom left point. This is done by figuring out how far the entity is from
11431 the bottom of the platform and multiplying the result by the difference of the bottom left point and the top
11432 left point divided by depth of the platform. The same is done for the right side, and checks to see if they are
11433 within the bottom/top and the left/right area.
11434 */
testplatform(entity * plat,float x,float z,entity * exclude)11435 int testplatform(entity* plat, float x, float z, entity* exclude)
11436 {
11437 	float coef1, coef2;
11438 	float offz, offx;
11439 	if(plat==exclude) return 0;
11440 	if(!plat->animation || !plat->animation->platform || !plat->animation->platform[plat->animpos][7]) return 0;
11441 	offz = plat->z+plat->animation->platform[plat->animpos][1];
11442 	offx = plat->x+plat->animation->platform[plat->animpos][0];
11443 	if(z <= offz && z > offz - plat->animation->platform[plat->animpos][6])
11444 	{
11445 		coef1 = (offz - z) * ((plat->animation->platform[plat->animpos][2] -
11446 			plat->animation->platform[plat->animpos][3]) / plat->animation->platform[plat->animpos][6]);
11447 		coef2 = (offz - z) * ((plat->animation->platform[plat->animpos][4] -
11448 			plat->animation->platform[plat->animpos][5]) / plat->animation->platform[plat->animpos][6]);
11449 
11450 		if(x > offx + plat->animation->platform[plat->animpos][3] + coef1 &&
11451 		   x < offx + plat->animation->platform[plat->animpos][5] + coef2) return 1;
11452 	}
11453 	return 0;
11454 }
11455 
11456 
11457 //find the first platform between these 2 altitudes
check_platform_between(float x,float z,float amin,float amax,entity * exclude)11458 entity * check_platform_between(float x, float z, float amin, float amax, entity* exclude)
11459 {
11460 	entity *plat = NULL;
11461 	int i;
11462 
11463 	if(level==NULL) return NULL;
11464 
11465 	for(i=0; i<ent_max; i++)
11466 	{
11467 		if(ent_list[i]->exists && testplatform(ent_list[i], x, z, exclude) )
11468 		{
11469 			plat = ent_list[i];
11470 			if(plat->a <= amax && plat->a + plat->animation->platform[plat->animpos][7] > amin)
11471 			{
11472 				return plat;
11473 			}
11474 		}
11475 	}
11476 	return NULL;
11477 }
11478 
11479 //find a lowest platform above this altitude
check_platform_above(float x,float z,float a,entity * exclude)11480 entity * check_platform_above(float x, float z, float a, entity* exclude)
11481 {
11482 	float mina;
11483 	entity *plat = NULL;
11484 	int i, ind;
11485 
11486 	if(level==NULL) return NULL;
11487 
11488 	mina = 9999999;
11489 	ind = -1;
11490 	for(i=0; i<ent_max; i++)
11491 	{
11492 		if(ent_list[i]->exists && testplatform(ent_list[i], x, z, exclude) )
11493 		{
11494 			plat = ent_list[i];
11495 			if(plat->a >= a && plat->a < mina)
11496 			{
11497 				mina = plat->a;
11498 				ind = i;
11499 			}
11500 		}
11501 	}
11502 	return (ind>=0)?ent_list[ind]:NULL;
11503 }
11504 
11505 //find a highest platform below this altitude
check_platform_below(float x,float z,float a,entity * exclude)11506 entity * check_platform_below(float x, float z, float a, entity* exclude)
11507 {
11508 	float maxa;
11509 	entity *plat = NULL;
11510 	int i, ind;
11511 
11512 	if(level==NULL) return NULL;
11513 
11514 	maxa = MIN_INT;
11515 	ind = -1;
11516 	for(i=0; i<ent_max; i++)
11517 	{
11518 		if(ent_list[i]->exists && testplatform(ent_list[i], x, z, exclude) )
11519 		{
11520 			plat = ent_list[i];
11521 			if(plat->a + plat->animation->platform[plat->animpos][7] <= a &&
11522 			   plat->a + plat->animation->platform[plat->animpos][7] > maxa)
11523 			{
11524 				maxa = plat->a + plat->animation->platform[plat->animpos][7];
11525 				ind = i;
11526 			}
11527 		}
11528 	}
11529 	return (ind>=0)?ent_list[ind]:NULL;
11530 }
11531 
11532 // find the 1st platform entity here
check_platform(float x,float z,entity * exclude)11533 entity * check_platform(float x, float z, entity* exclude)
11534 {
11535 	int i;
11536 	if(level==NULL) return NULL;
11537 
11538 	for(i=0; i<ent_max; i++)
11539 	{
11540 		if(ent_list[i]->exists && testplatform(ent_list[i], x, z, exclude))
11541 		{
11542 			return ent_list[i];
11543 		}
11544 	}
11545 	return NULL;
11546 }
11547 
11548 // for adjust grab position function, test if an entity can move from a to b
11549 // TODO: check points between the two pionts, if necessary
testmove(entity * ent,float sx,float sz,float x,float z)11550 int testmove(entity* ent, float sx, float sz, float x, float z){
11551 	entity *other = NULL;
11552 	int wall, heightvar;
11553 	float xdir, zdir;
11554 
11555 	xdir = x - sx;
11556 	zdir = z - sz;
11557 
11558 	if(!xdir && !zdir) return 1;
11559 
11560 	// -----------bounds checking---------------
11561 	// Subjec to Z and out of bounds? Return to level!
11562 	if (ent->modeldata.subject_to_minz>0)
11563 	{
11564 		if(zdir && z < PLAYER_MIN_Z)
11565 			return 0;
11566 	}
11567 
11568 	if (ent->modeldata.subject_to_maxz>0)
11569 	{
11570 		if(zdir && z > PLAYER_MAX_Z)
11571 			return 0;
11572 	}
11573 
11574 	// End of level is blocked?
11575 	if(level->exit_blocked)
11576 	{
11577 		if(x > level->width-30-(PLAYER_MAX_Z-z)) return 0;
11578 	}
11579 	// screen checking
11580 	if(ent->modeldata.subject_to_screen>0)
11581 	{
11582 		if(x < advancex+10) return 0;
11583 		else if(x > advancex+(videomodes.hRes-10)) return 0;
11584 	}
11585 	//-----------end of bounds checking-----------
11586 
11587 	//-------------hole checking ---------------------
11588 	if(ent->modeldata.subject_to_hole>0)
11589 	{
11590 		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))
11591 			return 0;
11592 	}
11593 	//-----------end of hole checking---------------
11594 
11595 	//--------------obstacle checking ------------------
11596 	if(ent->modeldata.subject_to_obstacle>0)
11597 	{
11598 		if((other = find_ent_here(ent, x, z, (TYPE_OBSTACLE | TYPE_TRAP))) &&
11599 		   (!other->animation->platform||!other->animation->platform[other->animpos][7]))
11600 			return 0;
11601 	}
11602 	//-----------end of obstacle checking--------------
11603 
11604 	// ---------------- platform checking----------------
11605 
11606 	if(ent->animation->height) heightvar = ent->animation->height;
11607 	else heightvar = ent->modeldata.height;
11608 
11609 	// Check for obstacles with platform code and adjust base accordingly
11610 	if(ent->modeldata.subject_to_platform>0 && (other = check_platform_between(x, z, ent->a, ent->a+heightvar, ent)) )
11611 	{
11612 		return 0;
11613 	}
11614 	//-----------end of platform checking------------------
11615 
11616 	// ------------------ wall checking ---------------------
11617 	if(ent->modeldata.subject_to_wall>0 && (wall = checkwall(x, z))>=0 && level->walls[wall][7]>ent->a)
11618 	{
11619 		return 0;
11620 	}
11621 	//----------------end of wall checking--------------
11622 
11623 	return 1;
11624 
11625 }
11626 
11627 // find real opponent
set_opponent(entity * ent,entity * other)11628 void set_opponent(entity* ent, entity* other)
11629 {
11630 	entity* realself, *realother;
11631 
11632 	if(!ent) return;
11633 
11634 	realself = ent;
11635 	while(realself->owner) realself = realself->owner;
11636 
11637 	realother = other;
11638 	while(realother && realother->owner) realother = realother->owner;
11639 
11640 	realself->opponent = ent->opponent = realother;
11641 	if(realother) realother->opponent = other->opponent = realself;
11642 
11643 }
11644 
11645 
do_attack(entity * e)11646 void do_attack(entity *e)
11647 {
11648 	int them;
11649 	int i;
11650 	int force;
11651 	entity *temp            = NULL;
11652 	entity *flash           = NULL;    // Used so new flashes can be used
11653 	entity *def             = NULL;
11654 	entity *topowner        = NULL;
11655 	entity *otherowner      = NULL;
11656 	int didhit              = 0;
11657 	int didblock            = 0;    // So a different sound effect can be played when an attack is blocked
11658 	int current_attack_id;
11659 	int current_follow_id   = 0;
11660 #define followed (current_anim!=e->animation)
11661 	s_anim* current_anim;
11662 	s_attack* attack = e->animation->attacks[e->animpos];
11663 	static unsigned int new_attack_id = 1;
11664 	int fdefense_blockthreshold = (int)self->modeldata.defense_blockthreshold[(short)attack->attack_type]; //Maximum damage that can be blocked for attack type.
11665 
11666 	// Can't get hit after this
11667 	if(level_completed || !attack) return;
11668 
11669 	topowner = e; // trace the top owner, for projectile combo checking :)
11670 	while(topowner->owner) topowner = topowner->owner;
11671 
11672 	if(e->projectile>0) them = e->modeldata.projectilehit;
11673 	else them = e->modeldata.candamage;
11674 
11675 	// Every attack gets a unique ID to make sure no one
11676 	// gets hit more than once by the same attack
11677 	current_attack_id = e->attack_id;
11678 
11679 	if(!current_attack_id)
11680 	{
11681 		++new_attack_id;
11682 		if(new_attack_id==0) new_attack_id = 1;
11683 		e->attack_id = current_attack_id = new_attack_id;
11684 	}
11685 
11686 	force = attack->attack_force;
11687 	current_anim = e->animation;
11688 
11689 	for(i=0; i<ent_max && !followed; i++)
11690 	{
11691 
11692 		// if #0
11693 		if( ent_list[i]->exists &&
11694 			!ent_list[i]->dead && // dont hit the dead
11695 			(ent_list[i]->invincible != 1 || attack->attack_type == ATK_ITEM) && // so invincible people can get items
11696 			!(current_anim->attackone>0 && e->lasthit && ent_list[i]!=e->lasthit) &&
11697 			(ent_list[i]->modeldata.type & them) &&
11698 			(ent_list[i]->pain_time<time || e->animation->fastattack) &&
11699 			ent_list[i]->takedamage &&
11700 			ent_list[i]->hit_by_attack_id != current_attack_id &&
11701 			((ent_list[i]->takeaction != common_lie && attack->otg < 2) || (attack->otg >= 1 && ent_list[i]->takeaction == common_lie)) && //over the ground hit
11702 			((ent_list[i]->falling == 0 && attack->jugglecost >= 0) || (ent_list[i]->falling == 1 && attack->jugglecost <= ent_list[i]->modeldata.jugglepoints.current)) && // juggle system
11703 			(checkhit(e, ent_list[i], 0) || // normal check bbox
11704 			 (attack->counterattack && checkhit(e, ent_list[i], 1)))  )// check counter, e.g. upper
11705 		{
11706 			temp = self;
11707 			self = ent_list[i];
11708 
11709 			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.
11710 			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.
11711 
11712 			if(!lasthitc){	return;	}	//12312010, DC: Allows modder to cancel engine's attack handling. Useful for parry systems, alternate blocking, or other scripted hit events.
11713 
11714 			didhit = 1;
11715 
11716 			otherowner = self; // trace top owner for opponent
11717 			while(otherowner->owner) otherowner = otherowner->owner;
11718 
11719 			//if #01, if they are fired by the same owner, or the owner itself
11720 			if(topowner == otherowner) didhit = 0;
11721 
11722 			//if #02 , ground missle checking, and bullets wont hit each other
11723 			if( (e->owner && self->owner) ||
11724 				(e->modeldata.ground && inair(e))  )
11725 			{
11726 				didhit = 0;
11727 			}//end of if #02
11728 
11729 			//if #05,   blocking code section
11730 			if(didhit)
11731 			{
11732 				if(attack->attack_type == ATK_ITEM){
11733 					 didfind_item(e);
11734 					 execute_didhit_script(e, self, force, attack->attack_drop, self->modeldata.subtype, attack->no_block, attack->guardcost, attack->jugglecost, attack->pause_add, 1);
11735 					 return;
11736 				}
11737 				//if #051
11738 				if(self->toexplode == 1) self->toexplode = 2;    // Used so the bomb type entity explodes when hit
11739 				//if #052
11740 				if(e->toexplode == 1) e->toexplode = 2;    // Used so the bomb type entity explodes when hitting
11741 
11742 				if(inair(self)) self->modeldata.jugglepoints.current = self->modeldata.jugglepoints.current - attack->jugglecost; //reduce available juggle points.
11743 
11744 				//if #053
11745 				if( !self->modeldata.nopassiveblock && // cant block by itself
11746 					validanim(self,ANI_BLOCK) && // of course, move it here to avoid some useless checking
11747 					((self->modeldata.guardpoints.maximum == 0) || (self->modeldata.guardpoints.maximum > 0 && self->modeldata.guardpoints.current > 0)) &&
11748 					!(self->link ||
11749 					inair(self) ||
11750 					self->frozen ||
11751 					(self->direction == e->direction && self->modeldata.blockback < 1) ||                       // Can't block an attack that is from behind unless blockback flag is enabled
11752 					(!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
11753 					attack->no_block <= self->modeldata.defense_blockpower[(short)attack->attack_type] &&       // If unblockable, will automatically hit
11754 					(rand32()&self->modeldata.blockodds) == 1 &&                                                // Randomly blocks depending on blockodds (1 : blockodds ratio)
11755 					(!self->modeldata.thold || (self->modeldata.thold > 0 && self->modeldata.thold > force))&&
11756 					(!fdefense_blockthreshold ||                                                                //Specific attack type threshold.
11757 					(fdefense_blockthreshold > force)))
11758 				{   //execute the didhit script
11759 					execute_didhit_script(e, self, force, attack->attack_drop, attack->attack_type, attack->no_block, attack->guardcost, attack->jugglecost, attack->pause_add, 1);
11760 					set_blocking(self);
11761 					self->xdir = self->zdir = 0;
11762 					ent_set_anim(self, ANI_BLOCK, 0);
11763 					self->takeaction = common_block;
11764 					execute_didblock_script(self, e, force, attack->attack_drop, attack->attack_type, attack->no_block, attack->guardcost, attack->jugglecost, attack->pause_add);
11765 					if(self->modeldata.guardpoints.maximum > 0) self->modeldata.guardpoints.current = self->modeldata.guardpoints.current - attack->guardcost;
11766 					++e->animation->animhits;
11767 					didblock = 1;    // Used for when playing the block.wav sound
11768 					// Spawn a flash
11769 					//if #0531
11770 					if(!attack->no_flash)
11771 					{
11772 						if(!self->modeldata.noatflash)
11773 						{
11774 							if(attack->blockflash>=0) flash = spawn(lasthitx, lasthitz, lasthita, 0, NULL, attack->blockflash, NULL); // custom bflash
11775 							else flash = spawn(lasthitx,lasthitz,lasthita, 0, NULL, ent_list[i]->modeldata.bflash, NULL);    // New block flash that can be smaller
11776 						}
11777 						else flash = spawn(lasthitx,lasthitz,lasthita, 0, NULL, self->modeldata.bflash, NULL);
11778 						//ent_default_init(flash); // initiliaze this because there're no default values now
11779 
11780 						if(flash) execute_onspawn_script(flash);
11781 					}
11782 					//end of if #0531
11783 				}
11784 				else if(self->modeldata.nopassiveblock && // can block by itself
11785 					self->blocking &&  // of course he must be blocking
11786 					((self->modeldata.guardpoints.maximum == 0) || (self->modeldata.guardpoints.maximum > 0 && self->modeldata.guardpoints.current > 0)) &&
11787 					!((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
11788 					attack->no_block <= self->modeldata.defense_blockpower[(short)attack->attack_type] &&    // Make sure you are actually blocking and that the attack is blockable
11789 					(!self->modeldata.thold ||
11790 					(self->modeldata.thold > 0 &&
11791 					self->modeldata.thold > force))&&
11792 					(!self->modeldata.defense_blockthreshold[(short)attack->attack_type] ||                   //Specific attack type threshold.
11793 					(self->modeldata.defense_blockthreshold[(short)attack->attack_type] > force)))
11794 				{    // Only block if the attack is less than the players threshold
11795 					//execute the didhit script
11796 					execute_didhit_script(e, self, force, attack->attack_drop, attack->attack_type, attack->no_block, attack->guardcost, attack->jugglecost, attack->pause_add, 1);
11797 					if(self->modeldata.guardpoints.maximum > 0) self->modeldata.guardpoints.current = self->modeldata.guardpoints.current - attack->guardcost;
11798 					++e->animation->animhits;
11799 					didblock = 1;    // Used for when playing the block.wav sound
11800 
11801 					if(self->modeldata.blockpain && self->modeldata.blockpain <= force && self->animation == self->modeldata.animation[ANI_BLOCK]) //Blockpain 1 and in block animation?
11802 					{
11803 						set_blockpain(self, attack->attack_type, 0);
11804 					}
11805 					execute_didblock_script(self, e, force, attack->attack_drop, attack->attack_type, attack->no_block, attack->guardcost, attack->jugglecost, attack->pause_add);
11806 
11807 					// Spawn a flash
11808 					if(!attack->no_flash)
11809 					{
11810 						if(!self->modeldata.noatflash)
11811 						{
11812 							if(attack->blockflash>=0) flash = spawn(lasthitx, lasthitz, lasthita, 0, NULL, attack->blockflash, NULL); // custom bflash
11813 							else flash = spawn(lasthitx,lasthitz,lasthita, 0, NULL, ent_list[i]->modeldata.bflash, NULL);    // New block flash that can be smaller
11814 						}
11815 						else flash = spawn(lasthitx,lasthitz,lasthita, 0, NULL, self->modeldata.bflash, NULL);
11816 						//ent_default_init(flash); // initiliaze this because there're no default values now
11817 						if(flash) execute_onspawn_script(flash);
11818 					}
11819 				}
11820 				else if((self->animpos >= self->animation->counterrange.framestart && self->animpos <= self->animation->counterrange.frameend)  &&	//Within counter range?
11821 					!self->frozen)// &&																								//Not frozen?
11822 					//(self->animation->counterrange.condition <= 1 && e->modeldata.type & them)) //&&												//Friend/foe?
11823 					//(self->animation->counterrange.condition <= 3 && !attack->no_block) &&														//Counter attack self couldn't block?
11824 					//self->animation->counterrange.condition <= 2 ||
11825 					//self->animation->counterrange.condition <= 2 || !(self->direction == e->direction)) //&&										//Direction check.
11826 					//(self->animation->counterrange.condition <= 3 || !attack->freeze))															//Freeze attacks?
11827 
11828 					//&& (!self->animation->counterrange.damaged || self->health > force))													// Does damage matter?
11829 				{
11830 					if(self->animation->counterrange.damaged) self->health -= force;					// Take damage?
11831 					current_follow_id = animfollows[self->animation->followanim - 1];
11832 					if(validanim(self,current_follow_id))
11833 					{
11834 						if(self->modeldata.animation[current_follow_id]->attackone==-1)
11835 							self->modeldata.animation[current_follow_id]->attackone = self->animation->attackone;
11836 						ent_set_anim(self, current_follow_id, 0);
11837 						self->hit_by_attack_id = current_attack_id;
11838 					}
11839 
11840 					if(!attack->no_flash)
11841 					{
11842 						if(!self->modeldata.noatflash)
11843 						{
11844 							if(attack->blockflash>=0) flash = spawn(lasthitx, lasthitz, lasthita, 0, NULL, attack->blockflash, NULL); // custom bflash
11845 							else flash = spawn(lasthitx,lasthitz,lasthita, 0, NULL, ent_list[i]->modeldata.bflash, NULL);    // New block flash that can be smaller
11846 						}
11847 						else flash = spawn(lasthitx,lasthitz,lasthita, 0, NULL, self->modeldata.bflash, NULL);
11848 						//ent_default_init(flash); // initiliaze this because there're no default values now
11849 						if(flash) execute_onspawn_script(flash);
11850 					}
11851 				}
11852 				else if(self->takedamage(e, attack))
11853 				{    // Didn't block so go ahead and take the damage
11854 					//printf("*%d*", current_attack_id);
11855 					execute_didhit_script(e, self, force, attack->attack_drop, attack->attack_type, attack->no_block, attack->guardcost, attack->jugglecost, attack->pause_add, 0);
11856 					++e->animation->animhits;
11857 
11858 					e->lasthit = self;
11859 
11860 					// Spawn a flash
11861 					if(!attack->no_flash)
11862 					{
11863 						if(!self->modeldata.noatflash)
11864 						{
11865 							if(attack->hitflash>=0) flash = spawn(lasthitx, lasthitz, lasthita, 0, NULL, attack->hitflash, NULL);
11866 							else flash = spawn(lasthitx, lasthitz, lasthita, 0, NULL, e->modeldata.flash, NULL);
11867 						}
11868 						else flash = spawn(lasthitx,lasthitz,lasthita, 0, NULL, self->modeldata.flash, NULL);
11869 						if(flash) execute_onspawn_script(flash);
11870 					}
11871 					topowner->combotime = time + combodelay; // well, add to its owner's combo
11872 
11873 					if(e->animpos != e->lastanimpos || (inair(e) && !equalairpause))          // if equalairpause is set, inair(e) is nolonger a condition for extra pausetime
11874 					{    // Adds pause to the current animation
11875 						e->toss_time += attack->pause_add;      // So jump height pauses in midair
11876 						e->nextanim += attack->pause_add;       //Pause animation for a bit
11877 						e->nextthink += attack->pause_add;      // So anything that auto moves will pause
11878 					}
11879 
11880 					e->lastanimpos = e->animpos;
11881 
11882 					self->toss_time += attack->pause_add;       // So jump height pauses in midair
11883 					self->nextanim += attack->pause_add;        //Pause animation for a bit
11884 					self->nextthink += attack->pause_add;       // So anything that auto moves will pause
11885 
11886 				}
11887 				else
11888 				{
11889 					didhit = 0;
11890 					continue;
11891 				}
11892 				// end of if #053
11893 
11894 				// if #054
11895 				if(flash && !attack->no_flash)
11896 				{
11897 					if(flash->modeldata.toflip) flash->direction = (e->x > self->x);    // Now the flash will flip depending on which side the attacker is on
11898 
11899 					flash->base = lasthita;
11900 					flash->autokill = 1;
11901 				}//end of if #054
11902 
11903 				// 2007 3 24, hmm, def should be like this
11904 				if(didblock && !def)  def = self;
11905 				//if #055
11906 				if((e->animation->followanim) &&                                        // follow up?
11907 					(e->animation->counterrange.framestart == -1) &&                                // This isn't suppossed to be a counter, right?
11908 					((e->animation->followcond < 2) || (self->modeldata.type & them)) &&    // Does type matter?
11909 					((e->animation->followcond < 3) || ((self->health > 0) &&
11910 					!didblock)) &&                   // check if health or blocking matters
11911 					((e->animation->followcond < 4) || cangrab(e,self))  )// check if nograb matters
11912 				{
11913 					current_follow_id = animfollows[e->animation->followanim-1];
11914 					if(validanim(e,current_follow_id))
11915 					{
11916 						if(e->modeldata.animation[current_follow_id]->attackone==-1)
11917 							e->modeldata.animation[current_follow_id]->attackone = e->animation->attackone;
11918 						ent_set_anim(e, current_follow_id, 1);          // Then go to it!
11919 					}
11920 					//followed = 1; // quit loop, animation is changed
11921 				}//end of if #055
11922 
11923 				self->hit_by_attack_id = current_attack_id;
11924 				if(self==def) self->blocking = didblock; // yeah, if get hit, stop blocking
11925 			}//end of if #05
11926 			self = temp;
11927 		}//end of if #0
11928 
11929 	}//end of for
11930 
11931 
11932 	// if ###
11933 	if(didhit)
11934 	{
11935 		// well, dont check player or not - UTunnels. TODO: take care of that healthcheat
11936 		if(e==topowner && current_anim->energycost.cost > 0 && nocost && !healthcheat) e->tocost = 1;    // Set flag so life is subtracted when animation is finished
11937 		else if(e!=topowner && current_anim->energycost.cost > 0 && nocost && !healthcheat && !e->tocost) // if it is not top, then must be a shot
11938 		{
11939 			if(current_anim->energycost.mponly != 2 && topowner->mp > 0)
11940 			{
11941 				topowner->mp -= current_anim->energycost.cost;
11942 				if(topowner->mp < 0) topowner->mp = 0;
11943 			}
11944 			else
11945 			{
11946 				topowner->health -= current_anim->energycost.cost;
11947 				if(topowner->health <= 0) topowner->health = 1;
11948 			}
11949 
11950 			topowner->cantfire = 0;    // Life subtracted, so go ahead and allow firing
11951 			e->tocost = 1;    // Little backwards, but set to 1 so cost doesn't get subtracted multiple times
11952 		}
11953 		// New blocking checks
11954 		//04/27/2008 Damon Caskey: Added checks for defense property specfic blockratio and type. Could probably use some cleaning.
11955 		if(didblock)
11956 		{
11957 			if(blockratio || def->modeldata.defense_blockratio[(short)attack->attack_type]) // Is damage reduced?
11958 			{
11959 				if (def->modeldata.defense_blockratio[(short)attack->attack_type]){                      //Typed blockratio?
11960 					force = (int)(force * def->modeldata.defense_blockratio[(short)attack->attack_type]);
11961 				}else{                                                                            //No typed. Use static block ratio.
11962 					force = force / 4;
11963 				}
11964 
11965 				if(mpblock && !def->modeldata.defense_blocktype[(short)attack->attack_type]){                                                                                 // Drain MP bar first?
11966 					def->mp -= force;
11967 					if(def->mp < 0)
11968 					{
11969 						force = -def->mp;
11970 						def->mp = 0;
11971 					}
11972 					else force = 0;                                                               // Damage removed from MP!
11973 				}else if(def->modeldata.defense_blocktype[(short)attack->attack_type]==1){                //Damage from MP only for this attack type.
11974 					def->mp -= force;
11975 					if(def->mp < 0){
11976 						force = -def->mp;
11977 						def->mp = 0;
11978 					}
11979 					else force = 0;                                                               // Damage removed from MP!
11980 				}else if(def->modeldata.defense_blocktype[(short)attack->attack_type]==2){              //Damage from both HP and MP at once.
11981 					def->mp -= force;
11982 				}else if(def->modeldata.defense_blocktype[(short)attack->attack_type]==-1){             //Health only?
11983 					//Do nothing. This is so modders can overidde energycost.mponly 1 with health only.
11984 				}
11985 
11986 				if(force < def->health)                    // If an attack won't deal damage, this line won't do anything anyway.
11987 					def->health -= force;
11988 				else if(nochipdeath)                       // No chip deaths?
11989 					def->health = 1;
11990 				else
11991 				{
11992 					temp = self;
11993 					self = def;
11994 					self->takedamage(e, attack);           // Must be a fatal attack, then!
11995 					self = temp;
11996 				}
11997 			}
11998 		}
11999 
12000 		if(!didblock)
12001 		{
12002 			topowner->rushtime = time + (GAME_SPEED*rush[1]);
12003 			topowner->rush[0]++;
12004 			if(topowner->rush[0] > topowner->rush[1] && topowner->rush[0] > 1) topowner->rush[1] = topowner->rush[0];
12005 		}
12006 
12007 		if(didblock)
12008 		{
12009 			if(attack->blocksound >= 0) sound_play_sample(attack->blocksound, 0, savedata.effectvol,savedata.effectvol, 100); // New custom block sound effect
12010 			else if(SAMPLE_BLOCK >= 0) sound_play_sample(SAMPLE_BLOCK, 0, savedata.effectvol,savedata.effectvol, 100);    // Default block sound effect
12011 		}
12012 		else if(e->projectile > 0 && SAMPLE_INDIRECT >= 0) sound_play_sample(SAMPLE_INDIRECT, 0, savedata.effectvol,savedata.effectvol, 100);
12013 		else
12014 		{
12015 			if(noslowfx)
12016 			{
12017 				if(attack->hitsound >= 0) sound_play_sample(attack->hitsound, 0, savedata.effectvol,savedata.effectvol, 100);
12018 				else if(SAMPLE_BEAT >= 0) sound_play_sample(SAMPLE_BEAT, 0, savedata.effectvol,savedata.effectvol, 100);
12019 			}
12020 			else
12021 			{
12022 				if(attack->hitsound >= 0) sound_play_sample(attack->hitsound, 0, savedata.effectvol,savedata.effectvol, 105 - force);
12023 				else if(SAMPLE_BEAT >= 0) sound_play_sample(SAMPLE_BEAT, 0, savedata.effectvol,savedata.effectvol, 105 - force);
12024 			}
12025 		}
12026 
12027 		if(e->remove_on_attack) kill(e);
12028 	}//end of if ###
12029 #undef followed
12030 }
12031 
12032 
check_gravity()12033 void check_gravity()
12034 {
12035 	int heightvar;
12036 	entity* other, *dust;
12037 	s_attack attack;
12038 
12039 	if(!is_frozen(self) )// Incase an entity is in the air, don't update animations
12040 	{
12041 		if((self->falling || self->tossv || self->a!=self->base) && self->toss_time <= time && !self->animation->dive.x && !self->animation->dive.v)
12042 		{
12043 			if(self->modeldata.subject_to_platform>0 && self->tossv>0)
12044 				other = check_platform_above(self->x, self->z, self->a+self->tossv, self);
12045 			else other = NULL;
12046 
12047 			if(self->animation->height) heightvar = self->animation->height;
12048 			else heightvar = self->modeldata.height;
12049 
12050 			if( other && other->a<=self->a+heightvar)
12051 			{
12052 				if(self->hithead == NULL) // bang! Hit the ceiling.
12053 				{
12054 					self->tossv = 0;
12055 					self->hithead = other;
12056 					execute_onblocka_script(self, other);
12057 				}
12058 			}
12059 			else self->hithead = NULL;
12060 			// gravity, antigravity factors
12061 			self->a += self->tossv;
12062 			if(self->modeldata.subject_to_gravity>0)
12063 				self->tossv += level->gravity * (1.0-self->modeldata.antigravity-self->antigravity);
12064 
12065 			if(self->tossv < level->maxfallspeed)
12066 			{
12067 				self->tossv = level->maxfallspeed;
12068 			}
12069 			else if(self->tossv > level->maxtossspeed)
12070 			{
12071 				self->tossv = level->maxtossspeed;
12072 			}
12073 			if(self->animation->dropframe>=0 && self->tossv<=0 && self->animpos<self->animation->dropframe) // begin dropping
12074 			{
12075 				update_frame(self, self->animation->dropframe);
12076 			}
12077 			if (self->tossv) execute_onmovea_script(self); //Move A event.
12078 
12079 			if(self->idling && validanim(self, ANI_WALKOFF))
12080 			{
12081 				self->idling = 0;
12082 				self->takeaction = common_walkoff;
12083 				ent_set_anim(self, ANI_WALKOFF, 0);
12084 			}
12085 
12086 			// UTunnels: tossv <= 0 means land, while >0 means still rising, so
12087 			// you wont be stopped if you are passing the edge of a wall
12088 			if( (self->a<=self->base || !inair(self)) && self->tossv <= 0)
12089 			{
12090 				self->a = self->base;
12091 				self->falling = 0;
12092 				//self->projectile = 0;
12093 				// cust dust entity
12094 				if(self->modeldata.dust[0]>=0 && self->tossv < -1 && self->drop)
12095 				{
12096 					dust = spawn(self->x, self->z, self->a, self->direction, NULL, self->modeldata.dust[0], NULL);
12097 					if(dust){
12098 						dust->base = self->a;
12099 						dust->autokill = 1;
12100 						execute_onspawn_script(dust);
12101 					}
12102 				}
12103 				// bounce/quake
12104 				if(tobounce(self) && self->modeldata.bounce)
12105 				{
12106 					int i;
12107 					self->xdir /= self->animation->bounce;
12108 					self->zdir /= self->animation->bounce;
12109 					toss(self, (-self->tossv)/self->animation->bounce);
12110 					if(!self->modeldata.noquake) level->quake = 4;    // Don't shake if specified
12111 					if(SAMPLE_FALL >= 0) sound_play_sample(SAMPLE_FALL, 0, savedata.effectvol,savedata.effectvol, 100);
12112 					if(self->modeldata.type == TYPE_PLAYER) control_rumble(self->playerindex, 100*(int)self->tossv/2);
12113 					for(i=0; i<MAX_PLAYERS; i++) control_rumble(i, 75*(int)self->tossv/2);
12114 				}
12115 				else if((!self->animation->seta || self->animation->seta[self->animpos]<0) &&
12116 					(!self->animation->movea || self->animation->movea[self->animpos]<=0))
12117 						self->xdir = self->zdir = self->tossv= 0;
12118 				else self->tossv = 0;
12119 
12120 				if(self->animation->landframe.frame>=0                                 //Has landframe?
12121                     && self->animation->landframe.frame<= self->animation->numframes   //Not over animation frame count?
12122                     && self->animpos < self->animation->landframe.frame)               //Not already past landframe?
12123 				{
12124 					if(self->animation->landframe.ent>=0)
12125 					{
12126 						dust = spawn(self->x, self->z, self->a, self->direction, NULL, self->animation->landframe.ent, NULL);
12127 						if(dust){
12128 							dust->base = self->a;
12129 							dust->autokill = 1;
12130 							execute_onspawn_script(dust);
12131 						}
12132 					}
12133 					update_frame(self, self->animation->landframe.frame);
12134 				}
12135 
12136 				// takedamage if thrown or basted
12137 				if(self->damage_on_landing > 0 && !self->dead)
12138 				{
12139 					if(self->takedamage)
12140 
12141 					{
12142 						attack              = emptyattack;
12143 						attack.attack_force = self->damage_on_landing;
12144 						attack.attack_type  = self->damagetype;
12145 						self->takedamage(self, &attack);
12146 					}
12147 					else
12148 					{
12149 						self->health -= self->damage_on_landing;
12150 						if(self->health <=0 ) kill(self);
12151 						self->damage_on_landing = 0;
12152 					}
12153 				}
12154 				// in case landing, set hithead to NULL
12155 				self->hithead = NULL;
12156 			}// end of if - land checking
12157 			self->toss_time = time + (GAME_SPEED/100);
12158 		}// end of if  - in-air checking
12159 
12160 	}//end of if
12161 }
12162 
check_lost()12163 void check_lost()
12164 {
12165 	s_attack attack;
12166 	int osk = self->modeldata.offscreenkill?self->modeldata.offscreenkill:DEFAULT_OFFSCREEN_KILL;
12167 
12168 	if((self->z!=100000 && (advancex - self->x>osk || self->x - advancex - videomodes.hRes>osk ||
12169 		(level->scrolldir!=SCROLL_UP && level->scrolldir!=SCROLL_DOWN && (advancey - self->z>osk || self->z - advancey - videomodes.vRes>osk)) ||
12170 		((level->scrolldir==SCROLL_UP || level->scrolldir==SCROLL_DOWN) && (self->z<-osk || self->z>videomodes.vRes + osk))		) )
12171 		|| self->a < 2*PIT_DEPTH) //self->z<100000, so weapon item won't be killed
12172 	{
12173 		if(self->modeldata.type==TYPE_PLAYER)
12174 		player_die();
12175 		else
12176 		kill(self);
12177 		return;
12178 	}
12179 	// fall in to a pit
12180 	if(self->a < PIT_DEPTH || self->lifespancountdown<0)
12181 	{
12182 		if(!self->takedamage) kill(self);
12183 		else
12184 		{
12185 			attack              = emptyattack;
12186 			attack.dropv[0]     = (float)3; attack.dropv[1] = (float)1.2; attack.dropv[2] = (float)0;
12187 			attack.attack_force = self->health;
12188 			attack.attack_type  = max_attack_types;
12189 			self->takedamage(self, &attack);
12190 		}
12191 		return;
12192 	}//else
12193 	// Doom count down
12194 	if(!is_frozen(self) && self->lifespancountdown != (float)0xFFFFFFFF) self->lifespancountdown--;
12195 }
12196 
12197 // grab walk check
check_link_move(float xdir,float zdir)12198 void check_link_move(float xdir, float zdir)
12199 {
12200 	float x, z, gx, gz;
12201 	int tryresult;
12202 	entity* tempself = self;
12203 	gx = self->grabbing->x; gz = self->grabbing->z;
12204 	x = self->x; z = self->z;
12205 	self = self->grabbing;
12206 	tryresult = self->trymove(xdir, zdir);
12207 	self = tempself;
12208 	if(tryresult!=1) // changed
12209 	{
12210 		xdir = self->grabbing->x - gx;
12211 		zdir = self->grabbing->z - gz;
12212 	}
12213 	tryresult = self->trymove(xdir, zdir);
12214 	if(tryresult != 1)
12215 	{
12216 		self->grabbing->x = self->x - x + gx;
12217 		self->grabbing->z = self->z - z + gz;
12218 	}
12219 }
12220 
check_ai()12221 void check_ai()
12222 {
12223 	entity* plat;
12224 	// check moving platform
12225 	if((plat=self->landed_on_platform) &&
12226 		(plat->xdir || plat->zdir) &&
12227 		(plat->nextthink <= time || (plat->update_mark & 2)) &&// plat is updated before self or will be updated this loop
12228 		testplatform(plat,self->x,self->z, NULL) &&
12229 		self->a <= plat->a + plat->animation->platform[plat->animpos][7] ) // on the platform?
12230 	{
12231 		// passive move with the platform
12232 		if(self->trymove )
12233 		{
12234 			// grab walk check
12235 			if(self->grabbing && self->grabwalking && self->grabbing->trymove)
12236 			{
12237 				check_link_move(plat->xdir, plat->zdir);
12238 			}
12239 			else self->trymove(plat->xdir, plat->zdir);
12240 		}
12241 		else
12242 		{
12243 			self->x += plat->xdir;
12244 			self->z += plat->zdir;
12245 		}
12246 	}
12247 
12248 	if(self->nextthink <= time && !endgame)
12249 	{
12250 		self->update_mark |= 2; //mark it
12251 		// take actions
12252 		if(self->takeaction) self->takeaction();
12253 
12254 		// A.I. think
12255 		if(self->think)
12256 		{
12257 			if(self->nextthink<=time) self->nextthink = time + THINK_SPEED;
12258 			// use noaicontrol flag to turn of A.I. think
12259 			if(!self->noaicontrol) self->think();
12260 		}
12261 
12262 		// Execute think script
12263 		execute_think_script(self);
12264 
12265 		// A.I. move
12266 		if (self->xdir || self->zdir)
12267 		{
12268 			if(self->trymove)
12269 			{
12270 				// grab walk check
12271 				if(self->grabbing && self->grabwalking && self->grabbing->trymove)
12272 				{
12273 					check_link_move(self->xdir, self->zdir);
12274 				}
12275 				else if(self->trymove(self->xdir, self->zdir)!=1 && self->idling)
12276 				{
12277 					self->pathblocked++; // for those who walk against wall or borders
12278 				}
12279 				else
12280 				{
12281 					self->pathblocked = 0;
12282 				}
12283 			}
12284 			else
12285 			{
12286 				self->x += self->xdir;
12287 				self->z += self->zdir;
12288 			}
12289 		}
12290 		// Used so all entities can have a spawn animation, and then just changes to the idle animation when done
12291 		// move here to so players wont get stuck
12292 		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);
12293 	}
12294 }
12295 
12296 
update_animation()12297 void update_animation()
12298 {
12299 	int f, wall, hole;
12300 	float move, movez, seta;
12301 	entity *other = NULL;
12302 
12303 	if(level)
12304 	{
12305 		if(self->modeldata.facing == 1 || level->facing == 1) self->direction = 1;
12306 		else if(self->modeldata.facing == 2 || level->facing == 2) self->direction = 0;
12307 		else if((self->modeldata.facing == 3 || level->facing == 3) && (level->scrolldir & SCROLL_RIGHT)) self->direction = 1;
12308 		else if((self->modeldata.facing == 3 || level->facing == 3) && (level->scrolldir & SCROLL_LEFT)) self->direction = 0;
12309 		if(self->modeldata.type == TYPE_PANEL)
12310 		{
12311 			self->x += scrolldx * ((float)(self->modeldata.speed));
12312 			if(level->scrolldir==SCROLL_UP)
12313 			{
12314 				self->a += scrolldy * ((float)(self->modeldata.speed));
12315 			}
12316 			else if(level->scrolldir==SCROLL_DOWN)
12317 			{
12318 				self->a -= scrolldy * ((float)(self->modeldata.speed));
12319 			}
12320 			else
12321 			{
12322 				self->a -= scrolldy * ((float)(self->modeldata.speed));
12323 			}
12324 		}
12325 		if(self->modeldata.scroll)
12326 		{
12327 			self->x += scrolldx * ((float)(self->modeldata.scroll));
12328 			if(level->scrolldir==SCROLL_UP)
12329 			{
12330 				self->a += scrolldy * ((float)(self->modeldata.scroll));
12331 			}
12332 			else if(level->scrolldir==SCROLL_DOWN)
12333 			{
12334 				self->a -= scrolldy * ((float)(self->modeldata.scroll));
12335 			}
12336 			else
12337 			{
12338 				self->a -= scrolldy * ((float)(self->modeldata.scroll));
12339 			}
12340 		}
12341 	}
12342 
12343 	if(self->invincible && time >= self->invinctime)    // Invincible time has run out, turn off
12344 	{
12345 		self->invincible    = 0;
12346 		self->blink         = 0;
12347 		self->invinctime    = 0;
12348 		self->arrowon       = 0;
12349 	}
12350 
12351 	if(self->freezetime && time >= self->freezetime)
12352 	{
12353 		unfrozen(self);
12354 	}
12355 
12356 	if(self->maptime && time >= self->maptime)
12357 	{
12358 		ent_set_colourmap(self, self->map);
12359 	}
12360 
12361 	if(self->sealtime && time >= self->sealtime) //Remove seal, special moves are available again.
12362 	{
12363 		self->seal = 0;
12364 	}
12365 
12366 	if(self->nextanim == time ||
12367 		(self->modeldata.type == TYPE_TEXTBOX && self->modeldata.subtype != SUBTYPE_NOSKIP &&
12368 		 (bothnewkeys&(FLAG_JUMP|FLAG_ATTACK|FLAG_ATTACK2|FLAG_ATTACK3|FLAG_ATTACK4|FLAG_SPECIAL))))// Textbox will autoupdate if a valid player presses an action button
12369 	{    // Now you can display text and cycle through with any jump/attack/special unless SUBTYPE_NOSKIP
12370 
12371 		f = self->animpos + self->animating;
12372 
12373 		//Specified loop break frame.
12374 		if(self->animation->loop.mode && self->animation->loop.frameend)
12375 		{
12376 			if (f == self->animation->loop.frameend)
12377 			{
12378 				if(f<0) f = self->animation->numframes-1;
12379 				else f = 0;
12380 
12381 				if (self->animation->loop.framestart)
12382 				{
12383 					f = self->animation->loop.framestart;
12384 				}
12385 			}
12386 			else if((unsigned)f >= (unsigned)self->animation->numframes)
12387 			{
12388 				self->animating = 0;
12389 
12390 				if(self->autokill)
12391 				{
12392 					kill(self);
12393 					return;
12394 				}
12395 			}
12396 		}
12397 		else if((unsigned)f >= (unsigned)self->animation->numframes)
12398 		{
12399 			if(f<0) f = self->animation->numframes-1;
12400 			else f = 0;
12401 
12402 			if(!self->animation->loop.mode)
12403 			{
12404 				self->animating = 0;
12405 
12406 				if(self->autokill)
12407 				{
12408 					kill(self);
12409 					return;
12410 				}
12411 			}
12412 			else
12413 			{
12414 				if (self->animation->loop.framestart)
12415 				{
12416 					f = self->animation->loop.framestart;
12417 				}
12418 			}
12419 		}
12420 
12421 		if(self->animating)
12422 		{
12423 			//self->nextanim = time + (self->animation->delay[f]);
12424 			self->update_mark |= 1; // frame updated, mark it
12425 			// just switch frame to f, if frozen, expand_time will deal with it well
12426 			update_frame(self, f);
12427 		}
12428 	}
12429 
12430 	if(self->modeldata.subject_to_platform>0)
12431 	{
12432 		other = self->landed_on_platform;
12433 		if(other && testplatform(other, self->x, self->z, NULL) && self->a <= other->a + other->animation->platform[other->animpos][7])
12434 		{
12435 			self->a = self->base = other->a + other->animation->platform[other->animpos][7];
12436 		}
12437 		else other = check_platform_below(self->x, self->z, self->a, self);
12438 	}
12439 	else other = NULL;
12440 	self->landed_on_platform = other;
12441 	// adjust base
12442 	if(self->modeldata.no_adjust_base<=0)
12443 	{
12444 		seta = (float)((self->animation->seta)?(self->animation->seta[self->animpos]):(-1));
12445 
12446 		// Checks to see if entity is over a wall and or obstacle, and adjusts the base accordingly
12447 		//wall = checkwall_below(self->x, self->z);
12448 		//find a wall below us
12449 		if(self->modeldata.subject_to_wall>0)
12450 			wall = checkwall_below(self->x, self->z, self->a);
12451 		else wall = -1;
12452 
12453 		if(self->modeldata.subject_to_hole>0)
12454 		{
12455 			hole = (wall<0&&!other)?checkhole(self->x, self->z):0;
12456 
12457 			if(seta<0 && hole)
12458 			{
12459 				self->base=-1000;
12460 				ent_unlink(self);
12461 			}
12462 			else if(!hole && self->base == -1000)
12463 			{
12464 				 if(self->a>=0) self->base = 0;
12465 				 else
12466 				 {
12467 					 self->xdir = self->zdir = 0; // hit the hole border
12468 				 }
12469 			}
12470 		}
12471 
12472 		if(self->base != -1000 || wall>=0)
12473 		{
12474 			if(other != NULL && other != self )
12475 			{
12476 				self->base = (seta + self->altbase >=0 ) * (seta+self->altbase) + (other->a + other->animation->platform[other->animpos][7]);
12477 			}
12478 			else if(wall >= 0)
12479 			{
12480 				//self->modeldata.subject_to_wall &&//we move this up to avoid some checking time
12481 				self->base = (seta + self->altbase >=0 ) * (seta+self->altbase) + (self->a >= level->walls[wall][7]) * level->walls[wall][7];
12482 			}
12483 			else if(seta >= 0) self->base = (seta + self->altbase >=0 ) * (seta+self->altbase);
12484 			else if(self->animation != self->modeldata.animation[ANI_VAULT] && (!self->animation->movea || self->animation->movea[self->animpos] == 0))
12485 			{
12486 				// Don't want to adjust the base if vaulting
12487 				// No obstacle/wall or seta, so just set to 0
12488 				self->base = 0;
12489 			}
12490 		}
12491 	}
12492 
12493 	// Code for when entities move (useful for moving platforms, etc)
12494 	if(other && other != self )
12495 	{
12496 		// a bit complex, other->nextanim == time means other is behind self and not been updated,
12497 		// update_mark & 1 means other is updated in this loop and before self
12498 		if((other->nextanim == time || (other->update_mark & 1)) && self->a <= other->a + other->animation->platform[other->animpos][7])
12499 		{
12500 			if(other->update_mark & 1) f = other->animpos;
12501 			else f = other->animpos + other->animating;
12502 			if(f >= other->animation->numframes)
12503 			{
12504 				if(f<0) f = other->animation->numframes-1;
12505 				else f = 0;
12506 			}
12507 			//printf("%d %d %d\n", other->nextanim, time, other->update_mark);
12508 			move = (float)(other->animation->move?other->animation->move[f]:0);
12509 			movez = (float)(other->animation->movez?other->animation->movez[f]:0);
12510 			if(other->direction==0) move = -move;
12511 			if(move||movez)
12512 			{
12513 				if(self->trymove)
12514 				{
12515 					self->trymove(move, movez);
12516 				}
12517 				else
12518 				{
12519 					self->z += movez;
12520 					self->x += move;
12521 				}
12522 			}
12523 		}
12524 	}
12525 }
12526 
check_attack()12527 void check_attack()
12528 {
12529 	// a normal fall
12530 	if(self->falling && !self->projectile)
12531 	{
12532 		self->attack_id = 0;
12533 		return;
12534 	}
12535 	// on ground
12536 	if(self->drop && !self->falling)
12537 	{
12538 		self->attack_id= 0;
12539 		return;
12540 	}
12541 
12542 	// Can't hit an opponent if you are frozen
12543 	if(!is_frozen(self) && self->animation->attacks &&
12544 		self->animation->attacks[self->animpos])
12545 	{
12546 		do_attack(self);
12547 		return;
12548 	}
12549 	self->attack_id = 0;
12550 }
12551 
12552 
update_health()12553 void update_health()
12554 {
12555 	//12/30/2008: Guardrate by OX. Guardpoints increase over time.
12556 	if(self->modeldata.guardpoints.maximum > 0 && time >= self->guardtime) // If this is > 0 then guardpoints are set..
12557 	{
12558 		if(self->blocking)
12559 		{
12560 			self->modeldata.guardpoints.current += (self->modeldata.guardrate/2);
12561 			if(self->modeldata.guardpoints.current > self->modeldata.guardpoints.maximum) self->modeldata.guardpoints.current = self->modeldata.guardpoints.maximum;
12562 		}
12563 		else
12564 		{
12565 			self->modeldata.guardpoints.current += self->modeldata.guardrate;
12566 			if(self->modeldata.guardpoints.current > self->modeldata.guardpoints.maximum) self->modeldata.guardpoints.current = self->modeldata.guardpoints.maximum;
12567 		}
12568 		self->guardtime = time + GAME_SPEED;    //Reset guardtime.
12569 	}
12570 
12571 	common_dot();   //Damage over time.
12572 
12573 	// this is for restoring mp by time by tails
12574 	// Cleaning and addition of mpstable by DC, 08172008.
12575 	// stabletype 4 added by OX 12272008
12576 	if(magic_type == 0 && !self->charging)
12577 	{
12578 		if(time >= self->magictime)
12579 		{
12580 
12581 			// 1 Only recover MP > mpstableval.
12582 			// 2 No recover. Drop MP if MP < mpstableval.
12583 			// 3 Both: recover if MP if MP < mpstableval and drop if MP > mpstableval.
12584 			// 0 Default. Recover MP at all times.
12585 
12586 
12587 			if (self->modeldata.mpstable == 1){
12588 				if (self->mp < self->modeldata.mpstableval) self->mp += self->modeldata.mprate;
12589 			}else if(self->modeldata.mpstable == 2){
12590 				if (self->mp > self->modeldata.mpstableval) self->mp -= self->modeldata.mpdroprate;
12591 			}else if (self->modeldata.mpstable == 3){
12592 				if (self->mp < self->modeldata.mpstableval)
12593 				{
12594 
12595 					self->mp += self->modeldata.mprate;
12596 				}
12597 				else if (self->mp > self->modeldata.mpstableval)
12598 				{
12599 					self->mp -= self->modeldata.mpdroprate;
12600 				}
12601 			}
12602 
12603 			// OX. Stabletype 4. Gain mp until it reaches max. Then it drops down to mpstableval.
12604 			else if (self->modeldata.mpstable == 4)
12605 			{
12606 				if(self->mp <= self->modeldata.mpstableval) self->modeldata.mpswitch = 0;
12607 				else if(self->mp == self->modeldata.mp) self->modeldata.mpswitch = 1;
12608 
12609 				if(self->modeldata.mpswitch == 1)
12610 				{
12611 					self->mp -= self->modeldata.mpdroprate;
12612 				}
12613 				else if(self->modeldata.mpswitch == 0)
12614 				{
12615 					self->mp += self->modeldata.mprate;
12616 				}
12617 			}
12618 			else
12619 			{
12620 				self->mp += self->modeldata.mprate;
12621 			}
12622 
12623 			self->magictime = time + GAME_SPEED;    //Reset magictime.
12624 		}
12625 	}
12626 	if(self->charging && time >= self->mpchargetime)
12627 	{
12628 		self->mp += self->modeldata.chargerate;
12629 		self->mpchargetime = time + (GAME_SPEED / 4);
12630 	}
12631 	if(self->mp > self->modeldata.mp) self->mp = self->modeldata.mp; // Don't want to add more than the max
12632 
12633 	if(self->oldhealth < self->health) self->oldhealth++;
12634 	else if(self->oldhealth > self->health) self->oldhealth--;
12635 
12636 	if(self->oldmp < self->mp) self->oldmp++;
12637 	else if(self->oldmp > self->mp) self->oldmp--;
12638 }
12639 
common_dot()12640 void common_dot()
12641 {
12642 	//common_dot
12643 	//Damon V. Caskey
12644 	//06172009
12645 	//Mitigates damage over time (dot). Moved here from update_health().
12646 
12647 	int         iFForce;    //Final force; total damage after defense and offense factors are applied.
12648 	int         iType;      //Attack type.
12649 	int         iIndex;     //Dot index.
12650 	int         iDot;       //Dot mode.
12651 	int         iDot_time;  //Dot expire time.
12652 	int         iDot_cnt;   //Dot next tick time.
12653 	int         iDot_rate;  //Dot tick rate.
12654 	int         iForce;     //Unmodified force.
12655 	float       fOffense;   //Owner's offense.
12656 	float       fDefense;   //Self defense.
12657 	entity*     eOpp;       //Owner of dot effect.
12658 	s_attack    attack;     //Attack struct.
12659 
12660 	for(iIndex=0; iIndex<MAX_DOTS; iIndex++)                                                   //Loop through all DOT indexes.
12661 	{
12662 		iDot_time   =   self->dot_time[iIndex];                                                 //Get expire time.
12663 		iDot_cnt    =   self->dot_cnt[iIndex];                                                  //Get next tick time.
12664 		iDot_rate   =   self->dot_rate[iIndex];                                                 //Get tick rate.
12665 
12666 		if(iDot_time)                                                                           //Dot time present?
12667 		{
12668 			if(time > iDot_time)                                                                //Dot effect expired? Then clear variants.
12669 			{
12670 				self->dot[iIndex]       = 0;
12671 				self->dot_atk[iIndex]   = 0;
12672 				self->dot_cnt[iIndex]   = 0;
12673 				self->dot_rate[iIndex]  = 0;
12674 				self->dot_time[iIndex]  = 0;
12675 				self->dot_force[iIndex] = 0;
12676 			}
12677 			else if(time >= iDot_cnt && self->health>=0)                                        //Time for a dot tick and alive?
12678 			{
12679 				self->dot_cnt[iIndex] = time + (iDot_rate * GAME_SPEED / 100);                  //Reset next tick time.
12680 
12681 				iDot    =   self->dot[iIndex];                                                  //Get dot mode.
12682 				iForce  =   self->dot_force[iIndex];                                            //Get dot force.
12683 
12684 				if(iDot==1 || iDot==3 || iDot==4 || iDot==5)                                    //HP?
12685 				{
12686 					eOpp        = self->dot_owner[iIndex];                                      //Get dot effect owner.
12687 					iType       = self->dot_atk[iIndex];                                        //Get attack type.
12688 					iFForce     = iForce;                                                       //Initialize final force.
12689 					fOffense    = eOpp->modeldata.offense_factors[iType];                       //Get owner's offense.
12690 					fDefense    = self->modeldata.defense_factors[iType];                       //Get Self defense.
12691 
12692 					if (fOffense){  iFForce = (int)(iForce  * fOffense);    }                   //Apply offense factors.
12693 					if (fDefense){  iFForce = (int)(iFForce * fDefense);    }                   //Apply defense factors.
12694 
12695 					if(iFForce >= self->health && (iDot==4 || iDot==5))                         //Total force lethal?
12696 					{
12697 						attack              = emptyattack;                                      //Clear struct.
12698 						attack.attack_type  = iType;                                            //Set type.
12699 						attack.attack_force = iForce;                                           //Set force. Use unmodified force here; takedamage applys damage mitigation.
12700 						attack.dropv[0]     = (float)3;                                         //Apply drop Y.
12701 						attack.dropv[1]     = (float)1.2;                                       //Apply drop X
12702 						attack.dropv[2]     = (float)0;                                         //Apply drop Z
12703 
12704 						if(self->takedamage)                                                    //Defender uses takedamage()?
12705 						{
12706 							self->takedamage(eOpp, &attack);                                    //Apply attack to kill defender.
12707 						}
12708 						else
12709 						{
12710 							kill(self);                                                         //Kill defender instantly.
12711 						}
12712 					}
12713 					else                                                                        //Total force less then health or using non lethal setting.
12714 					{
12715 						if (self->health > iFForce)                                             //Final force less then health?
12716 						{
12717 							self->health -= iFForce;                                            //Reduce health directly. Using takedamage() breaks grabs and spams defender's status in HUD.
12718 						}
12719 						else
12720 						{
12721 							self->health = 1;                                                   //Set minimum health.
12722 						}
12723 						execute_takedamage_script(self, eOpp, iForce, 0, iType, 0, 0, 0, 0);    //Execute the takedamage script.
12724 					}
12725 				}
12726 
12727 				if(iDot==2 || iDot==3 || iDot==5)                                               //MP?
12728 				{
12729 					self->mp -= iForce;                                                         //Subtract force from MP.
12730 					if(self->mp<0) self->mp = 0;                                                //Stablize MP at 0.
12731 				}
12732 			}
12733 		}
12734 	}
12735 }
12736 
adjust_bind(entity * e)12737 void adjust_bind(entity* e)
12738 {
12739 	if(e->bindanim)
12740 	{
12741 		if(e->animnum!=e->bound->animnum)
12742 		{
12743 			if(!validanim(e,e->bound->animnum))
12744 			{
12745 				if(e->bindanim&4)
12746 				{
12747 				   kill(e);
12748 				}
12749 				e->bound=NULL;
12750 				return;
12751 			}
12752 			ent_set_anim(e, e->bound->animnum, 1);
12753 		}
12754 		if(e->animpos!=e->bound->animpos && e->bindanim&2)
12755 		{
12756 			update_frame(e, e->bound->animpos);
12757 		}
12758 	}
12759 	e->z = e->bound->z +e->bindoffset[1];
12760 	e->a = e->bound->a + e->bindoffset[2];
12761 	switch(e->bindoffset[3])
12762 	{
12763 	case 0:
12764 		if(e->bound->direction) e->x = e->bound->x + e->bindoffset[0];
12765 		else e->x = e->bound->x - e->bindoffset[0];
12766 		break;
12767 	case 1:
12768 		e->direction = e->bound->direction;
12769 		if(e->bound->direction) e->x = e->bound->x + e->bindoffset[0];
12770 		else e->x = e->bound->x - e->bindoffset[0];
12771 		break;
12772 	case -1:
12773 		e->direction = !e->bound->direction;
12774 		if(e->bound->direction) e->x = e->bound->x + e->bindoffset[0];
12775 		else e->x = e->bound->x - e->bindoffset[0];
12776 		break;
12777 	case 2:
12778 		e->direction = 1;
12779 		e->x = e->bound->x + e->bindoffset[0];
12780 		break;
12781 	case -2:
12782 		e->direction = 0;
12783 		e->x = e->bound->x + e->bindoffset[0];
12784 		break;
12785 	default:
12786 		e->x = e->bound->x + e->bindoffset[0];
12787 		break;
12788 	// the default is no change :), just give a value of 12345 or so
12789 	}
12790 }
12791 
12792 // arrenge the list reduce its length
arrange_ents()12793 void arrange_ents()
12794 {
12795 	int i, ind=-1;
12796 	entity* temp;
12797 	if(ent_count == 0) return;
12798 	if(ent_max == ent_count)
12799 	{
12800 		for(i=0; i<ent_max; i++)
12801 		{
12802 			ent_list[i]->update_mark = 0;
12803 			if(ent_list[i]->exists && ent_list[i]->bound)
12804 			{
12805 				adjust_bind(ent_list[i]);
12806 			}
12807 		}
12808 	}
12809 	else
12810 	{
12811 		for(i=0; i<ent_max; i++)
12812 		{
12813 			if(!ent_list[i]->exists && ind<0)
12814 				ind = i;
12815 			else if(ent_list[i]->exists && ind>=0)
12816 			{
12817 				temp = ent_list[i];
12818 				ent_list[i] = ent_list[ind];
12819 				ent_list[ind] = temp;
12820 				ind++;
12821 			}
12822 			ent_list[i]->update_mark = 0;
12823 			if(ent_list[i]->exists && ent_list[i]->bound)
12824 			{
12825 				adjust_bind(ent_list[i]);
12826 			}
12827 		}
12828 		ent_max = ent_count;
12829 	}
12830 }
12831 
12832 // Update all entities that wish to think or animate in this cycle.
12833 // All loops are separated because "self" might die during a pass.
update_ents()12834 void update_ents()
12835 {
12836 	int i;
12837 	for(i=0; i<ent_max; i++)
12838 	{
12839 		if(ent_list[i]->exists && time != ent_list[i]->timestamp)// dont update fresh entity
12840 		{
12841 			self = ent_list[i];
12842 			self->update_mark = 0;
12843 			if(level) check_lost();// check lost caused by level scrolling or lifespan
12844 			if(!self->exists) continue;
12845 			// expand time incase being frozen
12846 			if(is_frozen(self)){expand_time(self);}
12847 			else
12848 			{
12849 				execute_updateentity_script(self);// execute a script
12850 				if(!self->exists) continue;
12851 				check_ai();// check ai
12852 				if(!self->exists) continue;
12853 				check_gravity();// check gravity
12854 				if(!self->exists) continue;
12855 				update_animation(); // if not frozen, update animation
12856 				if(!self->exists) continue;
12857 				check_attack();// Collission detection
12858 				if(!self->exists) continue;
12859 				update_health();// Update displayed health
12860 			}
12861 		}
12862 	}//end of for
12863 	arrange_ents();
12864 	/*
12865 	if(time>=nextplan){
12866 		plan();
12867 		nextplan = time+GAME_SPEED/2;
12868 	}*/
12869 }
12870 
12871 
display_ents()12872 void display_ents()
12873 {
12874 	unsigned f;
12875 	int i, z, wall = 0, wall2;
12876 	entity *e = NULL;
12877 	entity *other = NULL;
12878 	int qx, qy, sy,sz, alty;
12879 	float temp1, temp2;
12880 	int useshadow = 0;
12881 	int can_mirror = 0;
12882 	s_drawmethod* drawmethod = NULL;
12883 	s_drawmethod commonmethod;
12884 	s_drawmethod shadowmethod;
12885 	int use_mirror = (level && level->mirror);
12886 
12887 	for(i=0; i<ent_max; i++)
12888 	{
12889 		if(ent_list[i] && ent_list[i]->exists)
12890 		{
12891 			e = ent_list[i];
12892 			if(e->modeldata.hpbarstatus.sizex)
12893 			{
12894 				drawenemystatus(e);
12895 
12896 			}
12897 			if(freezeall || !(e->blink && (time%(GAME_SPEED/10))<(GAME_SPEED/20)))
12898 			{    // If special is being executed, display all entities regardless
12899 				f = e->animation->sprite[e->animpos];
12900 
12901 				other = check_platform(e->x, e->z, e);
12902 				wall = checkwall(e->x, e->z);
12903 
12904 				if(f<sprites_loaded)
12905 				{
12906 					// var "z" takes into account whether it has a setlayer set, whether there are other entities on
12907 					// the same "z", in which case there is a layer offset, whether the entity is on an obstacle, and
12908 					// whether the entity is grabbing someone and has grabback set
12909 
12910 					z = (int)e->z;    // Set the layer offset
12911 
12912 					if(e->grabbing && e->modeldata.grabback)
12913 						z = (int)e->link->z - 1;    // Grab animation displayed behind
12914 					else if(!e->modeldata.grabback && e->grabbing)
12915 						z = (int)e->link->z + 1;
12916 
12917 					if(e->bound && e->bound->grabbing)
12918 					{
12919 						if(e->bound->modeldata.grabback) z--;
12920 						else                             z++;
12921 					}
12922 
12923 					if(other && e->a >= other->a + other->animation->platform[other->animpos][7] && !other->modeldata.setlayer)
12924 					{
12925 						if(
12926 							e->link &&
12927 							((e->modeldata.grabback &&
12928 							!e->grabbing) ||
12929 							(e->link->modeldata.grabback &&
12930 							e->link->grabbing) ||
12931 							e->grabbing)
12932 							)
12933 							z = (int)(other->z + 2);    // Make sure entities get displayed in front of obstacle and grabbee
12934 
12935 						else z = (int)(other->z + 1);    // Entity should always display in front of the obstacle
12936 
12937 					}
12938 
12939 					if(e->owner) z = (int)(e->z/* + e->layer*/ + 1);    // Always in front
12940 
12941 					if(e->modeldata.setlayer) z = HOLE_Z + e->modeldata.setlayer;    // Setlayer takes precedence
12942 
12943 					if(checkhole(e->x, e->z)==2) z = PANEL_Z-1;        // place behind panels
12944 
12945 					drawmethod = e->animation->drawmethods?getDrawMethod(e->animation, e->animpos):NULL;
12946 		    //drawmethod = e->animation->drawmethods?e->animation->drawmethods[e->animpos]:NULL;
12947 					if(e->drawmethod.flag) drawmethod = &(e->drawmethod);
12948 					if(!drawmethod)
12949 						commonmethod = plainmethod;
12950 					else
12951 						commonmethod = *drawmethod;
12952 					drawmethod = &commonmethod;
12953 
12954 					if(drawmethod->remap>=1 && drawmethod->remap<=e->modeldata.maps_loaded)
12955 					{
12956 						drawmethod->table = e->modeldata.colourmap[drawmethod->remap-1];
12957 					}
12958 
12959 					if(e->colourmap)
12960 					{
12961 						if(drawmethod->remap<0) drawmethod->table = e->colourmap;
12962 					}
12963 					if(e->modeldata.alpha >=1 && e->modeldata.alpha <= MAX_BLENDINGS)
12964 					{
12965 						if(drawmethod->alpha<0)
12966 						{
12967 							drawmethod->alpha = e->modeldata.alpha;
12968 						}
12969 					}
12970 					if(!drawmethod->table) drawmethod->table = e->modeldata.palette;
12971 					if(e->modeldata.globalmap)
12972 					{
12973 						if(level&&current_palette)
12974 							drawmethod->table = level->palettes[current_palette-1];
12975 						else drawmethod->table = pal;
12976 					}
12977 					if(e->dying)    // Code for doing dying flash
12978 					{
12979 						if((e->health <= e->per1 && e->health > e->per2 && (time %(GAME_SPEED / 5)) < (GAME_SPEED / 10)) ||
12980 							(e->health <= e->per2 && (time %(GAME_SPEED / 10)) < (GAME_SPEED / 20)))
12981 						{
12982 							if(e->health > 0 )
12983 							{
12984 								drawmethod->table = e->modeldata.colourmap[e->dying - 1];
12985 							}
12986 						}
12987 					}
12988 
12989 					if(!e->direction)
12990 					{
12991 						drawmethod->flipx = !drawmethod->flipx;
12992 						if(drawmethod->fliprotate && drawmethod->rotate)
12993 							drawmethod->rotate = 360-drawmethod->rotate;
12994 					}
12995 
12996 					if(!use_mirror || z > MIRROR_Z) // don't display if behind the mirror
12997 					{
12998 						spriteq_add_sprite((int)(e->x - (level?advancex:0) + gfx_x_offset), (int)(e->z-e->a + gfx_y_offset), z, f, drawmethod, e->bound?e->bound->sortid-1:e->sortid);
12999 					}
13000 
13001 					can_mirror = (use_mirror && self->z>MIRROR_Z);
13002 					if(can_mirror)
13003 					{
13004 						spriteq_add_sprite((int)(e->x-(level?advancex:0) + gfx_x_offset), (int)((2*MIRROR_Z - e->z)-e->a+gfx_y_offset), 2*PANEL_Z - z , f, drawmethod, MAX_ENTS - (e->bound?e->bound->sortid-1:e->sortid));
13005 					}
13006 				}//end of if(f<sprites_loaded)
13007 
13008 				if(e->modeldata.gfxshadow==1 && f<sprites_loaded)//gfx shadow
13009 				{
13010 					useshadow = (e->animation->shadow?e->animation->shadow[e->animpos]:1) && shadowcolor && light[1];
13011 					//printf("\n %d, %d, %d\n", shadowcolor, light[0], light[1]);
13012 					if(useshadow && e->a>=0 && (!e->modeldata.aironly || (e->modeldata.aironly && inair(e))))
13013 					{
13014 						wall = checkwall_below(e->x, e->z, e->a);
13015 						if(wall<0)
13016 						{
13017 							alty = (int)e->a;
13018 							temp1 = -1*e->a*light[0]/256; // xshift
13019 							temp2 = (float)(-alty*light[1]/256);                   // zshift
13020 							qx = (int)(e->x - advancex + gfx_x_offset/* + temp1*/);
13021 							qy = (int)(e->z + gfx_y_offset/* +  temp2*/);
13022 						}
13023 						else
13024 						{
13025 							alty = (int)(e->a-level->walls[wall][7]);
13026 							temp1 = -1*(e->a-level->walls[wall][7])*light[0]/256; // xshift
13027 							temp2 = (float)(-alty*light[1]/256);                   // zshift
13028 							qx = (int)(e->x - advancex + gfx_x_offset/* + temp1*/);
13029 							qy = (int)(e->z + gfx_y_offset /*+  temp2*/ - level->walls[wall][7]);
13030 						}
13031 
13032 						wall2=checkwall_below(e->x + temp1, e->z + temp2, e->a); // check if the shadow drop into a hole or fall on another wall
13033 
13034 						//TODO check platforms, don't want to go through the entity list again right now
13035 						if(!(checkhole(e->x + temp1, e->z + temp2) && wall2<0 && !other) )//&& !(wall>=0 && level->walls[wall][7]>e->a))
13036 						{
13037 							if(wall>=0 && wall2 >= 0)
13038 							{
13039 							   alty += (int)(level->walls[wall][7] - level->walls[wall2][7]);
13040 							   /*qx += -1*(level->walls[wall][7]-level->walls[wall2][7])*light[0]/256;
13041 							   qy += (level->walls[wall][7]-level->walls[wall2][7]) - (level->walls[wall][7]-level->walls[wall2][7])*light[1]/256;*/
13042 							}
13043 							else if(wall>=0)
13044 							{
13045 							   alty += (int)(level->walls[wall][7]);
13046 							   /*qx += -1*level->walls[wall][7]*light[0]/256;
13047 							   qy += level->walls[wall][7] - level->walls[wall][7]*light[1]/256;*/
13048 							}
13049 							else if(wall2>=0)
13050 							{
13051 							   alty -= (int)(level->walls[wall2][7]);
13052 							   /*qx -= -1*level->walls[wall2][7]*light[0]/256;
13053 							   qy -= level->walls[wall2][7] - level->walls[wall2][7]*light[1]/256;*/
13054 							}
13055 							sy = (2*MIRROR_Z - qy) + 2*gfx_y_offset;
13056 							z = SHADOW_Z;
13057 							sz = PANEL_Z-HUD_Z;
13058 							if(e->animation->shadow_coords)
13059 							{
13060 								if(e->direction) qx += e->animation->shadow_coords[e->animpos][0];
13061 								else qx -= e->animation->shadow_coords[e->animpos][0];
13062 								qy += e->animation->shadow_coords[e->animpos][1];
13063 								sy -= e->animation->shadow_coords[e->animpos][1];
13064 							}
13065 							shadowmethod = plainmethod;
13066 							shadowmethod.fillcolor = (shadowcolor>0?shadowcolor:0);
13067 							shadowmethod.alpha = shadowalpha;
13068 							shadowmethod.scalex = drawmethod->scalex;
13069 							shadowmethod.flipx = drawmethod->flipx;
13070 							shadowmethod.scaley = light[1]*drawmethod->scaley/256;
13071 							shadowmethod.flipy = drawmethod->flipy;
13072 							shadowmethod.centery += alty;
13073 							if(shadowmethod.flipy) shadowmethod.centery = -shadowmethod.centery;
13074 							if(shadowmethod.scaley<0)
13075 							{
13076 								shadowmethod.scaley = -shadowmethod.scaley;
13077 								shadowmethod.flipy = !shadowmethod.flipy;
13078 							}
13079 							shadowmethod.rotate = drawmethod->rotate;
13080 							shadowmethod.shiftx = drawmethod->shiftx + light[0];
13081 
13082 							spriteq_add_sprite(qx, qy, z, f, &shadowmethod, 0);
13083 							if(use_mirror)
13084 							{
13085 								shadowmethod.flipy = !shadowmethod.flipy;
13086 								shadowmethod.centery = -shadowmethod.centery;
13087 								spriteq_add_sprite(qx, sy, sz, f, &shadowmethod, 0);
13088 							}
13089 						}
13090 					}//end of gfxshadow
13091 				}
13092 				else //plan shadow
13093 				{
13094 					useshadow = e->animation->shadow?e->animation->shadow[e->animpos]:e->modeldata.shadow;
13095 					if(useshadow<0) {useshadow=e->modeldata.shadow;}
13096 					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))))
13097 					{
13098 						if(other && other != e && e->a >= other->a + other->animation->platform[other->animpos][7])
13099 						{
13100 							qx = (int)(e->x - advancex + gfx_x_offset);
13101 							qy = (int)(e->z - other->a - other->animation->platform[other->animpos][7] + gfx_y_offset);
13102 							sy = (int)((2*MIRROR_Z - e->z) - other->a - other->animation->platform[other->animpos][7] + gfx_y_offset);
13103 							z = (int)(other->z + 1);
13104 							sz = 2*PANEL_Z - z;
13105 						}
13106 						else if(level && wall >= 0)// && e->a >= level->walls[wall][7])
13107 						{
13108 							qx = (int)(e->x - advancex + gfx_x_offset);
13109 							qy = (int)(e->z - level->walls[wall][7] + gfx_y_offset);
13110 							sy = (int)((2*MIRROR_Z - e->z)  - level->walls[wall][7] + gfx_y_offset);
13111 							z = SHADOW_Z;
13112 							sz = PANEL_Z-HUD_Z;
13113 						}
13114 						else
13115 						{
13116 							qx = (int)(e->x - advancex + gfx_x_offset);
13117 							qy = (int)(e->z + gfx_y_offset);
13118 							sy = (int)((2*MIRROR_Z - e->z) + gfx_y_offset);
13119 							z = SHADOW_Z;
13120 							sz = PANEL_Z-HUD_Z;
13121 						}
13122 						if(e->animation->shadow_coords)
13123 						{   if(e->direction) qx += e->animation->shadow_coords[e->animpos][0];
13124 							else qx -= e->animation->shadow_coords[e->animpos][0];
13125 							qy += e->animation->shadow_coords[e->animpos][1];
13126 							sy -= e->animation->shadow_coords[e->animpos][1];
13127 						}
13128 						shadowmethod=plainmethod;
13129 						shadowmethod.alpha = BLEND_MULTIPLY+1;
13130 						shadowmethod.flipx = !e->direction;
13131 						spriteq_add_sprite(qx, qy, z, shadowsprites[useshadow-1], &shadowmethod, 0);
13132 						if(use_mirror)
13133 						spriteq_add_sprite(qx, sy, sz, shadowsprites[useshadow-1], &shadowmethod, 0);
13134 					}//end of plan shadow
13135 				}
13136 			}// end of blink checking
13137 
13138 			if(e->arrowon)    // Display the players image while invincible to indicate player number
13139 			{
13140 				if(e->modeldata.parrow[(int)e->playerindex][0] && e->invincible == 1)
13141 					spriteq_add_sprite((int)(e->x - advancex + gfx_x_offset + e->modeldata.parrow[(int)e->playerindex][1]), (int)(e->z-e->a+gfx_y_offset + e->modeldata.parrow[(int)e->playerindex][2]), (int)e->z, e->modeldata.parrow[(int)e->playerindex][0], NULL, e->sortid*2);
13142 			}
13143 		}// end of if(ent_list[i]->exists)
13144 	}// end of for
13145 }
13146 
13147 
13148 
toss(entity * ent,float lift)13149 void toss(entity *ent, float lift)
13150 {
13151 	if(!lift) return; //zero?
13152 	ent->toss_time = time + 1;
13153 	ent->tossv = lift;
13154 	ent->a += 0.5;        // Get some altitude (needed for checks)
13155 }
13156 
13157 
13158 
findent(int types)13159 entity * findent(int types)
13160 {
13161 	int i;
13162 	for(i=0; i<MAX_ENTS; i++)
13163 	{ // 2007-12-18, remove all nodieblink checking, because dead corpse with nodieblink 3 will be changed to TYPE_NONE
13164 	  // so if it is "dead" and TYPE_NONE, it must be a corpse
13165 		if(ent_list[i]->exists && (ent_list[i]->modeldata.type & types) && !(ent_list[i]->dead && ent_list[i]->modeldata.type==TYPE_NONE))
13166 		{
13167 				return ent_list[i];
13168 		}
13169 	}
13170 	return NULL;
13171 }
13172 
13173 
13174 
count_ents(int types)13175 int count_ents(int types)
13176 {
13177 	int i;
13178 	int count = 0;
13179 	for(i=0; i<MAX_ENTS; i++)
13180 	{ // 2007-12-18, remove all nodieblink checking, because dead corpse with nodieblink 3 will be changed to TYPE_NONE
13181 	  // so if it is "dead" and TYPE_NONE, it must be a corpse
13182 		count += (ent_list[i]->exists && (ent_list[i]->modeldata.type & types) && !(ent_list[i]->dead && ent_list[i]->modeldata.type==TYPE_NONE));
13183 	}
13184 	return count;
13185 }
13186 
13187 
13188 
find_ent_here(entity * exclude,float x,float z,int types)13189 entity * find_ent_here(entity *exclude, float x, float z, int types)
13190 {
13191 	int i;
13192 	for(i=0; i<MAX_ENTS; i++)
13193 	{
13194 		if( ent_list[i]->exists
13195 			&& ent_list[i] != exclude
13196 			&& (ent_list[i]->modeldata.type & types)
13197 			&& diff(ent_list[i]->x,x)<(self->modeldata.grabdistance*0.83333)
13198 			&& diff(ent_list[i]->z,z)<(self->modeldata.grabdistance/3)
13199 			&& ent_list[i]->animation->vulnerable[ent_list[i]->animpos]  )
13200 		{
13201 			return ent_list[i];
13202 		}
13203 	}
13204 	return NULL;
13205 }
13206 
set_idle(entity * ent)13207 int set_idle(entity* ent)
13208 {
13209 	//int ani = ANI_IDLE;
13210 	//if(validanim(ent,ANI_FAINT) && ent->health <= ent->modeldata.health / 4) ani = ANI_FAINT;
13211 	//if(validanim(ent,ani)) ent_set_anim(ent, ani, 0);
13212 	if (common_idle_anim(ent))
13213 	{
13214 	}
13215 	else return 0;
13216 	ent->idling = 1;
13217 	ent->attacking = 0;
13218 	ent->inpain = 0;
13219 	ent->jumping = 0;
13220 	ent->blocking = 0;
13221 	return 1;
13222 }
13223 
set_death(entity * iDie,int type,int reset)13224 int set_death(entity *iDie, int type, int reset)
13225 {
13226 	//iDie->xdir = iDie->zdir = iDie->tossv = 0; // stop the target
13227 	if(iDie->blocking && validanim(iDie, ANI_CHIPDEATH)){
13228 		ent_set_anim(iDie,ANI_CHIPDEATH,reset);
13229 		iDie->idling = 0;
13230 		iDie->getting = 0;
13231 		iDie->jumping = 0;
13232 		iDie->charging = 0;
13233 		iDie->attacking = 0;
13234 		iDie->blocking = 0;
13235 		return 1;
13236 	}
13237 	if(type < 0 || type >= max_attack_types || !validanim(iDie,animdies[type])) type = 0;
13238 	if(validanim(iDie,animdies[type])) ent_set_anim(iDie, animdies[type], reset);
13239 	else return 0;
13240 
13241 	iDie->idling = 0;
13242 	iDie->getting = 0;
13243 	iDie->jumping = 0;
13244 	iDie->charging = 0;
13245 	iDie->attacking = 0;
13246 	iDie->blocking = 0;
13247 	if(iDie->frozen) unfrozen(iDie);
13248 	return 1;
13249 }
13250 
13251 
set_fall(entity * iFall,int type,int reset,entity * other,int force,int drop,int noblock,int guardcost,int jugglecost,int pauseadd)13252 int set_fall(entity *iFall, int type, int reset, entity* other, int force, int drop, int noblock, int guardcost, int jugglecost, int pauseadd)
13253 {
13254 	if(type < 0 || type >= max_attack_types || !validanim(iFall,animfalls[type])) type = 0;
13255 	if(validanim(iFall,animfalls[type])) ent_set_anim(iFall, animfalls[type], reset);
13256 	else return 0;
13257 	iFall->drop = 1;
13258 	iFall->inpain = 0;
13259 	iFall->idling = 0;
13260 	iFall->falling = 1;
13261 	iFall->jumping = 0;
13262 	iFall->getting = 0;
13263 	iFall->charging = 0;
13264 	iFall->attacking = 0;
13265 	iFall->blocking = 0;
13266 	iFall->nograb = 1;
13267 	if(iFall->frozen) unfrozen(iFall);
13268 	execute_onfall_script(iFall, other, force, drop, type, noblock, guardcost, jugglecost, pauseadd);
13269 
13270 	return 1;
13271 }
13272 
set_rise(entity * iRise,int type,int reset)13273 int set_rise(entity *iRise, int type, int reset)
13274 {
13275 	if(type < 0 || type >= max_attack_types || !validanim(iRise,animrises[type])) type = 0;
13276 	if(validanim(iRise,animrises[type])) ent_set_anim(iRise, animrises[type], reset);
13277 	else return 0;
13278 	iRise->takeaction = common_rise;
13279 	// Get up again
13280 	iRise->drop = 0;
13281 	iRise->falling = 0;
13282 	iRise->projectile = 0;
13283 	iRise->nograb = 0;
13284 	iRise->xdir = self->zdir = self->tossv = 0;
13285 	iRise->modeldata.jugglepoints.current = iRise->modeldata.jugglepoints.maximum; //reset jugglepoints
13286 	return 1;
13287 }
13288 
set_riseattack(entity * iRiseattack,int type,int reset)13289 int set_riseattack(entity *iRiseattack, int type, int reset)
13290 {
13291 	if(!validanim(iRiseattack,animriseattacks[type]) && iRiseattack->modeldata.riseattacktype == 1) type = 0;
13292 	if(iRiseattack->modeldata.riseattacktype == 0 || type < 0 || type >= max_attack_types) type = 0;
13293 	if(validanim(iRiseattack,animriseattacks[type])) ent_set_anim(iRiseattack, animriseattacks[type], reset);
13294 	else return 0;
13295 	self->staydown.riseattack_stall = 0;			//Reset riseattack delay.
13296 	set_attacking(iRiseattack);
13297 	iRiseattack->drop = 0;
13298 	iRiseattack->nograb = 0;
13299 	ent_set_anim(iRiseattack, animriseattacks[type], 0);
13300 	iRiseattack->takeaction = common_attack_proc;
13301 	iRiseattack->modeldata.jugglepoints.current = iRiseattack->modeldata.jugglepoints.maximum; //reset jugglepoints
13302 	return 1;
13303 }
13304 
set_blockpain(entity * iBlkpain,int type,int reset)13305 int set_blockpain(entity *iBlkpain, int type, int reset)
13306 {
13307 	if(!validanim(iBlkpain,ANI_BLOCKPAIN)){
13308 		iBlkpain->takeaction = common_pain;
13309 		return 1;
13310 	}
13311 	if(type < 0 || type >= max_attack_types || !validanim(iBlkpain,animblkpains[type])) type = 0;
13312 	if(validanim(iBlkpain,animblkpains[type])) ent_set_anim(iBlkpain, animblkpains[type], reset);
13313 	else return 0;
13314 	iBlkpain->takeaction = common_block;
13315 	set_attacking(iBlkpain);
13316 	return 1;
13317 }
13318 
set_pain(entity * iPain,int type,int reset)13319 int set_pain(entity *iPain, int type, int reset)
13320 {
13321 	int pain = 0;
13322 
13323 	iPain->xdir = iPain->zdir = iPain->tossv = 0; // stop the target
13324 	if(iPain->modeldata.guardpoints.maximum > 0 && iPain->modeldata.guardpoints.current <= 0) pain = ANI_GUARDBREAK;
13325 	else if(type == -1 || type >= max_attack_types) pain = ANI_GRABBED;
13326 	else pain = animpains[type];
13327 	if(validanim(iPain,pain))              ent_set_anim(iPain, pain, reset);
13328 	else if(validanim(iPain,animpains[0])) ent_set_anim(iPain, animpains[0], reset);
13329 	else if(validanim(iPain,ANI_IDLE))     ent_set_anim(iPain, ANI_IDLE, reset);
13330 	else return 0;
13331 
13332 	if(pain == ANI_GRABBED) iPain->inpain = 0;
13333 	else iPain->inpain = 1;
13334 
13335 	iPain->idling = 0;
13336 	iPain->falling = 0;
13337 	iPain->projectile = 0;
13338 	iPain->drop = 0;
13339 	iPain->attacking = 0;
13340 	iPain->getting = 0;
13341 	iPain->charging = 0;
13342 	iPain->jumping = 0;
13343 	iPain->blocking = 0;
13344 	if(iPain->modeldata.guardpoints.maximum > 0 && iPain->modeldata.guardpoints.current <= 0) iPain->modeldata.guardpoints.current = iPain->modeldata.guardpoints.maximum;
13345 	if(iPain->frozen) unfrozen(iPain);
13346 
13347 	execute_onpain_script(iPain, type, reset);
13348 	return 1;
13349 }
13350 
13351 
13352 //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)13353 void set_model_ex(entity* ent, char* modelname, int index, s_model* newmodel, int anim_flag)
13354 {
13355 	s_model* model = NULL;
13356 	s_model oldmodel;
13357 	int   animnum, animpos;
13358 	int   i;
13359 	int   type = ent->modeldata.type;
13360 
13361 	model = ent->model;
13362 	if(!newmodel)
13363 	{
13364 		if(index>=0) newmodel = model_cache[index].model;
13365 		else newmodel = findmodel(modelname);
13366 	}
13367 	if(!newmodel) shutdown(1, "Can't set model for entity '%s', model not found.\n", ent->name);
13368 	if(newmodel==model) return;
13369 
13370 	animnum = ent->animnum;
13371 	animpos = ent->animpos;
13372 
13373 	if(!(newmodel->model_flag & MODEL_NO_COPY))
13374 	{
13375 		if(!newmodel->speed) newmodel->speed = model->speed;
13376 		if(!newmodel->runspeed)
13377 		{
13378 			newmodel->runspeed = model->runspeed;
13379 			newmodel->runjumpheight = model->runjumpheight;
13380 			newmodel->runjumpdist = model->runjumpdist;
13381 			newmodel->runupdown = model->runupdown;
13382 			newmodel->runhold = model->runhold;
13383 		}
13384 		if(newmodel->icon.def           <   0)  newmodel->icon.def          = model->icon.def;
13385 		if(newmodel->icon.pain       <   0)  newmodel->icon.pain      = model->icon.pain;
13386 		if(newmodel->icon.get        <   0)  newmodel->icon.get       = model->icon.get;
13387 		if(newmodel->icon.die        <   0)  newmodel->icon.die       = model->icon.die;
13388 		if(newmodel->shadow         <   0)  newmodel->shadow        = model->shadow;
13389 		if(newmodel->knife          <   0)  newmodel->knife         = model->knife;
13390 		if(newmodel->pshotno        <   0)  newmodel->pshotno       = model->pshotno;
13391 		if(newmodel->bomb           <   0)  newmodel->bomb          = model->bomb;
13392 		if(newmodel->star           <   0)  newmodel->star          = model->star;
13393 		if(newmodel->flash          <   0)  newmodel->flash         = model->flash;
13394 		if(newmodel->bflash         <   0)  newmodel->bflash        = model->bflash;
13395 		if(newmodel->dust[0]        <   0)  newmodel->dust[0]       = model->dust[0];
13396 		if(newmodel->dust[1]        <   0)  newmodel->dust[1]       = model->dust[1];
13397 		if(newmodel->diesound       <   0)  newmodel->diesound      = model->diesound;
13398 
13399 		for(i=0; i<max_animations; i++)
13400 		{
13401 			if(!newmodel->animation[i] && model->animation[i] && model->animation[i]->numframes>0)
13402 				newmodel->animation[i] = model->animation[i];
13403 		}
13404 		// copy the weapon list if model flag is not set to use its own weapon list
13405 		if(!(newmodel->model_flag & MODEL_NO_WEAPON_COPY))
13406 		{
13407 			newmodel->weapnum = model->weapnum;
13408 			if(!newmodel->weapon) newmodel->weapon = model->weapon;
13409 		}
13410 	}
13411 
13412 	if(anim_flag)
13413 	{
13414 		ent->attacking = 0;
13415 		ent_set_model(ent, newmodel->name);
13416 	}
13417 	else
13418 	{
13419 		oldmodel = ent->modeldata;
13420 		ent->model = newmodel;
13421 		ent->modeldata = *newmodel;
13422 		ent->animation = newmodel->animation[ent->animnum];
13423 		ent_copy_uninit(ent, &oldmodel);
13424 	}
13425 
13426 	ent->modeldata.type = type;
13427 
13428 	copy_all_scripts(&newmodel->scripts, &ent->scripts, 0);
13429 
13430 	ent_set_colourmap(ent, ent->map);
13431 }
13432 
set_weapon(entity * ent,int wpnum,int anim_flag)13433 void set_weapon(entity* ent, int wpnum, int anim_flag) // anim_flag added for scripted midair weapon changing
13434 {
13435 	if(!ent) return;
13436 //printf("setweapon: %d \n", wpnum);
13437 
13438 	if(ent->modeldata.weapon && wpnum > 0 && wpnum <= MAX_WEAPONS && (*ent->modeldata.weapon)[wpnum-1])
13439 		set_model_ex(ent, NULL, (*ent->modeldata.weapon)[wpnum-1], NULL, !anim_flag);
13440 	else set_model_ex(ent, NULL, -1, ent->defaultmodel, 1);
13441 
13442 	if(ent->modeldata.type == TYPE_PLAYER) // save current weapon for player's weaploss 3
13443 	{
13444 		if(ent->modeldata.weaploss[0] >= 3) player[(int)ent->playerindex].weapnum = wpnum;
13445 		else player[(int)ent->playerindex].weapnum = level->setweap;
13446 	}
13447 }
13448 
13449 //////////////////////////////////////////////////////////////////////////
13450 //                  common A.I. code for enemies & NPCs
13451 //////////////////////////////////////////////////////////////////////////
13452 
13453 
melee_find_target()13454 entity* melee_find_target()
13455 {
13456 	return NULL;
13457 }
13458 
long_find_target()13459 entity* long_find_target()
13460 {
13461 	return NULL;
13462 }
13463 
normal_find_target(int anim,int iDetect)13464 entity* normal_find_target(int anim, int iDetect)
13465 {
13466 
13467     /*
13468     normal_find_target
13469     Author unknown
13470     Date unknown
13471     ~Damon Caskey, 2011_07_22: Add support for detect adjustment.
13472 
13473     int anim:       Animation find range will be calculated by. Default to current animation if not passed.
13474     int iDetect:    Local detection adjustment. Allows lesser or greater penetration of target's stealth for location.
13475     */
13476 
13477 	int i , min, max;
13478 	int index = -1;
13479 	min = 0;
13480 	max = 9999;
13481 	float diffx, diffz, diffd, diffo = 0;
13482 
13483     iDetect += self->modeldata.stealth.detect;
13484 
13485 	//find the 'nearest' one
13486 	for(i=0; i<ent_max; i++)
13487 	{
13488 		if( ent_list[i]->exists && ent_list[i] != self //cant target self
13489 			&& (ent_list[i]->modeldata.type & self->modeldata.hostile)
13490 			&& (anim<0||(anim>=0 && check_range(self, ent_list[i], anim)))
13491 			&& !ent_list[i]->dead //must be alive
13492 			&& (diffd=(diffx=diff(ent_list[i]->x,self->x))+ (diffz=diff(ent_list[i]->z,self->z))) >= min
13493 			&& diffd <= max
13494 			&& (ent_list[i]->modeldata.stealth.hide <= iDetect) //Stealth factor less then perception factor (allows invisibility).
13495 			  )
13496 		{
13497 
13498 			if(index <0 || (index>=0 && (!ent_list[index]->animation->vulnerable[ent_list[index]->animpos] || ent_list[index]->invincible == 1)) ||
13499 				(
13500 					(self->x < ent_list[i]->x) == (self->direction) && // don't turn to the one on the back
13501 					//ent_list[i]->x >= advancex-10 && ent_list[i]->x<advancex+videomodes.hRes+10 && // don't turn to an offscreen target
13502 					//ent_list[i]->z >= advancey-10 && ent_list[i]->z<advancey+videomodes.vRes+10 &&
13503 					diffd < diffo
13504 				)
13505 			)
13506 			{
13507 				index = i;
13508 				diffo = diffd;
13509 			}
13510 		}
13511 	}
13512 	if( index >=0) {return ent_list[index];}
13513 	return NULL;
13514 }
13515 
isItem(entity * e)13516 int isItem(entity* e) {
13517 	return e->modeldata.type & TYPE_ITEM;
13518 }
13519 
isSubtypeTouch(entity * e)13520 int isSubtypeTouch(entity* e) {
13521 	return e->modeldata.subtype == SUBTYPE_TOUCH;
13522 }
13523 
isSubtypeWeapon(entity * e)13524 int isSubtypeWeapon(entity* e) {
13525 	return e->modeldata.subtype == SUBTYPE_WEAPON;
13526 }
13527 
isSubtypeProjectile(entity * e)13528 int isSubtypeProjectile(entity* e) {
13529 	return e->modeldata.subtype == SUBTYPE_PROJECTILE;
13530 }
13531 
canBeDamaged(entity * who,entity * bywhom)13532 int canBeDamaged(entity* who, entity* bywhom) {
13533 	return (who->modeldata.candamage & bywhom->modeldata.type) == bywhom->modeldata.type;
13534 }
13535 
13536 //Used by default A.I. pattern
13537 // A.I. characters try to find a pickable item
normal_find_item()13538 entity * normal_find_item(){
13539 
13540 	int i;
13541 	int index = -1;
13542 	entity* ce = NULL;
13543 	//find the 'nearest' one
13544 	for(i=0; i<ent_max; i++){
13545 		ce = ent_list[i];
13546 
13547 		if( ce->exists && isItem(ce) &&
13548 		(ce->modeldata.stealth.hide <= self->modeldata.stealth.detect) &&
13549 		diff(ce->x,self->x) + diff(ce->z,self->z)< videomodes.hRes/2 &&
13550 		ce->animation->vulnerable[ce->animpos] && !ce->blink &&
13551 		(validanim(self,ANI_GET) || (isSubtypeTouch(ce) && canBeDamaged(ce, self))) &&
13552 		(
13553 			(isSubtypeWeapon(ce) && !self->weapent && self->modeldata.weapon && (*self->modeldata.weapon)[ce->modeldata.weapnum-1]>=0)
13554 			||(isSubtypeProjectile(ce) && !self->weapent)
13555 			||(ce->health && (self->health < self->modeldata.health) && ! isSubtypeProjectile(ce) && ! isSubtypeWeapon(ce))
13556 		)
13557 		){
13558 			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))
13559 				index = i;
13560 		}
13561 	}
13562 	if( index >=0) return ent_list[index];
13563 	return NULL;
13564 }
13565 
long_attack()13566 int long_attack()
13567 {
13568 	return 0;
13569 }
13570 
melee_attack()13571 int melee_attack()
13572 {
13573 	return 0;
13574 }
13575 
13576 // chose next attack in atchain, if succeeded, return 1, otherwise return 0.
perform_atchain()13577 int perform_atchain()
13578 {
13579 	int pickanim = 0;
13580 	if(self->combotime > time)
13581 		self->combostep[0]++;
13582 	else self->combostep[0] = 1;
13583 
13584 	if(self->modeldata.atchain[self->combostep[0]-1]==0) // 0 means the chain ends
13585 	{
13586 		self->combostep[0] = 0;
13587 		return 0;
13588 	}
13589 
13590 	if(validanim(self,animattacks[self->modeldata.atchain[self->combostep[0]-1]-1]) )
13591 	{
13592 		if(((self->combostep[0]==1||self->modeldata.combostyle!=1) && self->modeldata.type==TYPE_PLAYER) ||  // player should use attack 1st step without checking range
13593 		   (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)
13594 		   (self->modeldata.combostyle==1 && normal_find_target(animattacks[self->modeldata.atchain[self->combostep[0]-1]-1],0))) // combostyle 1 checks all anyway
13595 		{
13596 			pickanim = 1;
13597 		}
13598 		else if(self->modeldata.combostyle==1 && self->combostep[0]!=1) // ranged combo? search for a valid attack
13599 		{
13600 			while(++self->combostep[0]<=self->modeldata.chainlength)
13601 			{
13602 				if(self->modeldata.atchain[self->combostep[0]-1] &&
13603 				   validanim(self,animattacks[self->modeldata.atchain[self->combostep[0]-1]-1]) &&
13604 				   (self->combostep[0]==self->modeldata.chainlength ||
13605 					normal_find_target(animattacks[self->modeldata.atchain[self->combostep[0]-1]-1],0)))
13606 				{
13607 					pickanim = 1;
13608 					break;
13609 				}
13610 			}
13611 		}
13612 	}
13613 	else self->combostep[0] = 0;
13614 	if(pickanim)
13615 	{
13616 		ent_set_anim(self, animattacks[self->modeldata.atchain[self->combostep[0]-1]-1], 1);
13617 		set_attacking(self);
13618 		self->takeaction = common_attack_proc;
13619 	}
13620 	if(!pickanim || self->combostep[0] > self->modeldata.chainlength) self->combostep[0] = 0;
13621 	return pickanim;
13622 }
13623 
normal_prepare()13624 void normal_prepare()
13625 {
13626 	int i, lastpick = -1;
13627 	int predir = self->direction;
13628 	entity* target = normal_find_target(-1,0);
13629 
13630 	self->xdir = self->zdir = 0; //stop
13631 
13632 	if(!target)
13633 	{
13634 		self->idling = 1;
13635 		self->takeaction = NULL;
13636 		return;
13637 	}
13638 
13639 	//check if target is behind, so we can perform a turn back animation
13640 	if(!self->modeldata.noflip) self->direction = (self->x < target->x);
13641 	if(predir != self->direction && validanim(self,ANI_TURN))
13642 
13643 	{
13644 		self->direction = predir;
13645 		set_turning(self);
13646 		ent_set_anim(self, ANI_TURN, 0);
13647 		self->takeaction = common_turn;
13648 		return;
13649 	}
13650 
13651 	// Wait...
13652 	if(time < self->stalltime) return;
13653 	// let go the projectile, well
13654 	if( self->weapent && self->weapent->modeldata.subtype == SUBTYPE_PROJECTILE &&
13655 		validanim(self,ANI_THROWATTACK) &&
13656 		(target = normal_find_target(ANI_THROWATTACK,0)))
13657 	{
13658 		set_attacking(self);
13659 		ent_set_anim(self, ANI_THROWATTACK, 0);
13660 		self->takeaction = common_attack_proc;
13661 		return ;
13662 	}
13663 
13664 	// move freespecial check here
13665 	if((rand32()&7) < 2)
13666 	{
13667 		for(i=0; i<max_freespecials; i++)
13668 		{
13669 			if(validanim(self,animspecials[i]) &&
13670 			   (check_energy(1, animspecials[i]) ||
13671 				check_energy(0, animspecials[i])) &&
13672 			   (target=normal_find_target(animspecials[i],0)) &&
13673 			   (rand32()%max_freespecials)<3 &&
13674 			   check_costmove(animspecials[i], 1) )
13675 			{
13676 				return;
13677 			}
13678 		}
13679 	}
13680 
13681 	if(self->modeldata.chainlength > 1) // have a chain?
13682 	{
13683 		if(perform_atchain()) return;
13684 	}
13685 	else if(target) // dont have a chain so just select an attack randomly
13686 	{
13687 		// Pick an attack
13688 		for(i=0; i<max_attacks; i++)
13689 		{
13690 			if( validanim(self,animattacks[i]) &&
13691 				(target = normal_find_target(animattacks[i],0)))
13692 			{
13693 				lastpick = animattacks[i];
13694 				if((rand32() & 31) > 10) break;
13695 			}
13696 		}
13697 		if(lastpick >= 0)
13698 		{
13699 			set_attacking(self);
13700 			ent_set_anim(self, lastpick, 0);
13701 			self->takeaction = common_attack_proc;
13702 			return ;
13703 		}
13704 	}
13705 
13706 	// No attack to perform, return to A.I. root
13707 	self->idling = 1;
13708 	self->takeaction = NULL;
13709 }
13710 
common_jumpland()13711 void common_jumpland()
13712 {
13713 	if(self->animating) return;
13714 	set_idle(self);
13715 	self->takeaction = NULL;
13716 }
13717 
13718 //A.I characters play the jump animation
common_jump()13719 void common_jump()
13720 {
13721 	entity* dust;
13722 
13723 	if(inair(self))
13724 	{
13725 		if(self->animation->dive.x || self->animation->dive.v)
13726 		{
13727 			self->tossv = 0;    // Void tossv so "a" can be adjusted manually
13728 			self->toss_time = 0;
13729 
13730 			if(self->direction) self->xdir = self->animation->dive.x;
13731 			else self->xdir = -self->animation->dive.x;
13732 
13733 			self->a -= self->animation->dive.v;
13734 
13735 			if(self->a <= self->base) self->a = self->base;    // Don't want to go below ground
13736 		}
13737 		return;
13738 	}
13739 
13740 	if(self->tossv<=0) // wait if it is still go up
13741 	{
13742 		self->tossv = 0;
13743 		self->a = self->base;
13744 
13745 		self->jumping = 0;
13746 		self->attacking = 0;
13747 
13748 		if(!self->modeldata.runhold) self->running = 0;
13749 
13750 		self->zdir = self->xdir = 0;
13751 
13752 		if(validanim(self,ANI_JUMPLAND) && self->animation->landframe.frame == -1) // check if jumpland animation exists and not using landframe
13753 		{
13754 			ent_set_anim(self, ANI_JUMPLAND, 0);
13755 			if(self->modeldata.dust[1]>=0)
13756 			{
13757 				dust = spawn(self->x, self->z, self->a, self->direction, NULL, self->modeldata.dust[1], NULL);
13758 				if(dust){
13759 					dust->base = self->a;
13760 					dust->autokill = 1;
13761 					execute_onspawn_script(dust);
13762 				}
13763 			}
13764 			self->takeaction = common_jumpland;
13765 		}
13766 		else
13767 		{
13768 			if(self->modeldata.dust[1]>=0 && self->animation->landframe.frame == -1)
13769 			{
13770 				dust = spawn(self->x, self->z, self->a, self->direction, NULL, self->modeldata.dust[1], NULL);
13771 				if(dust){
13772 					dust->base = self->a;
13773 					dust->autokill = 1;
13774 					execute_onspawn_script(dust);
13775 				}
13776 			}
13777 			if(self->animation->landframe.frame >= 0 && self->animating) return;
13778 
13779 			set_idle(self);
13780 			self->takeaction = NULL; // back to A.I. root
13781 		}
13782 	}
13783 }
13784 
13785 //A.I. characters spawn
common_spawn()13786 void common_spawn()
13787 {
13788 	self->idling = 0;
13789 	if(self->animating) return;
13790 	set_idle(self);
13791 	self->takeaction = NULL; // come to life
13792 }
13793 
13794 //A.I. characters drop from the sky
common_drop()13795 void common_drop()
13796 {
13797 	if(inair(self)) return;
13798 	self->idling = 1;
13799 	self->takeaction = NULL;
13800 	if(self->health<=0) kill(self);
13801 }
13802 
13803 //Similar as above, walk off a wall/cliff
common_walkoff()13804 void common_walkoff()
13805 {
13806 	if(inair(self) || self->animating) return;
13807 	set_idle(self);
13808 	self->takeaction = NULL;
13809 }
13810 
13811 // play turn animation and then flip
common_turn()13812 void common_turn()
13813 {
13814 	if(!self->animating)
13815 	{
13816 		self->xdir = self->zdir = 0;
13817 		self->direction = !self->direction;
13818 		set_idle(self);
13819 		self->takeaction = NULL;
13820 	}
13821 }
13822 
13823 // switch to land animation, land safely
doland()13824 void doland()
13825 {
13826 	self->xdir = self->zdir = 0;
13827 	self->drop = 0;
13828 	self->projectile = 0;
13829 	self->damage_on_landing = 0;
13830 	if(validanim(self,ANI_LAND))
13831 	{
13832 		self->direction = !self->direction;
13833 		ent_set_anim(self, ANI_LAND, 0);
13834 		self->takeaction = common_land;
13835 	}
13836 	else
13837 	{
13838 		set_idle(self);
13839 		self->takeaction = NULL;
13840 	}
13841 }
13842 
common_fall()13843 void common_fall()
13844 {
13845 	// Still falling?
13846 	if(self->falling ||  inair(self) || self->tossv)
13847 	{
13848 		return;
13849 	}
13850 
13851 
13852 	//self->xdir = self->zdir;
13853 
13854 	// Landed
13855 	if(self->projectile > 0)
13856 	{
13857 		if(self->projectile == 2)
13858 		{   // damage_on_landing==-2 means a player has pressed up+jump and has a land animation
13859 			if((autoland == 1 && self->damage_on_landing == -1) ||self->damage_on_landing == -2)
13860 			{
13861 				// Added autoland option for landing
13862 				doland();
13863 				return;
13864 			}
13865 		}
13866 		//self->projectile = 0;
13867 		self->falling = 0;
13868 	}
13869 
13870 	// Drop Weapon due to Enemy Falling.
13871 	//if(self->modeldata.weaploss[0] == 1) dropweapon(1);
13872 
13873 	if(self->boss && level_completed) tospeedup = 1;
13874 
13875 	// Pause a bit...
13876 	self->takeaction	= common_lie;
13877 	self->stalltime		= self->staydown.rise + (time + GAME_SPEED - self->modeldata.risetime[0]);	//Set rise delay.
13878 	self->staydown.riseattack_stall	= self->staydown.riseattack + (time - self->modeldata.risetime[1]);					//Set rise attack delay.
13879 	self->staydown.rise = 0; //Reset staydown.
13880 	self->staydown.riseattack = 0; //Reset staydown atk.
13881 }
13882 
common_try_riseattack()13883 void common_try_riseattack()
13884 {
13885 	entity * target;
13886 	if(!validanim(self,ANI_RISEATTACK)) return;
13887 
13888 	target = normal_find_target(ANI_RISEATTACK,0);
13889 	if(!target)
13890 	{
13891 		self->direction = !self->direction;
13892 		target = normal_find_target(ANI_RISEATTACK,0);
13893 		self->direction = !self->direction;
13894 	}
13895 
13896 	if(target)
13897 	{
13898 		self->direction = (target->x > self->x);    // Stands up and swings in the right direction depending on chosen target
13899 		set_riseattack(self, self->damagetype, 0);
13900 	}
13901 }
13902 
common_lie()13903 void common_lie()
13904 {
13905 	// Died?
13906 	if(self->health <= 0)
13907 	{
13908 		if(self->modeldata.falldie == 2) set_death(self, self->damagetype, 0);
13909 		if(!self->modeldata.nodieblink || (self->modeldata.nodieblink == 1 && !self->animating))
13910 		{    // Now have the option to blink or not
13911 			self->takeaction = (self->modeldata.type == TYPE_PLAYER)?player_blink:suicide;
13912 			self->blink = 1;
13913 			self->stalltime  = time + GAME_SPEED * 2;
13914 		}
13915 		else if(self->modeldata.nodieblink == 2  && !self->animating)
13916 		{
13917 			self->takeaction = (self->modeldata.type == TYPE_PLAYER)?player_die:suicide;
13918 
13919 		}
13920 		else if(self->modeldata.nodieblink == 3  && !self->animating)
13921 		{
13922 			if(self->modeldata.type == TYPE_PLAYER)
13923 			{
13924 				self->takeaction = player_die;
13925 
13926 			}
13927 			else
13928 			{
13929 				self->modeldata.type = TYPE_NONE;
13930 				self->noaicontrol = 1;
13931 			}
13932 		}
13933 
13934 		if (self->modeldata.maps.ko)                                                           //Have a KO map?
13935 		{
13936 			if (self->modeldata.maps.kotype)                                                       //Wait for fall/death animation to finish?
13937 			{
13938 				if (!self->animating)
13939 				{
13940 					self->colourmap = self->modeldata.colourmap[self->modeldata.maps.ko-1];    //If finished animating, apply map.
13941 				}
13942 			}
13943 			else                                                                                //Don't bother waiting.
13944 			{
13945 				self->colourmap = self->modeldata.colourmap[self->modeldata.maps.ko-1];        //Apply map.
13946 			}
13947 		}
13948 
13949 		return;
13950 	}
13951 
13952 	if(time < self->stalltime || self->a!=self->base || self->tossv) return;
13953 
13954 	//self->takeaction = common_rise;
13955 	// Get up again
13956 	//self->drop = 0;
13957 	//self->falling = 0;
13958 	//self->projectile = 0;
13959 	//self->xdir = self->zdir = self->tossv = 0;
13960 
13961 	set_rise(self, self->damagetype, 0);
13962 }
13963 
13964 // rise proc
common_rise()13965 void common_rise()
13966 {
13967 	if(self->animating) return;
13968 	self->staydown.riseattack_stall = 0;	//Reset riseattack delay.
13969 	set_idle(self);
13970 	if(self->modeldata.riseinv)
13971 	{
13972 		self->blink = self->modeldata.riseinv>0;
13973 		self->invinctime = time + ABS(self->modeldata.riseinv);
13974 		self->invincible = 1;
13975 	}
13976 	self->takeaction = NULL;
13977 }
13978 
13979 // pain proc
common_pain()13980 void common_pain()
13981 {
13982 	//self->xdir = self->zdir = 0; // complained
13983 
13984 	if(self->animating || inair(self)) return;
13985 
13986 	self->inpain = 0;
13987 	if(self->link){
13988 //        set_pain(self, -1, 0);
13989 		self->takeaction = common_grabbed;
13990 	}
13991 	else if(self->blocking)
13992 	{
13993 		ent_set_anim(self, ANI_BLOCK, 1);
13994 		self->takeaction = common_block;
13995 	}
13996 	else
13997 	{
13998 		set_idle(self);
13999 		self->takeaction = NULL;
14000 	}
14001 }
14002 
doprethrow()14003 void doprethrow()
14004 {
14005 	entity * other = self->link;
14006 	self->xdir = self->zdir = self->tossv = other->xdir = other->zdir = other->tossv = 0;
14007 	ent_set_anim(self, ANI_THROW, 0);
14008 	other->takeaction = common_prethrow;
14009 	self->takeaction = common_throw_wait;
14010 }
14011 
14012 // 1 grabattack 2 grabforward 3 grabup 4 grabdown 5 grabbackward
14013 // other means grab finisher at once
dograbattack(int which)14014 void dograbattack(int which)
14015 {
14016 	entity * other = self->link;
14017 	other->xdir = other->zdir = self->xdir = self->zdir = 0;
14018 	if(which<5 && which>=0)
14019 	{
14020 		++self->combostep[which];
14021 		if(self->combostep[which] < 3)
14022 			ent_set_anim(self, grab_attacks[which][0], 0);
14023 		else
14024 		{
14025 			if(validanim(self,grab_attacks[which][1])) ent_set_anim(self, grab_attacks[which][1], 0);
14026 			else ent_set_anim(self, ANI_ATTACK3, 0);
14027 			memset(self->combostep, 0, sizeof(int)*5);
14028 		}
14029 	}
14030 	else
14031 	{
14032 		if(validanim(self,grab_attacks[0][1])) ent_set_anim(self, grab_attacks[0][1], 0);
14033 		else if(validanim(self,ANI_ATTACK3)) ent_set_anim(self, ANI_ATTACK3, 0);
14034 		else return ;
14035 		memset(self->combostep, 0, sizeof(int)*5);
14036 	}
14037 	self->attacking = 1;
14038 	self->takeaction = common_grabattack;
14039 }
14040 
dovault()14041 void dovault()
14042 {
14043 	int heightvar;
14044 	entity * other = self->link;
14045 	self->link->xdir = self->link->zdir = self->xdir = self->zdir = 0;
14046 
14047 	self->attacking = 1;
14048 	self->x = other->x;
14049 
14050 	if(other->animation->height) heightvar = other->animation->height;
14051 	else heightvar = other->modeldata.height;
14052 
14053 	self->base = other->base + heightvar;
14054 	ent_set_anim(self, ANI_VAULT, 0);
14055 	self->takeaction = common_vault;
14056 }
14057 
common_grab_check()14058 void common_grab_check()
14059 {
14060 	int rnum, which;
14061 	entity * other = self->link;
14062 
14063 	if(other == NULL || (self->modeldata.grabfinish && self->animating && !self->grabwalking)) return;
14064 
14065 	if(self->base != other->base)
14066 	{       // Change this from ->a to ->base
14067 		ent_unlink(self);
14068 		set_idle(self);
14069 		self->takeaction = NULL;
14070 		return;
14071 	}
14072 
14073 	if(!nolost && self->modeldata.weaploss[0] <= 0) dropweapon(1);
14074 
14075 	self->attacking = 0; //for checking
14076 
14077 	rnum = rand32()&31;
14078 
14079 	if(time > self->releasetime)
14080 	{
14081 		if(rnum < 12)
14082 		{
14083 			// Release
14084 			ent_unlink(self);
14085 			set_idle(self);
14086 			self->takeaction = NULL;
14087 			return;
14088 		}
14089 		else self->releasetime = time + (GAME_SPEED/2);
14090 	}
14091 
14092 	if(validanim(self,ANI_THROW) && rnum < 7)
14093 	{
14094 		if(self->modeldata.throwframewait >= 0)
14095 			doprethrow();
14096 		else
14097 			dothrow();
14098 		return;
14099 	}
14100 	//grab finisher
14101 	if(rnum < 4)
14102 	{
14103 		 dograbattack(-1);
14104 		 return;
14105 	}
14106 	which = rnum%5;
14107 	// grab attacks
14108 	if(rnum > 12 && validanim(self,grab_attacks[which][0]))
14109 	{
14110 		dograbattack(which);
14111 		return;
14112 	}
14113 	// Vaulting.
14114 	if(rnum < 8 && validanim(self,ANI_VAULT))
14115 	{
14116 		dovault();
14117 		return;
14118 	}
14119 }
14120 
14121 //grabbing someone
common_grab()14122 void common_grab()
14123 {
14124 	// if(self->link) return;
14125 	if(self->link || (self->modeldata.grabfinish && self->animating && !self->grabwalking)) return;
14126 
14127 	memset(self->combostep, 0, sizeof(int)*5);
14128 	set_idle(self);
14129 	self->takeaction = NULL;
14130 	self->attacking = 0;
14131 }
14132 
14133 // being grabbed
common_grabbed()14134 void common_grabbed()
14135 {
14136 	// Just check if we're still grabbed...
14137 	if(self->link) return;
14138 
14139 	set_idle(self);
14140 	self->stalltime=0;
14141 	self->takeaction = NULL;
14142 }
14143 
14144 // picking up something
common_get()14145 void common_get()
14146 {
14147 	if(self->animating) return;
14148 
14149 	set_idle(self);
14150 	self->getting = 0;
14151 	self->takeaction = NULL;
14152 }
14153 
14154 // A.I. characters do the block
common_block()14155 void common_block()
14156 {
14157 	if(self->animating) return;
14158 
14159 	set_idle(self);
14160 	self->blocking = 0;
14161 	self->takeaction = NULL;
14162 }
14163 
14164 
common_charge()14165 void common_charge()
14166 {
14167 	if(self->animating) return;
14168 
14169 	set_idle(self);
14170 	self->charging = 0;
14171 	self->takeaction = NULL;
14172 }
14173 
14174 
14175 // common code for entities hold an item
drop_item(entity * e)14176 entity* drop_item(entity* e)
14177 {
14178 	s_spawn_entry p;
14179 	entity* item;
14180 	memset(&p, 0, sizeof(s_spawn_entry));
14181 
14182 	p.index = e->item;
14183 	p.itemindex = p.weaponindex = -1;
14184 	strcpy(p.alias, e->itemalias);
14185 	p.a = e->a+0.01; // for check, or an enemy "item" will drop from the sky
14186 	p.health[0] = e->itemhealth;
14187 	p.alpha = e->itemtrans;
14188 	p.colourmap = e->itemmap;
14189 	p.flip = e->direction;
14190 
14191 	item = smartspawn(&p);
14192 
14193 	if(item)
14194 	{
14195 		item->x = e->x;
14196 		item->z = e->z;
14197 		if(item->x < advancex) item->x = advancex + 10;
14198 		else if(item->x > advancex + videomodes.hRes) item->x = advancex + videomodes.hRes - 10;
14199 		if(!(level->scrolldir &(SCROLL_UP|SCROLL_DOWN)))
14200 		{
14201 			if(item->z-item->a < advancey) item->z = advancey + 10;
14202 			else if(item->z-item->a > advancey + videomodes.vRes) item->z = advancey + videomodes.vRes - 10;
14203 		}
14204 		if(e->boss && item->modeldata.type==TYPE_ENEMY) item->boss = 1;
14205 	}
14206 	return item;
14207 }
14208 
14209 //drop the driver, just spawn, dont takedamage
14210 // damage will adjust by the biker
drop_driver(entity * e)14211 entity* drop_driver(entity* e)
14212 {
14213 	int i;
14214 	s_spawn_entry p;
14215 	entity* driver;
14216 	memset(&p, 0, sizeof(s_spawn_entry));
14217 
14218 	if(e->modeldata.rider>=0) p.index = e->modeldata.rider;
14219 	else         return NULL; // should not happen, just in case
14220 	/*p.x = e->x - advancex; p.z = e->z; */p.a = e->a + 10;
14221 	p.itemindex = e->item;
14222 	p.weaponindex = -1;
14223 	strcpy(p.itemalias, e->itemalias);
14224 	strcpy(p.alias, e->name);
14225 	p.itemmap = e->itemmap;
14226 	p.itemtrans = e->itemtrans;
14227 	p.itemhealth = e->itemhealth;
14228 	p.itemplayer_count = e->itemplayer_count;
14229 	//p.colourmap = e->map;
14230 	for(i=0; i<MAX_PLAYERS; i++) p.health[i] = e->modeldata.health;
14231 	p.boss = e->boss;
14232 
14233 	driver = smartspawn(&p);
14234 	if(driver)
14235 	{
14236 		driver->x = e->x;
14237 		driver->z = e->z;
14238 	}
14239 	return driver;
14240 }
14241 
14242 
checkdeath()14243 void checkdeath()
14244 {
14245 	entity* item;
14246 	if(self->health>0) return;
14247 	self->dead = 1;
14248 	//be careful, since the opponent can be other types
14249 	if(self->opponent && self->opponent->modeldata.type == TYPE_PLAYER)
14250 	{
14251 		addscore(self->opponent->playerindex, self->modeldata.score);    // Add score to the player
14252 	}
14253 	self->nograb = 1;
14254 	self->idling = 0;
14255 
14256 	if(self->modeldata.diesound >= 0) sound_play_sample(self->modeldata.diesound, 0, savedata.effectvol,savedata.effectvol, 100);
14257 
14258 	// drop item
14259 	if(self->item && count_ents(TYPE_PLAYER) > self->itemplayer_count){ //4player
14260 		item = drop_item(self);
14261 	}
14262 
14263 	if(self->boss){
14264 		self->boss = 0;
14265 		--level->bosses;
14266 		if(!level->bosses && self->modeldata.type == TYPE_ENEMY){
14267 			kill_all_enemies();
14268 			level_completed = 1;
14269 		}
14270 	}
14271 }
14272 
checkdamageflip(entity * other,s_attack * attack)14273 void checkdamageflip(entity* other, s_attack* attack)
14274 {
14275 	if(other == NULL || other==self || (!self->drop && (attack->no_pain || self->modeldata.nopain || (self->modeldata.defense_pain[(short)attack->attack_type] && attack->attack_force < self->modeldata.defense_pain[(short)attack->attack_type])))) return;
14276 
14277 	if(!self->frozen && !self->modeldata.noflip)// && !inair(self))
14278 	{
14279 		if(attack->force_direction == 0)
14280 		{
14281 			if(self->x < other->x) self->direction = 1;
14282 			else if(self->x > other->x) self->direction = 0;
14283 		}
14284 		else if(attack->force_direction == 1)
14285 		{
14286 			self->direction = other->direction;
14287 		}
14288 		else if(attack->force_direction == -1)
14289 		{
14290 			self->direction = !other->direction;
14291 		}
14292 		else if(attack->force_direction == 2)
14293 		{
14294 			self->direction = 1;
14295 		}
14296 		else if(attack->force_direction == -2)
14297 		{
14298 			self->direction = 0;
14299 		}
14300 	}
14301 }
14302 
checkdamageeffects(s_attack * attack)14303 void checkdamageeffects(s_attack* attack)
14304 {
14305 #define _freeze         attack->freeze
14306 #define _maptime        attack->maptime
14307 #define _freezetime     attack->freezetime
14308 #define _remap          attack->forcemap
14309 #define _blast          attack->blast
14310 #define _steal          attack->steal
14311 #define _seal           attack->seal
14312 #define _sealtime       attack->sealtime
14313 #define _dot            attack->dot
14314 #define _dot_index      attack->dot_index
14315 #define _dot_time       attack->dot_time
14316 #define _dot_force      attack->dot_force
14317 #define _dot_rate       attack->dot_rate
14318 #define _staydown0      attack->staydown[0]
14319 #define _staydown1		attack->staydown[1]
14320 
14321 	entity* opp = self->opponent;
14322 
14323 	if(_steal && opp && opp!=self)
14324 	{
14325 		if(self->health >= attack->attack_force) opp->health += attack->attack_force;
14326 		else opp->health += self->health;
14327 		if(opp->health > opp->modeldata.health)
14328 			opp->health = opp->modeldata.health;
14329 	}
14330 	if(_freeze && !self->frozen && !self->owner && !self->modeldata.nomove)
14331 	{    // New freeze attack - If not frozen, freeze entity unless it's a projectile
14332 		self->frozen = 1;
14333 		if(self->freezetime == 0) self->freezetime = time + _freezetime;
14334 		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.
14335 		self->drop = 0;
14336 	}
14337 	else if(self->frozen)
14338 	{
14339 		unfrozen(self);
14340 		self->drop = 1;
14341 	}
14342 
14343 	if(_remap>0 && !_freeze)
14344 	{
14345 		self->maptime = time + _maptime;
14346 		self->colourmap = self->modeldata.colourmap[_remap-1];
14347 	}
14348 
14349 	if(_seal)                                                                       //Sealed: Disable special moves.
14350 	{
14351 		self->sealtime  = time + _sealtime;                                         //Set time to apply seal. No specials for you!
14352 		self->seal      = _seal;                                                    //Set seal. Any animation with energycost > seal is disabled.
14353 	}
14354 
14355 	if(_dot)                                                                        //dot: Damage over time effect.
14356 	{
14357 		self->dot_owner[_dot_index] = self->opponent;                               //dot owner.
14358 		self->dot[_dot_index]       = _dot;                                         //Mode: 1. HP (non lethal), 2. MP, 3. HP (non lethal) & MP, 4. HP, 5. HP & MP.
14359 		self->dot_time[_dot_index]  = time + (_dot_time * GAME_SPEED / 100);        //Gametime dot will expire.
14360 		self->dot_force[_dot_index] = _dot_force;                                   //How much to dot each tick.
14361 		self->dot_rate[_dot_index]  = _dot_rate;                                    //Delay between dot ticks.
14362 		self->dot_atk[_dot_index]   = attack->attack_type;                          //dot attack type.
14363 	}
14364 
14365 
14366 	if(self->modeldata.nodrop) self->drop = 0;                                      // Static enemies/nodrop enemies cannot be knocked down
14367 
14368 	if(inair(self) && !self->frozen && self->modeldata.nodrop<2) self->drop = 1;
14369 
14370 	if(attack->no_pain) self->drop = 0;
14371 
14372 	self->projectile = _blast;
14373 
14374 	if(self->drop)
14375 	{
14376 		self->staydown.rise	= _staydown0;                                            //Staydown: Add to risetime until next rise.
14377 		self->staydown.riseattack   = _staydown1;
14378 	}
14379 
14380 #undef _freeze
14381 #undef _maptime
14382 #undef _freezetime
14383 #undef _remap
14384 #undef _blast
14385 #undef _steal
14386 #undef _seal
14387 #undef _sealtime
14388 #undef _dot
14389 #undef _dot_index
14390 #undef _dot_time
14391 #undef _dot_force
14392 #undef _dot_rate
14393 #undef _staydown0
14394 #undef _staydown1
14395 }
14396 
checkdamagedrop(s_attack * attack)14397 void checkdamagedrop(s_attack* attack)
14398 {
14399 	int attackdrop = attack->attack_drop;
14400 	float fdefense_knockdown = self->modeldata.defense_knockdown[(short)attack->attack_type];
14401 	if(self->modeldata.animal) self->drop = 1;
14402 	if(self->modeldata.guardpoints.maximum > 0 && self->modeldata.guardpoints.current <= 0) attackdrop = 0; //guardbreak does not knock down.
14403 	if(self->drop || attack->no_pain) return; // just in case, if we already fall, dont check fall again
14404 	// reset count if knockdowntime expired.
14405 	if(self->knockdowntime && self->knockdowntime<time)
14406 		self->knockdowncount = self->modeldata.knockdowncount;
14407 
14408 	self->knockdowncount -= (attackdrop * fdefense_knockdown);
14409 	self->knockdowntime = time + GAME_SPEED;
14410 	self->drop = (self->knockdowncount<0); // knockdowncount < 0 means knocked down
14411 }
14412 
checkmpadd()14413 void checkmpadd()
14414 {
14415 	entity* other = self->opponent;
14416 	if(other == NULL || other == self) return;
14417 
14418 	if(magic_type == 1 )
14419 	{
14420 		if(other->modeldata.mprate) other->mp += other->modeldata.mprate;
14421 		else other->mp++;
14422 
14423 		if(other->mp > other->modeldata.mp) other->mp = other->modeldata.mp;
14424 	}
14425 }
14426 
checkhitscore(entity * other,s_attack * attack)14427 void checkhitscore(entity* other, s_attack* attack)
14428 {
14429 	entity* opp = self->opponent;
14430 	if(!opp) return;
14431 	if(opp && opp!=self && opp->modeldata.type == TYPE_PLAYER)
14432 	{    // Added obstacle so explosions can hurt enemies
14433 		addscore(opp->playerindex, attack->attack_force*self->modeldata.multiple);    // New multiple variable
14434 		control_rumble(opp->playerindex, attack->attack_force*2);
14435 	}
14436 	// Don't animate or fall if hurt by self, since
14437 	// it means self fell to the ground already. :)
14438 	// Add throw score to the player
14439 	else if(other==self && self->damage_on_landing > 0) addscore(opp->playerindex, attack->attack_force);
14440 }
14441 
checkdamage(entity * other,s_attack * attack)14442 void checkdamage(entity* other, s_attack* attack)
14443 {
14444 	int force = attack->attack_force;
14445 	int type = attack->attack_type;
14446 	if(self->modeldata.guardpoints.maximum > 0 && self->modeldata.guardpoints.current <= 0) force = 0; //guardbreak does not deal damage.
14447 	if(!(self->damage_on_landing && self == other) && !other->projectile && type >= 0 && type<max_attack_types)
14448 	{
14449 		force = (int)(force * other->modeldata.offense_factors[type]);
14450 		force = (int)(force * self->modeldata.defense_factors[type]);
14451 	}
14452 
14453 	self->health -= force; //Apply damage.
14454 
14455 	if (self->health > self->modeldata.health) self->health = self->modeldata.health; //Cap negative damage to max health.
14456 
14457 	if(attack->no_kill && self->health<=0) self->health = 1;
14458 
14459 	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.
14460 
14461 	if (self->health <= 0)                                      //Health at 0?
14462 	{
14463 		if(!(self->a < PIT_DEPTH || self->lifespancountdown<0)) //Not a pit death or countdown?
14464 		{
14465 			if (self->invincible == 2)                          //Invincible type 2?
14466 			{
14467 				self->health = 1;                               //Stop at 1hp.
14468 			}
14469 			else if(self->invincible == 3)                      //Invincible type 3?
14470 			{
14471 				self->health = self->modeldata.health;          //Reset to max health.
14472 			}
14473 		}
14474 		execute_ondeath_script(self, other, force, attack->attack_drop, type, attack->no_block, attack->guardcost, attack->jugglecost, attack->pause_add);   //Execute ondeath script.
14475 	}
14476 }
14477 
checkgrab(entity * other,s_attack * attack)14478 int checkgrab(entity *other, s_attack* attack)
14479 {
14480 	//if(attack->no_pain) return  0; //no effect, let modders to deside, don't bother check it here
14481 	if(self!=other && attack->grab && cangrab(other, self))
14482 	{
14483 		if(adjust_grabposition(other, self, attack->grab_distance, attack->grab))
14484 		{
14485 			ents_link(other, self);
14486 			self->a = other->a;
14487 		}
14488 		else return 0;
14489 	}
14490 	return 1;
14491 }
14492 
arrow_takedamage(entity * other,s_attack * attack)14493 int arrow_takedamage(entity *other, s_attack* attack)
14494 {
14495 	self->modeldata.no_adjust_base = 0;
14496 	self->modeldata.subject_to_wall = self->modeldata.subject_to_platform = self->modeldata.subject_to_hole = self->modeldata.subject_to_gravity = 1;
14497 	if( common_takedamage(other, attack) && self->dead)
14498 	{
14499 			  return 1;
14500 	}
14501 	return 0;
14502 }
14503 
common_takedamage(entity * other,s_attack * attack)14504 int common_takedamage(entity *other, s_attack* attack)
14505 {
14506 	if(self->dead) return 0;
14507 	if(self->toexplode == 2) return 0;
14508 	// fake 'grab', if failed, return as the attack hit nothing
14509 	if(!checkgrab(other, attack)) return 0; // try to grab but failed, so return 0 means attack missed
14510 
14511 	// set pain_time so it wont get hit too often
14512 	self->pain_time = time + (GAME_SPEED / 5);
14513 	// set oppoent
14514 	if(self!=other) set_opponent(self, other);
14515 	// adjust type
14516 	if(attack->attack_type >= 0 && attack->attack_type<max_attack_types) self->damagetype = attack->attack_type;
14517 	else self->damagetype = ATK_NORMAL;
14518 	// pre-check drop
14519 	checkdamagedrop(attack);
14520 	// Drop Weapon due to being hit.
14521 	if(self->modeldata.weaploss[0] <= 0) dropweapon(1);
14522 	// check effects, e.g., frozen, blast, steal
14523 	if(!(self->modeldata.guardpoints.maximum > 0 && self->modeldata.guardpoints.current <= 0)) checkdamageeffects(attack);
14524 	// check flip direction
14525 	checkdamageflip(other, attack);
14526 	// mprate can also control the MP recovered per hit.
14527 	checkmpadd();
14528 	//damage score
14529 	checkhitscore(other, attack);
14530 	// check damage, cost hp.
14531 	checkdamage(other, attack);
14532 	// is it dead now?
14533 	checkdeath();
14534 
14535 	if(self->modeldata.type == TYPE_PLAYER) control_rumble(self->playerindex, attack->attack_force * 3);
14536 	if(self->a<=PIT_DEPTH && self->dead)
14537 	{
14538 		if(self->modeldata.type == TYPE_PLAYER) player_die();
14539 		else kill(self);
14540 		return 1;
14541 	}
14542 	// fall to the ground so dont fall again
14543 	if(self->damage_on_landing)
14544 	{
14545 		self->damage_on_landing = 0;
14546 		return 1;
14547 	}
14548 	// unlink due to being hit
14549 	if((self->opponent && self->opponent->grabbing != self)||
14550 	   self->dead || self->frozen || self->drop)
14551 	{
14552 		ent_unlink(self);
14553 	}
14554 	// Enemies can now use SPECIAL2 to escape cheap attack strings!
14555 	if(self->modeldata.escapehits)
14556 	{
14557 		if(self->drop) self->escapecount = 0;
14558 		else self->escapecount++;
14559 	}
14560 	// New pain, fall, and death animations. Also, the nopain flag.
14561 	if(self->drop || self->health <= 0)
14562 	{
14563 		// Drop Weapon due to death.
14564 		if(self->modeldata.weaploss[0] <= 2 && self->health <= 0) dropweapon(1);
14565 		else if(self->modeldata.weaploss[0] <= 1) dropweapon(1);
14566 
14567 		if(self->health <= 0 && self->modeldata.falldie == 1)
14568 		{
14569 			self->xdir = self->zdir = self->tossv = 0;
14570 			set_death(self, self->damagetype, 0);
14571 		}
14572 		else
14573 		{
14574 			self->xdir = attack->dropv[1];
14575 			self->zdir = attack->dropv[2];
14576 			if(self->direction) self->xdir = -self->xdir;
14577 			toss(self, attack->dropv[0]);
14578 			self->damage_on_landing = attack->damage_on_landing;
14579 			self->knockdowncount = self->modeldata.knockdowncount; // reset the knockdowncount
14580 			self->knockdowntime = 0;
14581 
14582 			// Now if no fall/die animations exist, entity simply disapears
14583 			//set_fall(entity *iFall, int type, int reset, entity* other, int force, int drop)
14584 			if(!set_fall(self, self->damagetype, 1, other, attack->attack_force, attack->attack_drop, attack->no_block, attack->guardcost, attack->jugglecost, attack->pause_add))
14585 			{
14586 				if(self->modeldata.type == TYPE_PLAYER) player_die();
14587 				else kill(self);
14588 				return 1;
14589 			}
14590 		}
14591 		self->takeaction = common_fall;
14592 		if(self->modeldata.type == TYPE_PLAYER) control_rumble(self->playerindex, attack->attack_force * 3);
14593 	}
14594 	else if(attack->grab && !attack->no_pain)
14595 	{
14596 		set_pain(self, self->damagetype, 0);
14597 		other->stalltime = time + GRAB_STALL;
14598 		self->releasetime = time + (GAME_SPEED/2);
14599 		self->takeaction = common_pain;
14600 		other->takeaction = common_grabattack;
14601 	}
14602 	// Don't change to pain animation if frozen
14603 	else if(!self->frozen && !self->modeldata.nopain && !attack->no_pain && !(self->modeldata.defense_pain[(short)attack->attack_type] && attack->attack_force < self->modeldata.defense_pain[(short)attack->attack_type]))
14604 	{
14605 		set_pain(self, self->damagetype, 1);
14606 		self->takeaction = common_pain;
14607 	}
14608 	return 1;
14609 }
14610 
14611 // A.I. try upper cut
common_try_upper(entity * target)14612 int common_try_upper(entity* target)
14613 {
14614 	if(!validanim(self,ANI_UPPER)) return 0;
14615 
14616 
14617 	if(!target) target = normal_find_target(ANI_UPPER,0);
14618 
14619 	// Target jumping? Try uppercut!
14620 	if(target && target->jumping )
14621 	{
14622 		set_attacking(self);
14623 		self->zdir = self->xdir = 0;
14624 		// Don't waste any time!
14625 		ent_set_anim(self, ANI_UPPER, 0);
14626 		self->takeaction = common_attack_proc;
14627 		return 1;
14628 	}
14629 	return 0;
14630 }
14631 
common_try_runattack(entity * target)14632 int common_try_runattack(entity* target)
14633 {
14634 	if(!self->running || !validanim(self,ANI_RUNATTACK)) return 0;
14635 
14636 
14637 	if(!target) target = normal_find_target(ANI_RUNATTACK,0);
14638 
14639 	if(target)
14640 	{
14641 		if(!target->animation->vulnerable[target->animpos] && (target->drop || target->attacking))
14642 			return 0;
14643 		self->zdir = self->xdir = 0;
14644 		set_attacking(self);
14645 		ent_set_anim(self, ANI_RUNATTACK, 0);
14646 		self->takeaction = common_attack_proc;
14647 		return 1;
14648 	}
14649 	return 0;
14650 }
14651 
common_try_block(entity * target)14652 int common_try_block(entity* target)
14653 {
14654 	if(self->modeldata.nopassiveblock==0 ||
14655 	   (rand32()&self->modeldata.blockodds) != 1 ||
14656 	   !validanim(self,ANI_BLOCK))
14657 	   return 0;
14658 
14659 	if(!target) target = normal_find_target(ANI_BLOCK,0);
14660 
14661 	// no passive block, so block by himself :)
14662 	if(target && target->attacking)
14663 	{
14664 		set_blocking(self);
14665 		self->zdir = self->xdir = 0;
14666 		ent_set_anim(self, ANI_BLOCK, 0);
14667 		self->takeaction = common_block;
14668 		return 1;
14669 	}
14670 	return 0;
14671 }
14672 /*
14673 int common_try_freespecial(entity* target)
14674 {
14675 	int i, s=max_freespecials;
14676 
14677 	for(i=0; i<s; i++)
14678 	{
14679 		if(validanim(self,animspecials[i]) &&
14680 		   (check_energy(1, animspecials[i]) ||
14681 			check_energy(0, animspecials[i])) &&
14682 		   (target || (target=normal_find_target(animspecials[i],0))) &&
14683 		   (rand32()%s)<3 &&
14684 		   check_costmove(animspecials[i], 1)  )
14685 		{
14686 			return 1;
14687 		}
14688 	}
14689 
14690 	return 0;
14691 }*/
14692 
common_try_normalattack(entity * target)14693 int common_try_normalattack(entity* target)
14694 {
14695 	int i, found = 0;
14696 
14697 	for(i=0; !found && i<max_freespecials; i++)
14698 	{
14699 		if(validanim(self,animspecials[i]) &&
14700 		   (check_energy(1, animspecials[i]) ||
14701 			check_energy(0, animspecials[i])) &&
14702 		   (target || (target=normal_find_target(animspecials[i],0))) &&
14703 		   (rand32()%max_freespecials)<3)
14704 		{
14705 			found = 1;
14706 		}
14707 	}
14708 
14709 	for(i=0; !found && i<max_attacks; i++) // TODO: recheck range for attacks chains
14710 	{
14711 		if(!validanim(self,animattacks[i])) continue;
14712 
14713 		if(target || (target=normal_find_target(animattacks[i],0)))
14714 		{
14715 			found = 1;
14716 		}
14717 	}
14718 
14719 	if(!found && validanim(self,ANI_THROWATTACK) &&
14720 		self->weapent && self->weapent->modeldata.subtype == SUBTYPE_PROJECTILE &&
14721 		(target || (target=normal_find_target(ANI_THROWATTACK,0))) )
14722 	{
14723 		found = 1;
14724 	}
14725 
14726 	if(found)
14727 	{
14728 		if(!target->animation->vulnerable[target->animpos] && (target->drop || target->attacking))
14729 			return 0;
14730 
14731 		self->zdir = self->xdir = 0;
14732 		set_idle(self);
14733 		self->idling = 0; // not really idle, in fact it is thinking
14734 		self->attacking = -1; // pre-attack, for AI-block check
14735 		self->takeaction = normal_prepare;
14736 		if(self->combostep[0] && self->combotime>time) self->stalltime = time+1;
14737 		else self->stalltime = time + (GAME_SPEED/4) + (rand32()%(GAME_SPEED/10) - self->modeldata.aggression);
14738 		return 1;
14739 	}
14740 
14741 	return 0;
14742 }
14743 
common_try_jumpattack(entity * target)14744 int common_try_jumpattack(entity* target)
14745 {
14746 	entity* dust;
14747 	int rnum ;
14748 
14749 	if((validanim(self,ANI_JUMPATTACK) || validanim(self,ANI_JUMPATTACK2)))
14750 	{
14751 		if(!validanim(self,ANI_JUMPATTACK)) rnum = 1;
14752 		else if(validanim(self,ANI_JUMPATTACK2) && (rand32()&1)) rnum = 1;
14753 		else rnum = 0;
14754 
14755 
14756 		if(rnum==0 &&
14757 			// do a jumpattack
14758 			(target || (target = normal_find_target(ANI_JUMPATTACK,0))) )
14759 		{
14760 			if(!target->animation->vulnerable[target->animpos] && (target->drop || target->attacking))
14761 				rnum = -1;
14762 			else{
14763 				ent_set_anim(self, ANI_JUMPATTACK, 0);
14764 				if(self->direction) self->xdir = (float)1.3;
14765 				else self->xdir = (float)-1.3;
14766 				self->zdir = 0;
14767 			}
14768 		}
14769 		else if(rnum==1 &&
14770 			// do a jumpattack2
14771 			(target || (target = normal_find_target(ANI_JUMPATTACK2,0))) )
14772 		{
14773 			if(!target->animation->vulnerable[target->animpos] && (target->drop || target->attacking))
14774 				rnum = -1;
14775 			else{
14776 				ent_set_anim(self, ANI_JUMPATTACK2, 0);
14777 				self->xdir = self->zdir = 0;
14778 			}
14779 		} else {
14780 			rnum = -1;
14781 		}
14782 
14783 		if(rnum >= 0)
14784 		{
14785 
14786 			set_attacking(self);
14787 			self->jumping = 1;
14788 			toss(self, self->modeldata.jumpheight);
14789 			self->takeaction = common_jump;
14790 
14791 			if(self->modeldata.dust[2]>=0)
14792 			{
14793 				dust = spawn(self->x, self->z, self->a, self->direction, NULL, self->modeldata.dust[2], NULL);
14794 				if(dust){
14795 					dust->base = self->a;
14796 					dust->autokill = 1;
14797 					execute_onspawn_script(dust);
14798 				}
14799 			}
14800 
14801 			return 1;
14802 		}
14803 	}
14804 	return 0;
14805 }
14806 
14807 // Normal attack style
14808 // Used by root A.I., what to do if a target is found.
14809 // return 0 if no action is token
14810 // return 1 if an action is token
normal_attack()14811 int normal_attack()
14812 {
14813 	//int rnum;
14814 
14815 	//rnum = rand32()&7;
14816 	if(common_try_upper(NULL) ||
14817 	   common_try_block(NULL) ||
14818 	   common_try_runattack(NULL) ||
14819 	   //(rnum < 2 && common_try_freespecial(NULL)) ||
14820 	   common_try_normalattack(NULL) ||
14821 	   common_try_jumpattack(NULL) )
14822 	{
14823 		self->running = 0;
14824 		return 1;
14825 	}
14826 	return 0;// nothing to do? so go to next think step
14827 }
14828 
14829 // A.I. characters do a throw
common_throw()14830 void common_throw()
14831 {
14832 	if(self->animating) return; // just play the throw animation
14833 
14834 	set_idle(self);
14835 
14836 	// we have done the throw, return to A.I. root
14837 	self->takeaction = NULL;
14838 }
14839 
14840 // toss the grabbed one
dothrow()14841 void dothrow()
14842 {
14843 	entity* other;
14844 	self->xdir = self->zdir = 0;
14845 	other = self->link;
14846 	if(other == NULL) //change back to idle, or we will get stuck here
14847 	{
14848 		set_idle(self);
14849 		self->takeaction = NULL;// A.I. root again
14850 		return;
14851 	}
14852 
14853 	if(other->modeldata.throwheight) toss(other, other->modeldata.throwheight);
14854 	else toss(other, other->modeldata.jumpheight);
14855 
14856 	other->direction = self->direction;
14857 	other->projectile = 2;
14858 	other->xdir = (other->direction)?(-other->modeldata.throwdist):(other->modeldata.throwdist);
14859 
14860 	if(autoland == 1 && validanim(other,ANI_LAND)) other->damage_on_landing = -1;
14861 	else other->damage_on_landing = self->modeldata.throwdamage;
14862 
14863 	set_fall(other, ATK_NORMAL, 0, self, 0, 0, 0, 0, 0, 0);
14864 	ent_set_anim(self, ANI_THROW, 0);
14865 	ent_unlink(other);
14866 
14867 	other->takeaction = common_fall;
14868 	self->takeaction = common_throw;
14869 }
14870 
14871 
14872 // Waiting until throw frame reached
common_throw_wait()14873 void common_throw_wait()
14874 {
14875 	if(!self->link)
14876 	{
14877 		set_idle(self);
14878 		self->takeaction = NULL;// A.I. root again
14879 		return;
14880 	}
14881 
14882 	self->releasetime += THINK_SPEED; //extend release time
14883 
14884 	if(self->animpos != self->modeldata.throwframewait) return;
14885 
14886 	dothrow();
14887 }
14888 
14889 
common_prethrow()14890 void common_prethrow()
14891 {
14892 	self->running = 0;    // Quits running if grabbed by opponent
14893 
14894 	// Just check if we're still grabbed...
14895 	if(self->link) return;
14896 
14897 	set_idle(self);
14898 
14899 	self->takeaction = NULL;// A.I. root again
14900 }
14901 
14902 // warp to its parent entity, just like skeletons in Diablo 2
npc_warp()14903 void npc_warp()
14904 {
14905 	if(!self->parent) return;
14906 	self->z = self->parent->z;
14907 	self->x = self->parent->x;
14908 	self->a = self->parent->a;
14909 	self->xdir = self->zdir = 0;
14910 	self->base = self->parent->base;
14911 	self->tossv = 0;
14912 
14913 	if(validanim(self,ANI_RESPAWN)) {
14914 		ent_set_anim(self, ANI_RESPAWN, 0);
14915 		self->takeaction = common_spawn;
14916 	} else if(validanim(self,ANI_SPAWN)) {
14917 		ent_set_anim(self, ANI_SPAWN, 0);
14918 		self->takeaction = common_spawn;
14919 	}
14920 }
14921 
adjust_grabposition(entity * ent,entity * other,float dist,int grabin)14922 int adjust_grabposition(entity* ent, entity* other, float dist, int grabin)
14923 {
14924 	float x1, z1, x2, z2, x;
14925 
14926 	if(ent->a!=other->a) return 0;
14927 	if(ent->base!=other->base) return 0;
14928 
14929 	if(grabin==1)
14930 	{
14931 		x1 = ent->x;
14932 		z1 = z2 = ent->z;
14933 		x2 = ent->x + ((other->x>ent->x)?dist:-dist);
14934 	}
14935 	else
14936 	{
14937 		x = (ent->x + other->x)/2;
14938 		x1 = x + ((ent->x>=other->x)?(dist/2):(-dist/2));
14939 		x2 = x + ((other->x>ent->x)?(dist/2):(-dist/2));
14940 		z1 = z2 = (ent->z + other->z)/2;
14941 	}
14942 
14943 	if(!testmove(ent, ent->x, ent->z, x1, z1) || !testmove(other, other->x, other->z, x2, z2))
14944 		return 0;
14945 
14946 	ent->x = x1; ent->z = z1;
14947 	other->x = x2; other->z = z2;
14948 	//other->a = ent->a;
14949 	//other->base = ent->base;
14950 	return 1;
14951 }
14952 
14953 
common_trymove(float xdir,float zdir)14954 int common_trymove(float xdir, float zdir)
14955 {
14956 	entity *other = NULL;
14957 	int wall, heightvar;
14958 	float x, z, oxdir, ozdir;
14959 
14960 	if(!xdir && !zdir) return 0;
14961 
14962 	oxdir = xdir; ozdir = zdir;
14963 	/*
14964 	// entity is grabbed by other
14965 	if(self->link && self->link->grabbing==self && self->link->grabwalking)
14966 	{
14967 		return 1; // just return so we don't have to check twice
14968 	}*/
14969 
14970 	x = self->x + xdir;  z = self->z + zdir;
14971 	// -----------bounds checking---------------
14972 	// Subjec to Z and out of bounds? Return to level!
14973 	if (self->modeldata.subject_to_minz>0)
14974 	{
14975 		if(zdir && z < PLAYER_MIN_Z)
14976 		{
14977 			zdir = PLAYER_MIN_Z - self->z;
14978 			execute_onblockz_script(self);
14979 		}
14980 	}
14981 
14982 	if (self->modeldata.subject_to_maxz>0)
14983 	{
14984 		if(zdir && z > PLAYER_MAX_Z)
14985 		{
14986 			zdir = PLAYER_MAX_Z - self->z;
14987 			execute_onblockz_script(self);
14988 		}
14989 	}
14990 
14991 	// End of level is blocked?
14992 	if(level->exit_blocked)
14993 	{
14994 		if(x > level->width-30-(PLAYER_MAX_Z-z))
14995 		{
14996 			xdir = level->width-30-(PLAYER_MAX_Z-z) - self->x;
14997 		}
14998 	}
14999 	// screen checking
15000 	if(self->modeldata.subject_to_screen>0)
15001 	{
15002 		if(x < advancex+10)
15003 		{
15004 			xdir = advancex+10 - self->x;
15005 			execute_onblocks_script(self);  //Screen block event.
15006 		}
15007 		else if(x > advancex+(videomodes.hRes-10))
15008 		{
15009 			xdir = advancex+(videomodes.hRes-10) - self->x;
15010 			execute_onblocks_script(self);  //Screen block event.
15011 		}
15012 	}
15013 
15014 	if(!xdir && !zdir) return 0;
15015 	x = self->x + xdir;  z = self->z + zdir;
15016 
15017 	//-----------end of bounds checking-----------
15018 
15019 	//-------------hole checking ---------------------
15020 	// Don't walk into a hole or walk off platforms into holes
15021 	if( self->modeldata.type!=TYPE_PLAYER && self->idling &&
15022 		(!self->animation->seta||self->animation->seta[self->animpos]<0) &&
15023 		self->modeldata.subject_to_hole>0 && !inair(self) &&
15024 		!(self->modeldata.aimove&AIMOVE2_IGNOREHOLES))
15025 	{
15026 
15027 		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))
15028 		{
15029 			zdir = 0;
15030 		}
15031 		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))
15032 		{
15033 			xdir = 0;
15034 		}
15035 	}
15036 
15037 	if(!xdir && !zdir) return 0;
15038 	x = self->x + xdir;  z = self->z + zdir;
15039 	//-----------end of hole checking---------------
15040 
15041 	//--------------obstacle checking ------------------
15042 	if(self->modeldata.subject_to_obstacle>0 /*&& !inair(self)*/)
15043 	{
15044 		if((other = find_ent_here(self, x, self->z, (TYPE_OBSTACLE | TYPE_TRAP))) &&
15045 		   (xdir>0 ? other->x > self->x: other->x < self->x) &&
15046 		   (!other->animation->platform||!other->animation->platform[other->animpos][7]))
15047 			{
15048 				xdir    = 0;
15049 				execute_onblocko_script(self, other);
15050 			}
15051 		if((other = find_ent_here(self, self->x, z, (TYPE_OBSTACLE | TYPE_TRAP))) &&
15052 		   (zdir>0 ? other->z > self->z: other->z < self->z) &&
15053 		   (!other->animation->platform||!other->animation->platform[other->animpos][7]))
15054 			{
15055 				zdir    = 0;
15056 				execute_onblocko_script(self, other);
15057 			}
15058 	}
15059 
15060 	if(!xdir && !zdir) return 0;
15061 	x = self->x + xdir*2;  z = self->z + zdir*2;
15062 
15063 	//-----------end of obstacle checking--------------
15064 
15065 	// ---------------- platform checking----------------
15066 
15067 	if(self->animation->height) heightvar = self->animation->height;
15068 	else heightvar = self->modeldata.height;
15069 
15070 	// Check for obstacles with platform code and adjust base accordingly
15071 	if(self->modeldata.subject_to_platform>0 && (other = check_platform_between(x, z, self->a, self->a+heightvar, self)) )
15072 	{
15073 		if(xdir>0 ? other->x>self->x : other->x<self->x) {xdir = 0; }
15074 		if(zdir>0 ? other->z>self->z : other->z<self->z) {zdir = 0; }
15075 	}
15076 
15077 	if(!xdir && !zdir) return 0;
15078 	x = self->x + xdir;  z = self->z + zdir;
15079 
15080 	//-----------end of platform checking------------------
15081 
15082 	// ------------------ wall checking ---------------------
15083 	if(self->modeldata.subject_to_wall){
15084 
15085 		if((wall = checkwall(x, self->z))>=0 && level->walls[wall][7]>self->a)
15086 		{
15087 			if(xdir > 0.5){ xdir = 0.5; }
15088 			else if(xdir < -0.5){ xdir = -0.5; }
15089 			if((wall = checkwall(self->x + xdir, self->z))>=0 && level->walls[wall][7]>self->a){
15090 				xdir = 0;
15091 				execute_onblockw_script(self,1,(double)level->walls[wall][7]);
15092 			}
15093 		}
15094 		if((wall = checkwall(self->x, z))>=0 && level->walls[wall][7]>self->a)
15095 		{
15096 			if(zdir > 0.5){ zdir = 0.5; }
15097 			else if(zdir < -0.5){ zdir = -0.5; }
15098 			if((wall = checkwall(self->x, self->z + zdir))>=0 && level->walls[wall][7]>self->a){
15099 				zdir = 0;
15100 				execute_onblockw_script(self,2,(double)level->walls[wall][7]);
15101 			}
15102 		}
15103 	}
15104 
15105 
15106 	if(!xdir && !zdir) return 0;
15107 	x = self->x + xdir;  z = self->z + zdir;
15108 	//----------------end of wall checking--------------
15109 
15110 	//------------------ grab/throw checking------------------
15111 	if( (validanim(self,ANI_THROW) ||
15112 		 validanim(self,ANI_GRAB)) && self->idling &&
15113 		(other = find_ent_here(self,x, z, self->modeldata.hostile))&&
15114 		cangrab(self, other) &&
15115 		adjust_grabposition(self, other, self->modeldata.grabdistance, 0))
15116 	{
15117 		if(self->model->grabflip&1) self->direction = (self->x < other->x);
15118 
15119 		set_opponent(other, self);
15120 		ents_link(self, other);
15121 		other->attacking = 0;
15122 		self->idling = 0;
15123 		self->running = 0;
15124 
15125 		self->xdir = self->zdir =
15126 		other->xdir = other->zdir = 0;
15127 		if(validanim(self,ANI_GRAB))
15128 		{
15129 			ent_set_anim(self, ANI_GRAB, 0);
15130 			set_pain(other, -1, 0); //set grabbed animation
15131 			if(self->model->grabflip&2) other->direction = !self->direction;
15132 			self->attacking = 0;
15133 			memset(self->combostep, 0, 5*sizeof(int));
15134 			other->takeaction = common_grabbed;
15135 			self->takeaction = common_grab;
15136 			other->stalltime = time + GRAB_STALL;
15137 			self->releasetime = time + (GAME_SPEED/2);
15138 		}
15139 		// use original throw code if throwframewait not present, kbandressen 10/20/06
15140 		else if(self->modeldata.throwframewait == -1)
15141 			dothrow();
15142 		// otherwise enemy_throw_wait will be used, kbandressen 10/20/06
15143 		else
15144 		{
15145 			if(self->model->grabflip&2) other->direction = !self->direction;
15146 			ent_set_anim(self, ANI_THROW, 0);
15147 			set_pain(other, -1, 0); // set grabbed animation
15148 
15149 			other->takeaction = common_prethrow;
15150 			self->takeaction = common_throw_wait;
15151 		}
15152 		return 0;
15153 	}
15154 	// ---------------  end of grab/throw checking ------------------------
15155 
15156 	// do move and return
15157 	self->x += xdir;
15158 	self->z += zdir;
15159 
15160 	if(xdir)    execute_onmovex_script(self);   //X move event.
15161 	if(zdir)    execute_onmovez_script(self);   //Z move event.
15162 	return 2-(xdir==oxdir && zdir ==ozdir);     // return 2 for some checks
15163 }
15164 
15165 // enemies run off after attack
common_runoff()15166 void common_runoff()
15167 {
15168 	entity *target = normal_find_target(-1,0);
15169 
15170 	if(target == NULL) { //sealth checking
15171 		set_idle(self);
15172 		self->zdir = self->xdir = 0;
15173 		self->takeaction = NULL; // OK, back to A.I. root
15174 		return;
15175 	}
15176 
15177 	if(!self->modeldata.noflip) self->direction = (self->x < target->x);
15178 	if(self->direction) self->xdir = -self->modeldata.speed/2;
15179 	else self->xdir = self->modeldata.speed/2;
15180 
15181 	self->zdir = 0;
15182 
15183 	adjust_walk_animation(target);
15184 
15185 	if(time > self->stalltime) self->takeaction = NULL; // OK, back to A.I. root
15186 }
15187 
15188 
common_stuck_underneath()15189 void common_stuck_underneath()
15190 {
15191 	if(player[(int)self->playerindex].keys & FLAG_MOVELEFT)
15192 	{
15193 		player[(int)self->playerindex].playkeys -= FLAG_MOVELEFT;
15194 		self->direction = 0;
15195 	}
15196 	else if(player[(int)self->playerindex].keys & FLAG_MOVERIGHT)
15197 	{
15198 		player[(int)self->playerindex].playkeys -= FLAG_MOVERIGHT;
15199 		self->direction = 1;
15200 	}
15201 	if(player[(int)self->playerindex].keys & FLAG_ATTACK && validanim(self,ANI_DUCKATTACK))
15202 	{
15203 		player[(int)self->playerindex].playkeys -= FLAG_ATTACK;
15204 		set_attacking(self);
15205 		self->xdir = self->zdir = 0;
15206 		self->combostep[0] = 0;
15207 		self->running = 0;
15208 		ent_set_anim(self, ANI_DUCKATTACK, 0);
15209 		self->takeaction = common_attack_proc;
15210 		return;
15211 	}
15212 	if((player[(int)self->playerindex].keys & FLAG_MOVEDOWN) && (player[(int)self->playerindex].keys & FLAG_JUMP) && validanim(self,ANI_SLIDE))
15213 	{
15214 		player[(int)self->playerindex].playkeys -= FLAG_MOVEDOWN;
15215 		player[(int)self->playerindex].playkeys -= FLAG_JUMP;
15216 		set_attacking(self);
15217 		self->xdir = self->zdir = 0;
15218 		self->combostep[0] = 0;
15219 		self->running = 0;
15220 		ent_set_anim(self, ANI_SLIDE, 0);
15221 		self->takeaction = common_attack_proc;
15222 		return;
15223 	}
15224 	if(!check_platform_between(self->x, self->z, self->a, self->a+self->modeldata.height, self) )
15225 	{
15226 		set_idle(self);
15227 		self->takeaction = NULL;
15228 		return;
15229 	}
15230 }
15231 
15232 
15233 // finish attacking, do something
common_attack_finish()15234 void common_attack_finish()
15235 {
15236 	entity *target;
15237 	int stall;
15238 
15239 	self->xdir = self->zdir = 0;
15240 
15241 	if(self->modeldata.type == TYPE_PLAYER)
15242 	{
15243 		set_idle(self);
15244 		self->takeaction = NULL;
15245 		return;
15246 	}
15247 
15248 	target = self->opponent;
15249 
15250 	if(target && !self->modeldata.nomove && diff(self->x, target->x)<80 && (rand32()&3))
15251 	{
15252 		common_walk_anim(self);
15253 		//ent_set_anim(self, ANI_WALK, 0);
15254 		self->idling = 1;
15255 		self->takeaction = common_runoff;
15256 	}
15257 	else
15258 	{
15259 		set_idle(self);
15260 		self->takeaction = NULL;
15261 	}
15262 
15263 	stall = GAME_SPEED - self->modeldata.aggression;
15264 	if (stall<GAME_SPEED/2)
15265 	{
15266 		stall = GAME_SPEED/2;
15267 	}
15268 	self->stalltime = time + stall;
15269 }
15270 
15271 
15272 //while playing attack animation
common_attack_proc()15273 void common_attack_proc()
15274 {
15275 
15276 	if(self->animating || diff(self->a, self->base)>=4) return;
15277 
15278 	if(self->tocost)
15279 	{    // Enemy was hit with a special so go ahead and subtract life
15280 		if(check_energy(1, self->animnum))
15281 		{
15282 			self->mp -= self->animation->energycost.cost;
15283 		}
15284 		else self->health -= self->animation->energycost.cost;
15285 		self->tocost = 0;    // Life is subtracted, so go ahead and reset the flag
15286 	}
15287 
15288 	if(self == smartbomber)
15289 	{    // Player is done with the special animation, so unfreeze and execute a smart bomb
15290 		smart_bomb(self, self->modeldata.smartbomb);
15291 		smartbomber = NULL;
15292 	}
15293 	if(self->reactive == 1)
15294 	{
15295 		subtract_shot();
15296 		self->reactive=0;
15297 	}
15298 	self->attacking = 0;
15299 	// end of attack proc
15300 	common_attack_finish();
15301 }
15302 
15303 
15304 // dispatch A.I. attack
common_attack()15305 int common_attack()
15306 {
15307 	int aiattack ;
15308 
15309 	//if(stalker==self) return 0;
15310 
15311 	if(self->modeldata.aiattack==-1) return 0;
15312 
15313 	aiattack = self->modeldata.aiattack & MASK_AIATTACK1;
15314 
15315 	switch(aiattack)
15316 	{
15317 	case AIATTACK1_LONG:
15318 	case AIATTACK1_MELEE:
15319 	case AIATTACK1_NOATTACK:
15320 		return 0;
15321 	default:                    // this is the only available attack style by now
15322 		return inair(self)?0:normal_attack();
15323 	}
15324 }
15325 
15326 //maybe used many times, so make a function
15327 // A.I. characters will check if there's a wall infront, and jump onto it if possible
15328 // return 1 if jump
common_try_jump()15329 int common_try_jump()
15330 {
15331 	float xdir, zdir;
15332 	int wall, j=0;
15333 	float rmin, rmax;
15334 
15335 	if(validanim(self,ANI_JUMP)) //Can jump?
15336 	{
15337 		//Check to see if there is a wall within jumping distance and within a jumping height
15338 		xdir = 0; wall = -1;
15339 		rmin = (float)self->modeldata.animation[ANI_JUMP]->range.xmin;
15340 		rmax = (float)self->modeldata.animation[ANI_JUMP]->range.xmax;
15341 		if(self->direction) xdir = self->x + rmin;
15342 		else xdir = self->x - rmin;
15343 		//check z jump
15344 		if(self->modeldata.jumpmovez) zdir = self->z + self->zdir;
15345 		else zdir = self->z;
15346 
15347 		if( (wall = checkwall_below(xdir, zdir, 999999)) >= 0 &&
15348 			level->walls[wall][7] <= self->a + rmax &&
15349 			!inair(self) && self->a < level->walls[wall][7]  )
15350 		{
15351 			j=1;
15352 		}
15353 		else if(checkhole(self->x + (self->direction?2:-2), zdir) &&
15354 				checkwall(self->x + (self->direction?2:-2), zdir)<0 &&
15355 				check_platform (self->x + (self->direction?2:-2), zdir, self)==NULL &&
15356 				!checkhole(self->x + (self->direction?rmax:-rmax), zdir))
15357 		{
15358 			j=1;
15359 		}
15360 	}
15361 
15362 	/*
15363 	Damon V. Caskey
15364 	03292010
15365 	AI can will check its RUNJUMP range if JUMP can't reach. Code is pretty redundant,
15366 	can probably be moved to a function later.
15367 	*/
15368 	if(!j && validanim(self, ANI_RUNJUMP))														//Jump check failed and can run jump?
15369 	{
15370 		//Check for wall in range of RUNJUMP.
15371 		xdir = 0; wall = -1;
15372 		rmin = (float)self->modeldata.animation[ANI_RUNJUMP]->range.xmin;
15373 		rmax = (float)self->modeldata.animation[ANI_RUNJUMP]->range.xmax;
15374 		if(self->direction) xdir = self->x + rmin;
15375 		else xdir = self->x - rmin;
15376 		//check z jump
15377 		if(self->modeldata.jumpmovez) zdir = self->z + self->zdir;
15378 		else zdir = self->z;
15379 
15380 		if( (wall = checkwall_below(xdir, zdir, 999999)) >= 0 &&
15381 			level->walls[wall][7] <= self->a + rmax &&
15382 			!inair(self) && self->a < level->walls[wall][7]  )
15383 		{
15384 			j=2;																				//Set to perform runjump.
15385 		}
15386 		//Check for pit in range of RUNJUMP.
15387 		else if(checkhole(self->x + (self->direction?2:-2), zdir) &&
15388 				checkwall(self->x + (self->direction?2:-2), zdir)<0 &&
15389 				check_platform (self->x + (self->direction?2:-2), zdir, self)==NULL &&
15390 				!checkhole(self->x + (self->direction?rmax:-rmax), zdir))
15391 		{
15392 			j=2;																				//Set to perform runjump.
15393 		}
15394 	}
15395 
15396 	if(j)
15397 	{
15398 		if(self->running || j==2)
15399 		{
15400 			if(validanim(self,ANI_RUNJUMP))														//Running or only within range of RUNJUMP?
15401 				tryjump(self->modeldata.runjumpheight, self->modeldata.jumpspeed*self->modeldata.runjumpdist, (self->modeldata.jumpmovez)?self->zdir:0, ANI_RUNJUMP);
15402 			else if(validanim(self,ANI_FORWARDJUMP))
15403 				tryjump(self->modeldata.runjumpheight, self->modeldata.jumpspeed*self->modeldata.runjumpdist, (self->modeldata.jumpmovez)?self->zdir:0, ANI_FORWARDJUMP);
15404 			else
15405 				tryjump(self->modeldata.runjumpheight, self->modeldata.jumpspeed*self->modeldata.runjumpdist, (self->modeldata.jumpmovez)?self->zdir:0, ANI_JUMP);
15406 		}
15407 		else
15408 		{
15409 			if(validanim(self,ANI_FORWARDJUMP))
15410 				tryjump(self->modeldata.jumpheight, self->modeldata.jumpspeed, (self->modeldata.jumpmovez)?self->zdir:0, ANI_FORWARDJUMP);
15411 			else
15412 				tryjump(self->modeldata.jumpheight, self->modeldata.jumpspeed, (self->modeldata.jumpmovez)?self->zdir:0, ANI_JUMP);
15413 		}
15414 
15415 		return 1;
15416 	}
15417 	return 0;
15418 }
15419 
adjust_walk_animation(entity * other)15420 void adjust_walk_animation(entity* other)
15421 {
15422 	if(self->running)
15423 	{
15424 		ent_set_anim(self, ANI_RUN, 0);
15425 		return;
15426 	}
15427 
15428 	//reset the walk animation
15429 	if( ((!other && self->zdir<0)||(other && self->z>other->z)) && validanim(self,ANI_UP))
15430 		common_up_anim(self); //ent_set_anim(self, ANI_UP, 0);
15431 	else if(((!other && self->zdir>0)||(other && other->z > self->z)) && validanim(self,ANI_DOWN))
15432 		common_down_anim(self); //ent_set_anim(self, ANI_DOWN, 0);
15433 	else if((self->direction ? self->xdir<0 : self->xdir>0) && validanim(self,ANI_BACKWALK))
15434 		common_backwalk_anim(self); //ent_set_anim(self, ANI_BACKWALK, 0);
15435 	else common_walk_anim(self); //ent_set_anim(self, ANI_WALK, 0);
15436 
15437 	if((self->direction ? self->xdir<0 : self->xdir>0) && self->animnum!=ANI_BACKWALK)
15438 		self->animating = -1;
15439 	else self->animating = 1;
15440 }
15441 
15442 //may be used many times, so make a function
15443 // try to move towards the item
common_try_pick(entity * other)15444 int common_try_pick(entity* other)
15445 {
15446 	// if there's an item to pick up, move towards it.
15447 	float maxspeed = self->modeldata.speed*1.5;
15448 	float dx = diff(self->x, other->x);
15449 	float dz = diff(self->z, other->z);
15450 
15451 	if(other == NULL || self->modeldata.nomove) return 0;
15452 
15453 	if(!dz && !dx) self->xdir = self->zdir = 0;
15454 	else {
15455 		self->xdir = maxspeed * dx / (dx+dz);
15456 		self->zdir = maxspeed * dz / (dx+dz);
15457 	}
15458 	if(self->x > other->x) self->xdir = -self->xdir;
15459 	if(self->z > other->z) self->zdir = -self->zdir;
15460 
15461 	self->running = 0;
15462 
15463 	adjust_walk_animation(other);
15464 
15465 	return 1;
15466 }
15467 
15468 // wall sliding code
15469 // whichside:
15470 //      0
15471 //  1       3
15472 //      2
adjustdirection(float coords[],float offx,float offz,float ox,float oz,float xdir,float zdir,float * cxdir,float * czdir)15473 int adjustdirection(float coords[], float offx, float offz, float ox, float oz, float xdir, float zdir, float *cxdir, float *czdir)
15474 {
15475 	float x[4], z[4];
15476 	int whichside, i;
15477 	float a;
15478 
15479 	for(i=0; i<4; i++){
15480 		x[i] = coords[2+i] + coords[0] + offx;
15481 	}
15482 	z[1] = z[3] = coords[1] + offz;
15483 	z[0] = z[2] = z[1] - coords[6];
15484 
15485 	if(oz<=z[0]) whichside = 0;
15486 	else if(oz>=z[1]) whichside = 2;
15487 	else if(ox<x[2]) whichside = 1;
15488 	else whichside = 3;
15489 
15490 	if(whichside==0 || whichside==2){
15491 		*cxdir = xdir;
15492 		*czdir = 0;
15493 	}else{
15494 		if((x[0]==x[1] && whichside==1) || (x[2]==x[3] && whichside==3)) {
15495 			*cxdir = 0;
15496 			*czdir = zdir;
15497 		}else{
15498 			if(whichside==1)
15499 				a = (z[1]-z[0])/(x[1]-x[0]);
15500 			else
15501 				a = (z[3]-z[2])/(x[3]-x[2]);
15502 
15503 			*cxdir = xdir + zdir/a;
15504 			*czdir = a * xdir + zdir;
15505 
15506 			a = (ABS(xdir) + ABS(zdir)) / (ABS(*cxdir) + ABS(*czdir)) ;
15507 			*cxdir *= a;
15508 			*czdir *= a;
15509 		}
15510 	}
15511 	//printf("%f, %f, %f, %f, %d\n", xdir, zdir, *cxdir, *czdir, whichside);
15512 	return whichside;
15513 }
15514 
15515 // x, z - current position
15516 // tx, tz - target position
15517 // speed - max speed
15518 // xdir, zdir - return values
adjustspeed(float speed,float x,float z,float tx,float tz,float * xdir,float * zdir)15519 void adjustspeed(float speed, float x, float z, float tx, float tz, float* xdir, float* zdir){
15520 	float xd, zd;
15521 	float dx = diff(tx, x);
15522 	float dz = diff(tz,z)*2;
15523 
15524 	if(dx>dz) {
15525 		xd = speed;
15526 		zd = xd/dx*dz;
15527 	}else if(dz>dx){
15528 		zd = speed;
15529 		xd = zd/dz*dx;
15530 	}else if(dx){
15531 		xd = zd = speed;
15532 	}else{
15533 		xd = zd = 0;
15534 	}
15535 
15536 	if(tx<x) xd = -xd;
15537 	if(tz<z) zd = -zd;
15538 
15539 	zd /= 2;
15540 
15541 	*xdir = xd;
15542 	*zdir = zd;
15543 
15544 }
15545 
checkpathblocked()15546 int checkpathblocked()
15547 {
15548 	float x, z, r;
15549 	int aitype;
15550 	if(self->modeldata.nomove) return 0;
15551 	if(self->stalltime>=time)
15552 	{
15553 		aitype = self->modeldata.aimove;
15554 		if(self->modeldata.subtype==SUBTYPE_CHASE) aitype |= AIMOVE1_CHASE;
15555 
15556 		//be moo tolerable to PLAYER_MAX_Z and PLAYER_MIN_Z
15557 		if((self->modeldata.subject_to_maxz && self->zdir>0 && !self->xdir && self->zdir+self->z>=PLAYER_MAX_Z) ||
15558 		   (self->modeldata.subject_to_minz && self->zdir<0 && !self->xdir && self->zdir+self->z<=PLAYER_MIN_Z) )
15559 		{
15560 			self->zdir = -self->zdir;
15561 			self->pathblocked = 0;
15562 			return 1;
15563 		}
15564 
15565 		if(self->pathblocked>40 || (self->pathblocked>20 && (aitype & (AIMOVE1_CHASEX|AIMOVE1_CHASEZ|AIMOVE1_CHASE))))
15566 		{
15567 
15568 			x = self->xdir;
15569 			z = self->zdir;
15570 			if(x>0) x = self->modeldata.speed;
15571 			else if(x<0) x = -self->modeldata.speed;
15572 			if(z>0) z = self->modeldata.speed/2;
15573 			else if(z<0) z = -self->modeldata.speed/2;
15574 			r = randf(1);
15575 			if(r>0.6f){
15576 				self->zdir = x;
15577 				self->xdir = -z;
15578 			} else if(r>0.2f) {
15579 				self->zdir = -x;
15580 				self->xdir = z;
15581 			}else{
15582 				self->zdir = (1.0f - randf(2))*self->modeldata.speed/2;
15583 				self->xdir = (1.0f - randf(2))*self->modeldata.speed;
15584 			}
15585 			self->running = 0; // TODO: re-adjust walk speed
15586 			self->stalltime = time + GAME_SPEED/2;
15587 			adjust_walk_animation(NULL);
15588 			self->pathblocked = 0;
15589 
15590 		}
15591 		return 1;
15592 	}
15593 	return 0;
15594 }
15595 
15596 
15597 //may be used many times, so make a function
15598 // try to move towards the target
common_try_chase(entity * target,int dox,int doz)15599 int common_try_chase(entity* target, int dox, int doz)
15600 {
15601 	// start chasing the target
15602 	float dx, dz;
15603 	float mindx, mindz;
15604 	int grabd, facing;
15605 	int stalladd = 0;
15606 
15607 	self->running = 0;
15608 
15609 	if(self->xdir>0) self->xdir = self->modeldata.speed;
15610 	else if(self->xdir<0) self->xdir = -self->modeldata.speed;
15611 	if(self->zdir>0) self->zdir = self->modeldata.speed/2;
15612 	else if(self->zdir<0) self->zdir = -self->modeldata.speed/2;
15613 
15614 	if(target == NULL || self->modeldata.nomove) return 0;
15615 
15616 	facing = (self->direction?self->x<target->x:self->x>target->x);
15617 
15618 	if(!facing) {
15619 		return 0; // don't chase a target behind me
15620 	}
15621 
15622 	dx = diff(self->x, target->x);
15623 	dz = diff(self->z, target->z);
15624 	grabd = self->modeldata.grabdistance;
15625 
15626 	mindx = grabd;
15627 	mindz = grabd / 4;
15628 
15629 	if(dox){
15630 		if((dx>150 || dx+dz>200) && validanim(self, ANI_RUN)){
15631 			self->xdir = self->modeldata.runspeed;
15632 			self->running = 1;
15633 		}
15634 		else self->xdir = self->modeldata.speed;
15635 		if(target->x<self->x) self->xdir = -self->xdir;
15636 		if(dx<mindx && dz<mindz) {
15637 			self->xdir = -self->xdir;
15638 			stalladd = -GAME_SPEED/3;
15639 		}
15640 	}
15641 
15642 	if(doz){
15643 		if(dz>100 && self->modeldata.runupdown && validanim(self, ANI_RUN)){
15644 			self->zdir = self->modeldata.runspeed/2;
15645 			self->running = 1;
15646 		}
15647 		else self->zdir = self->modeldata.speed/2;
15648 		if(target->z<self->z) self->zdir = -self->zdir;
15649 		if(dx<mindx && dz<mindz) {
15650 			self->zdir = -self->zdir/2;
15651 			stalladd = -GAME_SPEED/3;
15652 		}
15653 	}
15654 
15655 	self->stalltime += stalladd;
15656 
15657 
15658 	return 1;
15659 }
15660 
15661 //may be used many times, so make a function
15662 // minion follow his owner
common_try_follow(entity * target,int dox,int doz)15663 int common_try_follow(entity* target, int dox, int doz)
15664 {
15665 	// start chasing the target
15666 	float dx, dz, distance;
15667 	int mx, mz;
15668 	int facing;
15669 
15670 	//target = self->parent;
15671 	if(target == NULL || self->modeldata.nomove) return 0;
15672 	distance = (float)((validanim(self,ANI_IDLE))? self->modeldata.animation[ANI_IDLE]->range.xmin: 100);
15673 
15674 	if(distance<=0) distance = 100.0;
15675 
15676 	facing = (self->direction?self->x<target->x:self->x>target->x);
15677 
15678 	dx = diff(self->x, target->x);
15679 	dz = diff(self->z, target->z);
15680 
15681 	if(dox && dx<distance) {
15682 		self->xdir = 0;
15683 		mx = 0;
15684 	}else mx = 1;
15685 
15686 	if(doz && dz<distance/2){
15687 		self->zdir = 0;
15688 		mz = 0;
15689 	}else mz = 1;
15690 
15691 	if(!mx && !mz){
15692 		self->running = 0;
15693 		return 1;
15694 	}
15695 
15696 	if(dox && mx){
15697 		if(facing && dx>200 && validanim(self, ANI_RUN)){
15698 			self->xdir = self->modeldata.runspeed;
15699 			self->running = 1;
15700 		}
15701 		else self->xdir = self->modeldata.speed;
15702 	}
15703 
15704 	if(doz && mz){
15705 		if(facing && dx>200 && self->modeldata.runupdown && validanim(self, ANI_RUN)){
15706 			self->zdir = self->modeldata.runspeed/2;
15707 			self->running = 1;
15708 		}
15709 		else self->zdir = self->modeldata.speed/2;
15710 	}
15711 
15712 	if(self->x>target->x) self->xdir = -self->xdir;
15713 	if(self->z>target->z) self->zdir = -self->zdir;
15714 
15715 	return 1;
15716 }
15717 
15718 // try to avoid the target
15719 // used by 'avoid avoidz avoidx
common_try_avoid(entity * target,int dox,int doz)15720 int common_try_avoid(entity* target, int dox, int doz)
15721 {
15722 	float dx, dz;
15723 	int stalladd = 0;
15724 	float maxdz, mindz, maxdx, mindx;
15725 
15726 	if(target == NULL || self->modeldata.nomove) return 0;
15727 
15728 	dx = diff(self->x, target->x);
15729 	dz = diff(self->z, target->z);
15730 
15731 	//printf("aimove: %d\n", (aitype &(AIMOVE1_AVOIDX|AIMOVE1_AVOIDZ|AIMOVE1_AVOIDX)));
15732 
15733 	/*if(validanim(self, ANI_BACKWALK)){
15734 		mindx = self->modeldata.animation[ANI_BACKWALK]->range.xmin;
15735 		maxdx = self->modeldata.animation[ANI_BACKWALK]->range.xmax;
15736 		mindz = self->modeldata.animation[ANI_BACKWALK]->range.zmin;
15737 		maxdz = self->modeldata.animation[ANI_BACKWALK]->range.zmax;
15738 	}else if(validanim(self, ANI_WALK)){
15739 		mindx = self->modeldata.animation[ANI_WALK]->range.xmin;
15740 		maxdx = self->modeldata.animation[ANI_WALK]->range.xmax;
15741 		mindz = self->modeldata.animation[ANI_WALK]->range.zmin;
15742 		maxdz = self->modeldata.animation[ANI_WALK]->range.zmax;
15743 	}else*/{
15744 		mindx = videomodes.hRes / 3;
15745 		maxdx = videomodes.hRes / 2;
15746 		mindz = videomodes.vRes / 3;
15747 		maxdz = videomodes.vRes / 2;
15748 	}
15749 
15750 	if(dox){
15751 		if(self->x < screenx) {
15752 			self->xdir = self->modeldata.speed;
15753 			stalladd = GAME_SPEED;
15754 		}else if(self->x > screenx + videomodes.hRes) {
15755 			self->xdir = -self->modeldata.speed;
15756 			stalladd = GAME_SPEED;
15757 		}else if(dx < mindx)
15758 			self->xdir = (self->x < target->x)? (-self->modeldata.speed):self->modeldata.speed;
15759 		else if (dx > maxdx)
15760 			self->xdir = (self->x < target->x)? self->modeldata.speed:(-self->modeldata.speed);
15761 		else self->xdir = 0;
15762 	}
15763 
15764 	if(doz){
15765 		if(self->z < screeny) {
15766 			self->zdir = self->modeldata.speed/2;
15767 			stalladd = GAME_SPEED;
15768 		}else if(self->z > screeny + videomodes.vRes) {
15769 			self->zdir = -self->modeldata.speed/2;
15770 			stalladd = GAME_SPEED;
15771 		}else if(dz < mindz)
15772 			self->zdir = (self->z < target->z)? (-self->modeldata.speed/2):(self->modeldata.speed/2);
15773 		else if(dz > maxdz)
15774 			self->zdir = (self->z < target->z)? (self->modeldata.speed/2):(-self->modeldata.speed/2);
15775 		else self->zdir = 0;
15776 	}
15777 
15778 	self->stalltime += stalladd;
15779 
15780 	return 1;
15781 }
15782 
15783 //  wander completely
common_try_wandercompletely(int dox,int doz)15784 int common_try_wandercompletely(int dox, int doz)
15785 {
15786 	int rnum;
15787 	int stalladd = 0;
15788 
15789 	if(self->modeldata.nomove) return 0;
15790 
15791 	if(dox){
15792 		rnum = rand32();
15793 		if((rnum & 15) < 4) self->xdir = -self->modeldata.speed;
15794 		else if((rnum & 15) > 11) self->xdir = self->modeldata.speed;
15795 		else self->xdir = 0;
15796 		if( (self->x<screenx-10 && self->xdir<0) ||
15797 			(self->x>screenx+videomodes.hRes+10 && self->xdir>0) ){
15798 			self->xdir = -self->xdir;
15799 			stalladd = GAME_SPEED;
15800 		}
15801 
15802 	}
15803 	if(doz){
15804 		rnum = rand32();
15805 		if((rnum & 15) < 4) self->zdir = -self->modeldata.speed/2;
15806 		else if((rnum & 15) > 11) self->zdir = self->modeldata.speed/2;
15807 		else self->zdir = 0;
15808 		if( (self->z<screeny-10 && self->zdir<0) ||
15809 			(self->z>screeny+videomodes.vRes+10 && self->zdir>0) )
15810 		{
15811 			self->zdir = -self->zdir;
15812 			stalladd = GAME_SPEED;
15813 		}
15814 
15815 	}
15816 
15817 	self->stalltime += stalladd;
15818 
15819 	return 1;
15820 
15821 }
15822 
15823 // for normal and default ai patttern
common_try_wander(entity * target,int dox,int doz)15824 int common_try_wander(entity* target, int dox, int doz)
15825 {
15826 	int walk = 0, behind, grabd, agg;
15827 	int stalladd = 0;
15828 
15829 	float diffx, diffz, //distance from target
15830 		returndx, returndz, //how far should keep from target
15831 		borderdx, borderdz, //how far should keep offscreen
15832 		mindx, mindz;// don't walk into the target
15833 	int rnum = rand32()&7, rnum2 = rand32()&15, t;
15834 
15835 	if(!target || self->modeldata.nomove) return 0;
15836 
15837 	diffx = diff(self->x, target->x);
15838 	diffz = diff(self->z, target->z);
15839 	behind = ((self->x<target->x)==target->direction);
15840 	grabd = self->modeldata.grabdistance;
15841 	//when entity is behind the target, it has a greater chance to go after the target
15842 	agg = self->modeldata.aggression/50;
15843 	if(agg>10) agg = 10;
15844 	if(behind&&diffx<grabd*4&&diffz<grabd){ //right behind, go for it
15845 		t = 13;
15846 	}else if(behind){ // only behind, half chance
15847 		t = 7;
15848 	}else { // otherwise, 1/3 chance
15849 		t = 1;
15850 	}
15851 	t += agg;
15852 	if(behind && target->attacking) t+=5;
15853 	if(rnum2<t){ //chase target
15854 		returndx = grabd*1.5;
15855 		returndz = grabd/3;
15856 	}else{ // only chase when too far away
15857 		returndx = videomodes.hRes/2;
15858 		returndz = videomodes.vRes/2;
15859 	}
15860 	if(rnum2>7){
15861 		borderdx = videomodes.hRes/8;
15862 		borderdz = videomodes.vRes/8;
15863 	}else{
15864 		borderdx = borderdz = 0;
15865 	}
15866 
15867 	mindx = (!behind&&target->attacking)? grabd*3:grabd*1.2;
15868 	mindz = grabd/4;
15869 
15870 	if(dox){
15871 		if(self->x<screenx-borderdx){
15872 			self->xdir = self->modeldata.speed;
15873 			stalladd = GAME_SPEED/2;
15874 			walk = 1;
15875 		}else if (self->x>screenx+videomodes.hRes+borderdx){
15876 			self->xdir = -self->modeldata.speed;
15877 			stalladd = GAME_SPEED/2;
15878 			walk = 1;
15879 		}else if(diffx<mindx/2){
15880 			self->xdir = (self->x>target->x)?self->modeldata.speed:-self->modeldata.speed;
15881 			walk = 1;
15882 		}else if(diffx<mindx){
15883 			self->xdir = 0;
15884 		}else if(diffx>returndx){
15885 			self->xdir = (self->x>target->x)?-self->modeldata.speed:self->modeldata.speed;
15886 			walk = 1;
15887 		}else if(rnum < 3){
15888 			self->xdir = self->modeldata.speed;
15889 			walk = 1;
15890 		}else if(rnum > 4){
15891 			self->xdir = -self->modeldata.speed;
15892 			walk = 1;
15893 		}
15894 	}
15895 
15896 	if(doz)
15897 	{
15898 		rnum = rand32()&7;
15899 		if(self->z<screeny-borderdz){
15900 			self->zdir = self->modeldata.speed/2;
15901 			stalladd = GAME_SPEED/2;
15902 			walk |= 1;
15903 		}else if (self->z>screeny+videomodes.vRes+borderdz){
15904 			self->zdir = -self->modeldata.speed/2;
15905 			stalladd = GAME_SPEED/2;
15906 			walk |= 1;
15907 		}else if(diffz<mindz){
15908 			self->zdir = 0;
15909 		}else if(diffz>returndz){
15910 			self->zdir = (self->z>target->z)?-self->modeldata.speed/2:self->modeldata.speed/2;;
15911 			walk |= 1;
15912 		} else if(rnum < 2){
15913 			// Move up
15914 			self->zdir = -self->modeldata.speed/2;
15915 			walk |= 1;
15916 		}
15917 		else if(rnum > 5){
15918 			// Move down
15919 			self->zdir = self->modeldata.speed/2;
15920 			walk |= 1;
15921 		}
15922 	}
15923 	self->stalltime += stalladd;
15924 
15925 	return walk;
15926 }
15927 
15928 //A.I chracter pickup an item
common_pickupitem(entity * other)15929 void common_pickupitem(entity* other){
15930 	int pickup = 0;
15931 	//weapons
15932 	if(self->weapent == NULL && isSubtypeWeapon(other) && validanim(self,ANI_GET))
15933 	{
15934 		dropweapon(0);  //don't bother dropping the previous one though, scine it won't pickup another
15935 		self->weapent = other;
15936 		set_weapon(self, other->modeldata.weapnum, 0);
15937 		ent_set_anim(self, ANI_GET, 0);
15938 		if(self->modeldata.animal)  // UTunnels: well, ride, not get. :)
15939 		{
15940 			self->direction = other->direction;
15941 			self->x = other->x;
15942 			self->z = other->z;
15943 		}
15944 		set_getting(self);
15945 		self->takeaction = common_get;
15946 		self->xdir=self->zdir=0;//stop moving
15947 		pickup = 1;
15948 	}
15949 	// projectiles
15950 	else if(self->weapent == NULL && isSubtypeProjectile(other) && validanim(self,ANI_GET))
15951 	{
15952 		dropweapon(0);
15953 		self->weapent = other;
15954 		ent_set_anim(self, ANI_GET, 0);
15955 		set_getting(self);
15956 		self->takeaction = common_get;
15957 		self->xdir=self->zdir=0;//stop moving
15958 		pickup = 1;
15959 	}
15960 	// other items
15961 	else if(! isSubtypeWeapon(other) && ! isSubtypeProjectile(other) )
15962 	{
15963 		if(validanim(self,ANI_GET) && !isSubtypeTouch(other))
15964 		{
15965 			ent_set_anim(self, ANI_GET, 0);
15966 			set_getting(self);
15967 			self->takeaction = common_get;
15968 			self->xdir=self->zdir=0;//stop moving
15969 		}
15970 		if(other->health){
15971 			self->health += other->health;
15972 			if(self->health > self->modeldata.health) self->health = self->modeldata.health;
15973 			other->health = 0;
15974 			//if(SAMPLE_GET >= 0) sound_play_sample(SAMPLE_GET, 0, savedata.effectvol,savedata.effectvol, 100);
15975 		}
15976 		// else if, TODO: other effects
15977 		// kill that item
15978 		other->takeaction = suicide;
15979 		other->nextthink = time + GAME_SPEED * 3;
15980 		pickup = 1;
15981 	}
15982 	// hide it
15983 	if(pickup)
15984 	{
15985 		other->z = 100000;
15986 		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.
15987 	}
15988 }
15989 
15990 // for old bikers
biker_move()15991 int biker_move()
15992 {
15993 
15994 	if((self->direction)?(self->x > advancex+(videomodes.hRes+200)):(self->x < advancex-200))
15995 	{
15996 		self->direction = !self->direction;
15997 		self->attack_id = 0;
15998 		self->z = (float)(PLAYER_MIN_Z + randf((float)(PLAYER_MAX_Z-PLAYER_MIN_Z)));
15999 		if(SAMPLE_BIKE >= 0) sound_play_sample(SAMPLE_BIKE, 0, savedata.effectvol,savedata.effectvol, 100);
16000 		if(self->modeldata.speed) self->xdir = (self->direction)?(self->modeldata.speed):(-self->modeldata.speed);
16001 		else self->xdir = (self->direction)?((float)1.7 + randf((float)0.6)):(-((float)1.7 + randf((float)0.6)));
16002 	}
16003 
16004 	self->nextthink = time + THINK_SPEED / 2;
16005 	return 1;
16006 }
16007 
16008 // for common arrow types
arrow_move()16009 int arrow_move(){
16010 	int wall;
16011 	float dx;
16012 	float dz;
16013 	float maxspeed;
16014 	entity* target = NULL;
16015 
16016 	/*
16017 	int osk = self->modeldata.offscreenkill?self->modeldata.offscreenkill:200; //TODO: temporary code here, needs refine
16018 
16019 	if( (!self->direction && self->x < advancex - osk) || (self->direction && self->x > advancex + (videomodes.hRes+osk)) ||
16020 		(level && level->scrolldir != SCROLL_UP && level->scrolldir != SCROLL_DOWN &&
16021 		 (self->z < advancey - 200 || self->z > advancey + (videomodes.vRes+200))) ||
16022 		(level && (level->scrolldir == SCROLL_UP || level->scrolldir == SCROLL_DOWN) &&
16023 		 (self->z < -osk || self->z > videomodes.vRes + osk)) )
16024 	{
16025 		kill(self);
16026 		return 0;
16027 	}*/
16028 
16029 	// new subtype chase
16030 	if(self->modeldata.subtype == SUBTYPE_CHASE)
16031 	{
16032 		target = homing_find_target(self->modeldata.hostile);
16033 
16034 		if(target)
16035 		{
16036 			if(!self->modeldata.noflip) self->direction = (target->x > self->x);
16037 			// start chasing the target
16038 			dx = diff(self->x, target->x);
16039 			dz = diff(self->z, target->z);
16040 			maxspeed = self->modeldata.speed * 1.5;
16041 
16042 			if(!dz && !dx) self->xdir = self->zdir = 0;
16043 			else
16044 			{
16045 				self->xdir = maxspeed * dx / (dx+dz);
16046 				self->zdir = maxspeed * dz / (dx+dz);
16047 			}
16048 			if(self->direction!=1) self->xdir = -self->xdir;
16049 			if(self->z > target->z) self->zdir = -self->zdir;
16050 		}
16051 		else
16052 		{
16053 			if(!self->xdir && !self->zdir)
16054 			{
16055 				if(self->direction == 0) self->xdir = -self->modeldata.speed;
16056 				else if(self->direction == 1) self->xdir = self->modeldata.speed;
16057 			}
16058 		}
16059 		if(!self->modeldata.nomove)
16060 		{
16061 			if(target && self->z > target->z && validanim(self,ANI_UP)) common_up_anim(self); //ent_set_anim(self, ANI_UP, 0);
16062 			else if(target && target->z > self->z && validanim(self,ANI_DOWN)) common_down_anim(self); //ent_set_anim(self, ANI_DOWN, 0);
16063 			else if(validanim(self,ANI_WALK)) common_walk_anim(self); //ent_set_anim(self, ANI_WALK, 0);
16064 			else
16065 			{
16066 				ent_set_anim(self, ANI_IDLE, 0);
16067 			}
16068 		}
16069 	}
16070 	else
16071 	{
16072 		// Now projectiles can have custom speeds
16073 		if(self->direction == 0) self->xdir = -self->modeldata.speed;
16074 		else if(self->direction == 1) self->xdir = self->modeldata.speed;
16075 	}
16076 
16077 	if(level)
16078 	{
16079 		if((level->exit_blocked && self->x > level->width-30-(PLAYER_MAX_Z-self->z)) ||
16080 			(self->modeldata.subject_to_wall && (wall = checkwall(self->x, self->z)) >= 0 && self->a < level->walls[wall][7]))
16081 		{
16082 			// Added so projectiles bounce off blocked exits
16083 			if(validanim(self,ANI_FALL))
16084 			{
16085 				self->attacking = 0;
16086 				self->health -= 100000;
16087 				self->projectile = 0;
16088 				if(self->direction == 0) self->xdir = (float)-1.2;
16089 				else if(self->direction == 1) self->xdir = (float)1.2;
16090 				self->takeaction = common_fall;
16091 				self->damage_on_landing = 0;
16092 				toss(self, 2.5 + randf(1));
16093 				self->modeldata.no_adjust_base = 0;
16094 				self->modeldata.subject_to_wall = self->modeldata.subject_to_platform = self->modeldata.subject_to_hole = self->modeldata.subject_to_gravity = 1;
16095 				set_fall(self, ATK_NORMAL, 0, self, 100000, 0, 0, 0, 0, 0);
16096 			}
16097 		}
16098 	}
16099 	if(self->ptype)
16100 	{
16101 		self->autokill = 1;
16102 		self->nextthink = time + 1;
16103 	}
16104 	else self->nextthink = time + THINK_SPEED / 2;
16105 	return 1;
16106 }
16107 
16108 // for common bomb types
bomb_move()16109 int bomb_move()
16110 {
16111 	if(inair(self) && self->toexplode == 1) {
16112 		if(self->direction == 0) self->xdir = -self->modeldata.speed;
16113 		else if(self->direction == 1) self->xdir = self->modeldata.speed;
16114 		self->nextthink = time + THINK_SPEED / 2;
16115 	}else if(self->takeaction != bomb_explode){
16116 
16117 		self->tossv = 0;    // Stop moving up/down
16118 		self->modeldata.no_adjust_base = 1;    // Stop moving up/down
16119 		self->base = self->a;
16120 		self->xdir = self->zdir = 0;
16121 
16122 		if(self->modeldata.diesound >= 0) sound_play_sample(self->modeldata.diesound, 0, savedata.effectvol,savedata.effectvol, 100);
16123 
16124 		if(self->toexplode == 2 && validanim(self,ANI_ATTACK2))
16125 		{
16126 			ent_set_anim(self, ANI_ATTACK2, 0);    // If bomb never reaces the ground, play this
16127 		}
16128 		else
16129 		{
16130 			if (validanim(self,ANI_ATTACK1)) ent_set_anim(self, ANI_ATTACK1, 0);
16131 		}
16132 		// hit something, just make it an explosion animation.
16133 		self->modeldata.subject_to_wall = 0;
16134 		self->modeldata.subject_to_platform = 1;
16135 		self->modeldata.subject_to_hole = 0;
16136 		self->takeaction = bomb_explode;
16137 	}
16138 	return 1;
16139 }
16140 
star_move()16141 int star_move(){
16142 	int wall;
16143 
16144 	if(self->x<advancex-80 || self->x>advancex+(videomodes.hRes+80) || (self->base<=0 && !self->modeldata.falldie)){
16145 		kill(self);
16146 		return 0;
16147 	}
16148 
16149 	self->base -= 2;
16150 	self->a = self->base;
16151 
16152 	if(validanim(self,ANI_FALL))    // Added so projectiles bounce off blocked exits
16153 	{
16154 		if((level->exit_blocked && self->x > level->width-30-(PLAYER_MAX_Z-self->z)) ||
16155 			((wall = checkwall(self->x, self->z)) >= 0 && self->a < level->walls[wall][7]))
16156 		{
16157 			self->attacking = 0;
16158 			self->health -= 100000;
16159 			self->projectile = 0;
16160 			self->xdir = (self->direction)?(-1.2):1.2;
16161 			self->takeaction = common_fall;
16162 			self->damage_on_landing = 0;
16163 			toss(self, 2.5 + randf(1));
16164 			set_fall(self, ATK_NORMAL, 0, self, 100000, 0, 0, 0, 0, 0);
16165 		}
16166 	}
16167 
16168 	if(self->landed_on_platform || self->base <= 0)
16169 	{
16170 		self->health -= 100000;
16171 		if(self->modeldata.nodieblink == 2) self->animating = 0;
16172 		self->takeaction = common_lie;
16173 	}
16174 
16175 	self->nextthink = time + THINK_SPEED / 2;
16176 	return 1;
16177 }
16178 
16179 
16180 //dispatch move patterns
common_move()16181 int common_move()
16182 {
16183 	int aimove;
16184 	int air = inair(self);
16185 	entity* other = NULL; //item
16186 	entity* target = NULL;//hostile target
16187 	entity* owner = NULL;
16188 	entity* ent = NULL;
16189 	float seta;
16190 	int predir, stall;
16191 	int patx[4], pxc, px, patz[4], pzc, pz, fx, fz; //move pattern in z and x
16192 
16193 	if(self->modeldata.aimove==-1) return 0; // invalid value
16194 
16195 	// get move pattern
16196 	aimove = self->modeldata.aimove & MASK_AIMOVE1;
16197 
16198 //if(stricmp(self->name, "os")==0) printf("%d\n", aimove);
16199 	if(aimove&AIMOVE1_BIKER)
16200 	{// for biker subtype
16201 		return biker_move();
16202 	}
16203 	else if(aimove&AIMOVE1_ARROW)
16204 	{// for common straight-flying arrow
16205 		return arrow_move();
16206 	}
16207 	else if(aimove&AIMOVE1_STAR)
16208 	{// for a star, disappear when hit ground
16209 		return star_move();
16210 	}
16211 	else if(aimove&AIMOVE1_BOMB)
16212 	{// for a bomb, travel in a arc
16213 		return bomb_move();
16214 	}
16215 	else if(aimove&AIMOVE1_NOMOVE)
16216 	{// no move, just return
16217 		return 0;
16218 	}else{
16219 		// all above are special move patterns, real AI goes here:
16220 
16221 		if(air) return 0; // skip if the entity is in air
16222 
16223 		predir = self->direction;
16224 
16225 		target = normal_find_target(-1,0); // confirm the target again
16226 		other = normal_find_item();    // find an item
16227 		owner = self->parent;
16228 
16229 		if(!self->xdir)
16230 				self->running = 0;
16231 
16232 		if(!self->modeldata.noflip && !self->running && aimove!=AIMOVE1_WANDER){
16233 			if(other)   //try to pick up an item, if possible
16234 				self->direction = (self->x < other->x);
16235 			else if(target)
16236 				self->direction = (self->x < target->x);
16237 			else if(owner)
16238 				self->direction = (self->x < owner->x);
16239 		}else if(aimove==AIMOVE1_WANDER){
16240 			self->direction = (self->xdir>0);
16241 		}
16242 
16243 		//turn back if we have a turn animation
16244 		if(self->direction != predir && validanim(self,ANI_TURN)){
16245 			self->direction = !self->direction;
16246 			ent_set_anim(self, ANI_TURN, 0);
16247 			self->xdir = self->zdir = 0;
16248 			self->takeaction = common_turn;
16249 			return 1;
16250 		}
16251 
16252 		//pick up the item if possible
16253 		if( (other && other == find_ent_here(self, self->x, self->z, TYPE_ITEM)) && other->animation->vulnerable[other->animpos])//won't pickup an item that is not previous one
16254 		{
16255 			seta = (float)(self->animation->seta?self->animation->seta[self->animpos]:-1);
16256 			if(diff(self->a - (seta>= 0) * seta , other->a)<0.1)
16257 			common_pickupitem(other);
16258 			return 1;
16259 		}
16260 
16261 		if(common_try_jump()) return 1;  //need to jump? so quit
16262 
16263 		if(checkpathblocked()) return 1;
16264 
16265 		//bump-into handle
16266 		if(!other && target && diff(self->x, target->x)<self->modeldata.grabdistance*2 &&
16267 			diff(self->z, target->z)<self->modeldata.grabdistance){
16268 			self->stalltime = time-1;
16269 		}
16270 
16271 		// judge next move if stalltime is expired
16272 		if(self->stalltime < time ){
16273 			if(other){
16274 				// try walking to the item
16275 				common_try_pick(other);
16276 				ent = other;
16277 			}else{
16278 				if(target && (self->modeldata.subtype == SUBTYPE_CHASE ||
16279 				(self->modeldata.type == TYPE_NPC && self->parent)))
16280 					// try chase a target
16281 					aimove |= AIMOVE1_CHASE;
16282 
16283 				if(aimove & AIMOVE1_CHASE) aimove |= AIMOVE1_CHASEX|AIMOVE1_CHASEZ;
16284 				if(aimove & AIMOVE1_AVOID) aimove |= AIMOVE1_AVOIDX|AIMOVE1_AVOIDZ;
16285 
16286 				if(other!=ent) self->xdir = self->zdir = 0;
16287 
16288 				self->stalltime = time;
16289 
16290 				if(!aimove && target){
16291 					common_try_wander(target, 1, 1);
16292 					ent = target;
16293 				} else if (target){
16294 					ent = target;
16295 					pxc = pzc = 0;
16296 
16297 					if(aimove&AIMOVE1_WANDER) {
16298 						patx[pxc] = AIMOVE1_WANDER;
16299 						pxc++;
16300 						patz[pzc] = AIMOVE1_WANDER;
16301 						pzc++;
16302 					}
16303 					if(aimove&AIMOVE1_CHASEX) {
16304 						patx[pxc] = AIMOVE1_CHASEX;
16305 						pxc++;
16306 					}
16307 					if(aimove&AIMOVE1_AVOIDX) {
16308 						patx[pxc] = AIMOVE1_AVOIDX;
16309 						pxc++;
16310 					}
16311 					if(aimove&AIMOVE1_CHASEZ) {
16312 						patz[pzc] = AIMOVE1_CHASEZ;
16313 						pzc++;
16314 					}
16315 					if(aimove&AIMOVE1_AVOIDZ) {
16316 						patz[pzc] = AIMOVE1_AVOIDZ;
16317 						pzc++;
16318 					}
16319 					if(!pxc) {
16320 						patx[pxc] = AIMOVE1_WANDER;
16321 						pxc++;
16322 					}
16323 					if(!pzc) {
16324 						patz[pzc] = AIMOVE1_WANDER;
16325 						pzc++;
16326 					}
16327 					px = patx[(rand32()&0xff)%pxc];
16328 					pz = patz[(rand32()&0xff)%pzc];
16329 
16330 					fx = fz = 0;
16331 
16332 					//valid types: avoidx, aviodz, chasex, chasez, wander
16333 					if(px==AIMOVE1_WANDER){
16334 						common_try_wandercompletely(1, (pz==AIMOVE1_WANDER));
16335 						fx = 1;
16336 						fz = (pz==AIMOVE1_WANDER);
16337 					}else if(px==AIMOVE1_CHASEX){
16338 						common_try_chase(target, 1, (pz==AIMOVE1_CHASEZ));
16339 						fx = 1;
16340 						fz = (pz==AIMOVE1_CHASEZ);
16341 					}else if (px==AIMOVE1_AVOIDX){
16342 						common_try_avoid(target, 1, (pz==AIMOVE1_AVOIDZ));
16343 						fx = 1;
16344 						fz = (pz==AIMOVE1_AVOIDZ);
16345 					}
16346 					if(!fz){
16347 						if(pz==AIMOVE1_WANDER)
16348 							common_try_wandercompletely(0, 1);
16349 						else if(pz==AIMOVE1_CHASEZ)
16350 							common_try_chase(target, 0, 1);
16351 						else if (pz==AIMOVE1_AVOIDZ)
16352 							common_try_avoid(target, 0, 1);
16353 					}
16354 
16355 				}else if(!common_try_follow(owner, 1, 1) && !(self->modeldata.aimove&AIMOVE2_NOTARGETIDLE) ){
16356 					common_try_wandercompletely(1, 1);
16357 					ent = NULL;
16358 				}else{
16359 					ent = owner;
16360 				}
16361 			}
16362 			//end of if
16363 			if(!self->xdir && !self->zdir){
16364 				set_idle(self);
16365 			}else{
16366 				if(self->running && !self->modeldata.runupdown) self->zdir = 0;
16367 				adjust_walk_animation(ent);
16368 			}
16369 
16370 			stall = GAME_SPEED - self->modeldata.aggression;
16371 
16372 			if(stall<GAME_SPEED) stall = GAME_SPEED/2;
16373 
16374 			self->stalltime += stall;
16375 		}
16376 
16377 		return 1;
16378 
16379 	}
16380 
16381 	return 1;
16382 }
16383 
16384 
decide_stalker()16385 void decide_stalker(){
16386 	entity* ent, *furthest = NULL;
16387 	int i;
16388 	int l = 0, r=0;
16389 	float maxz= 0.0f, z;
16390 
16391 	if(stalker && stalking) return;
16392 
16393 	firstplayer = NULL;
16394 
16395 	for(i=0; i<4; i++){
16396 		if(player[i].ent){
16397 			firstplayer = player[i].ent;
16398 			break;
16399 		}
16400 	}
16401 
16402 	if(!firstplayer) return;
16403 
16404 	for(i=0; i<ent_max; i++){
16405 		ent = ent_list[i];
16406 
16407 		if(ent->exists && !ent->dead && ent->modeldata.type == TYPE_ENEMY ){
16408 			if(ent->x>firstplayer->x) r++;
16409 			else l++;
16410 
16411 			if((z=diff(ent->z, firstplayer->z))>=maxz &&
16412 				(ent->modeldata.aimove==0 || (ent->modeldata.aimove&AIMOVE1_CHASE))){ // 2 mostly used type
16413 				maxz = z;
16414 				furthest = ent;
16415 			}
16416 		}
16417 	}
16418 
16419 	if((l>1 && !r) || (r>1 && !l)){
16420 		stalker = furthest;
16421 		//printf("** stalker decided: %s @ time %d\n", stalker->name, time);
16422 	}
16423 }
16424 
16425 
plan()16426 void plan(){
16427 	decide_stalker();
16428 }
16429 
checkstalker()16430 void checkstalker(){
16431 	float maxspeed;
16432 	int running;
16433 
16434 	if(self!=stalker) return;
16435 
16436 	if(!firstplayer) {
16437 		stalker = NULL;
16438 		return;
16439 	}
16440 
16441 	if(stalking){
16442 		if(self->stalltime<=time){
16443 			//printf("** stalk time expired: %s @ time %d\n", stalker->name, time);
16444 			stalker = NULL;
16445 		}
16446 		return;
16447 	}
16448 
16449 	running = validanim(self,ANI_RUN);
16450 
16451 	maxspeed = running?self->modeldata.runspeed:self->modeldata.speed;
16452 
16453 	self->xdir = maxspeed;
16454 	self->zdir = 0;
16455 
16456 	if(self->x>firstplayer->x) self->xdir = -self->xdir;
16457 
16458 	self->running = running;
16459 
16460 
16461 	self->stalltime = time + (diff(self->x, firstplayer->x) + 150)/maxspeed*THINK_SPEED;
16462 
16463 	adjust_walk_animation(firstplayer);
16464 
16465 	stalking = 1;
16466 	//printf("**start stalking: %s @ time %d till @%d\n", stalker->name, time, self->stalltime);
16467 }
16468 
checkplanned()16469 int checkplanned(){
16470 	return 0;
16471 }
16472 
16473 
16474 // A.I root
common_think()16475 void common_think()
16476 {
16477 
16478 	if(self->dead) return;
16479 
16480 	//if(checkplanned()) return;
16481 
16482 	// too far away , do a warp
16483 	if(self->modeldata.subtype == SUBTYPE_FOLLOW && self->parent &&
16484 		(diff(self->z, self->parent->z) > self->modeldata.animation[ANI_IDLE]->range.xmax ||
16485 		diff(self->x, self->parent->x) > self->modeldata.animation[ANI_IDLE]->range.xmax) )
16486 	{
16487 		self->takeaction = npc_warp;
16488 		return;
16489 	}
16490 
16491 	// rise? try rise attack
16492 	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))
16493 	{
16494 		common_try_riseattack();
16495 		return;
16496 	}
16497 
16498 	// Escape?
16499 	if(self->link && !self->grabbing && !self->inpain && self->takeaction!=common_prethrow && !inair(self) &&
16500 	   time >= self->stalltime && validanim(self,ANI_SPECIAL))
16501 	{
16502 		check_special();
16503 		return;
16504 	}
16505 
16506 	if(self->grabbing && !self->attacking)
16507 	{
16508 		common_grab_check();
16509 		return;
16510 	}
16511 
16512 	// Reset their escapecount if they aren't being spammed anymore.
16513 	if(self->modeldata.escapehits && !self->inpain) self->escapecount = 0;
16514 
16515 	// Enemies can now escape non-knockdown spammage (What a weird phrase)!
16516 	if((self->escapecount > self->modeldata.escapehits) && !inair(self) && validanim(self,ANI_SPECIAL2))
16517 	{
16518 		// Counter the player!
16519 		check_costmove(ANI_SPECIAL2, 0);
16520 		return;
16521 	}
16522 
16523 	if(self->link) return;
16524 
16525 	// idle, so try to attack or judge next move
16526 	// dont move if fall into a hole or off a wall
16527 	if(self->idling)
16528 	{
16529 	   if(common_attack()) return;
16530 	   common_move();
16531 	}
16532 }
16533 
16534 //////////////////////////////////////////////////////////////////////////
16535 
suicide()16536 void suicide()
16537 {
16538 	if(time < self->stalltime) return;
16539 	level_completed |= self->boss;
16540 	kill(self);
16541 }
16542 
16543 
16544 
16545 // Re-enter playfield
16546 // Used by player_fall and player_takedamage
player_die()16547 void player_die()
16548 {
16549 	int playerindex = self->playerindex;
16550 	if(!livescheat) --player[playerindex].lives;
16551 
16552 	if(firstplayer==self) firstplayer = NULL;
16553 
16554 	execute_pdie_script(playerindex);
16555 
16556 	if(nomaxrushreset[4] >= 1) nomaxrushreset[playerindex] = player[playerindex].ent->rush[1];
16557 	player[playerindex].ent = NULL;
16558 	player[playerindex].spawnhealth = self->modeldata.health;
16559 	player[playerindex].spawnmp = self->modeldata.mp;
16560 
16561 
16562 	if(self->modeldata.nodieblink != 3) kill(self);
16563 	else
16564 	{
16565 		self->think = NULL;
16566 		self->takeaction = NULL;
16567 		self->modeldata.type = TYPE_NONE;
16568 	}
16569 
16570 	if(player[playerindex].lives <= 0)
16571 	{
16572 		if(!player[0].ent && !player[1].ent && !player[2].ent && !player[3].ent)
16573 		{
16574 			timeleft = 10 * COUNTER_SPEED;
16575 			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;
16576 		}
16577 		if(self->modeldata.weaploss[0]<=3) player[playerindex].weapnum = level->setweap;
16578 		if(nomaxrushreset[4] != 2) nomaxrushreset[playerindex] = 0;
16579 		return;
16580 	}
16581 	else
16582 	{
16583 		spawnplayer(playerindex);
16584 		execute_respawn_script(playerindex);
16585 		if(!nodropen)
16586 		{
16587 			control_rumble(playerindex, 125);
16588 			drop_all_enemies();
16589 		}
16590 	}
16591 
16592 	if(!level->noreset) timeleft = level->settime * COUNTER_SPEED;    // Feb 24, 2005 - This line moved here to set custom time
16593 
16594 }
16595 
16596 
16597 
player_trymove(float xdir,float zdir)16598 int player_trymove(float xdir, float zdir)
16599 {
16600 	return common_trymove(xdir, zdir);
16601 }
16602 
check_energy(int which,int ani)16603 int check_energy(int which, int ani)
16604 {
16605 	int iCost[3];																//0 = energycost.cost (amount of HP or MP needed), 1 = Cost type (MP, HP, both), 2 = Disable flag.
16606 	int iType;																	//Entity type.
16607 
16608 	if(self->modeldata.animation[ani])											//Does animation exist?
16609 	{
16610 		iCost[2]	= self->modeldata.animation[ani]->energycost.disable;		//Get disable flag.
16611 		iType		= self->modeldata.type;										//Get entity type.
16612 
16613 		/* DC 05082010: It is now possible to individualy disable specials. In
16614 		many cases (weapons in particular) this can	help cut down the need for
16615 		superflous models when differing abilities are desired for players,
16616 
16617 		enemies, or npcs. */
16618 		if(!(iCost[2]==iType													//Disabled by type?
16619 			|| (iCost[2]==-1)													//Disabled for all?
16620 			|| (iCost[2]==-2 && (iType == TYPE_ENEMY || iType == TYPE_NPC))		//Disabled for all AI?
16621 			|| (iCost[2]==-3 && (iType == TYPE_PLAYER || iType == TYPE_NPC))	//Disabled for players & NPCs?
16622 			|| (iCost[2]==-4 && (iType == TYPE_PLAYER || iType == TYPE_ENEMY))))//Disabled for all AI?
16623 		{
16624 			iCost[0] = self->modeldata.animation[ani]->energycost.cost;			//Get energy cost amount
16625 			iCost[1] = self->modeldata.animation[ani]->energycost.mponly;		//Get energy cost type.
16626 
16627 			if(!self->seal || self->seal >= iCost[0])							//No seal or seal is less/same as energy cost?
16628 			{
16629 				if(validanim(self,ani) &&										//Validate the animation one more time.
16630 						((which &&												//Check magic validity
16631 						(iCost[1] != 2) &&										//2 = From health bar only, 0 from both
16632 						(self->mp >= iCost[0])) ||
16633 						(!which &&												//Checks health validity
16634 						(iCost[1] != 1) &&										//1 = From magic bar only, 0 from both
16635 						(self->health > iCost[0]))))
16636 				{
16637 					return 1;
16638 				}
16639 				else
16640 				{
16641 					//DC 01232009
16642 					//Tried putting the CANT animation here to keep code compacted, but won't work. I'll come back to this.
16643 					//if (validanim(self,ani)){
16644 					//    ent_set_anim(self, ANI_CANT, 0);
16645 					//    self->takeaction = common_attack_proc;
16646 					//    player[(int)self->playerindex].playkeys = 0;
16647 					//}
16648 					return 0;
16649 				}
16650 			}
16651 		}
16652 	}
16653 	return 0;
16654 }
16655 
16656 
check_special()16657 int check_special()
16658 {
16659 	if((!level->nospecial || level->nospecial == 3) &&
16660 	   !self->cantfire &&
16661 	   (check_energy(0, ANI_SPECIAL) ||
16662 		check_energy(1, ANI_SPECIAL)))
16663 	{
16664 		set_attacking(self);
16665 		memset(self->combostep, 0, sizeof(int)*5);
16666 		if(self->link){
16667 			set_idle(self->link);
16668 			self->link->takeaction = NULL;
16669 			ent_unlink(self);
16670 		}
16671 
16672 		if(self->modeldata.smartbomb && !self->modeldata.dofreeze)
16673 		{
16674 			smart_bomb(self, self->modeldata.smartbomb); // do smartbomb immediately if it doesn't freeze screen
16675 		}
16676 
16677 		self->running = 0;    // If special is executed while running, ceases to run
16678 		self->xdir = self->zdir = 0;
16679 		ent_set_anim(self, ANI_SPECIAL, 0);
16680 		self->takeaction = common_attack_proc;
16681 
16682 		if(self->modeldata.dofreeze) smartbomber = self;    // Freezes the animations of all enemies/players while special is executed
16683 
16684 		if(!nocost && !healthcheat)
16685 		{
16686 			if(check_energy(1, ANI_SPECIAL)) self->mp -= self->modeldata.animation[ANI_SPECIAL]->energycost.cost;
16687 			else self->health -= self->modeldata.animation[ANI_SPECIAL]->energycost.cost;
16688 		}
16689 
16690 		return 1;
16691 	}
16692 	return 0;
16693 }
16694 
16695 
16696 // Check keys for special move. Used several times, so I func'd it.
16697 // 1-10-05 changed self->health>6 to self->health > self->modeldata.animation[ANI_SPECIAL]->energycost.cost
player_check_special()16698 int player_check_special()
16699 {
16700 	u32 thekey = 0;
16701 
16702 	if((!ajspecial || (ajspecial && !validanim(self,ANI_BLOCK))) &&
16703 		(player[(int)self->playerindex].playkeys & FLAG_SPECIAL))
16704 	{
16705 		thekey = FLAG_SPECIAL;
16706 	}
16707 	else if(ajspecial && ((player[(int)self->playerindex].playkeys & FLAG_JUMP) &&
16708 		(player[(int)self->playerindex].keys & FLAG_ATTACK)))
16709 	{
16710 		thekey = FLAG_JUMP;
16711 	}
16712 	else return 0;
16713 
16714 	if(check_special())
16715 	{
16716 		self->stalltime = 0;
16717 		player[(int)self->playerindex].playkeys -= thekey;
16718 		return 1;
16719 	}else{
16720 		return 0;
16721 	}
16722 }
16723 
16724 
common_land()16725 void common_land()
16726 {
16727 	self->xdir = self->zdir = 0;
16728 	if(self->animating) return;
16729 
16730 	set_idle(self);
16731 	self->takeaction = NULL;
16732 }
16733 
16734 
16735 //animal run when you lost it 3 times by tails
runanimal()16736 void runanimal()
16737 {
16738 	common_walk_anim(self);
16739 	//ent_set_anim(self, ANI_WALK, 0);
16740 
16741 	if(self->x < advancex - 80 || self->x > advancex + (videomodes.hRes+80)){
16742 		kill(self);
16743 		return;
16744 	}
16745 
16746 	if(self->direction) self->x += self->modeldata.speed;
16747 	else self->x -= self->modeldata.speed;
16748 }
16749 
16750 
player_blink()16751 void player_blink()
16752 {
16753 	self->blink = 1;
16754 	if(time >= self->stalltime) player_die();
16755 }
16756 
16757 
common_grabattack()16758 void common_grabattack()
16759 {
16760 	if(self->animating) return;
16761 
16762 	self->attacking = 0;
16763 
16764 	if(!(self->combostep[0] || self->combostep[1] ||
16765 		 self->combostep[2] || self->combostep[3] ||
16766 		 self->combostep[4]))
16767 	{
16768 		ent_unlink(self);
16769 	}
16770 
16771 	if(self->link)
16772 	{
16773 		self->attacking = 0;
16774 		ent_set_anim(self, ANI_GRAB, 0);
16775 		set_pain(self->link, -1, 0);
16776 		update_frame(self, self->animation->numframes-1);
16777 		update_frame(self->link, self->link->animation->numframes-1);
16778 		self->takeaction = common_grab;
16779 		self->link->takeaction = common_grabbed;
16780 	}
16781 	else
16782 	{
16783 		memset(self->combostep, 0, sizeof(int)*5);
16784 		set_idle(self);
16785 		self->takeaction = NULL;
16786 	}
16787 }
16788 
16789 // The vault.
common_vault()16790 void common_vault()
16791 {
16792 	if(!self->link)
16793 	{
16794 		set_idle(self);
16795 		self->takeaction = NULL;
16796 		return;
16797 	}
16798 	if(!self->animating)
16799 	{
16800 		self->attacking = 0;
16801 		self->direction = !self->direction;
16802 		self->a = self->base = self->link->base;
16803 
16804 		if(self->direction) self->x = self->link->x - self->modeldata.grabdistance;
16805 		else self->x = self->link->x + self->modeldata.grabdistance;
16806 
16807 		ent_set_anim(self, ANI_GRAB, 0);
16808 		set_pain(self->link, -1, 0);
16809 		update_frame(self, self->animation->numframes-1);
16810 		update_frame(self->link, self->link->animation->numframes-1);
16811 		self->takeaction = common_grab;
16812 		self->link->takeaction = common_grabbed;
16813 		return;
16814 	}
16815 }
16816 
16817 
common_prejump()16818 void common_prejump()
16819 {
16820 	if(self->animating) return;
16821 	dojump(self->jumpv, self->jumpx, self->jumpz, self->jumpid);
16822 }
16823 
tryjump(float jumpv,float jumpx,float jumpz,int jumpid)16824 void tryjump(float jumpv, float jumpx, float jumpz, int jumpid)
16825 {
16826 	self->jumpv = jumpv;              self->jumpx = jumpx;
16827 	self->jumpz = jumpz;              self->jumpid = jumpid;
16828 	if(validanim(self,ANI_JUMPDELAY))
16829 	{
16830 		ent_set_anim(self, ANI_JUMPDELAY, 0);
16831 		self->xdir = self->zdir = 0;
16832 
16833 		self->idling = 0;
16834 		self->takeaction = common_prejump;
16835 	}
16836 	else
16837 	{
16838 		dojump(jumpv, jumpx, jumpz, jumpid);
16839 	}
16840 }
16841 
16842 
dojump(float jumpv,float jumpx,float jumpz,int jumpid)16843 void dojump(float jumpv, float jumpx, float jumpz, int jumpid)
16844 {
16845 	entity* dust;
16846 
16847 	if(SAMPLE_JUMP >= 0) sound_play_sample(SAMPLE_JUMP, 0, savedata.effectvol,savedata.effectvol, 100);
16848 
16849 	//Spawn jumpstart dust.
16850 	if(self->modeldata.dust[2]>=0)
16851 	{
16852 		dust = spawn(self->x, self->z, self->a, self->direction, NULL, self->modeldata.dust[2], NULL);
16853 		if(dust){
16854 			dust->base = self->a;
16855 			dust->autokill = 1;
16856 			execute_onspawn_script(dust);
16857 		}
16858 	}
16859 
16860 	set_jumping(self);
16861 	ent_set_anim(self, jumpid, 0);
16862 
16863 	toss(self, jumpv);
16864 
16865 	if(self->direction == 0)
16866 		self->xdir = -jumpx;
16867 	else self->xdir = jumpx;
16868 
16869 	self->zdir = jumpz;
16870 
16871 	self->takeaction = common_jump;
16872 }
16873 
16874 // make a function so enemies can use
check_costmove(int s,int fs)16875 int check_costmove(int s, int fs)
16876 {
16877 	if(((fs == 1 && level->nospecial < 2) || (fs == 0 && level->nospecial == 0) || (fs == 0 && level->nospecial == 3)) &&
16878 	   (check_energy(0, s) ||
16879 		check_energy(1, s))  )
16880 	{
16881 		if(!nocost && !healthcheat)
16882 		{
16883 			if(check_energy(1, s)) self->mp -= self->modeldata.animation[s]->energycost.cost;
16884 			else self->health -= self->modeldata.animation[s]->energycost.cost;
16885 		}
16886 
16887 		self->xdir = self->zdir = 0;
16888 		set_attacking(self);
16889 		self->inpain = 0;
16890 		memset(self->combostep, 0, sizeof(int)*5);
16891 		ent_unlink(self);
16892 		self->movestep = 0;
16893 		ent_set_anim(self, s, 0);
16894 		self->takeaction = common_attack_proc;
16895 		return 1;
16896 	}
16897 	return 0;
16898 }
16899 
16900 
16901 // Function to check custom combos. If movestep is 0, means ready to check to see if the second step in the combo is
16902 // valid. If so, returns 1, setting each valid combo in the list so far to 1, otherwise 0. If movestep is > 0, means
16903 // ready to check the action button step of the combo. Loops through the "valid combo" list and sees if the action
16904 // button step is valid, returning 1 if true, otherwise 0.
check_combo(int m)16905 int check_combo(int m){    // New function to check combos to make sure they are valid
16906 	int i;
16907 	int found = 0;    // Default not found unless overridden by finding a valid combo
16908 	int value = self->animation->cancel; // OX. If cancel is enabled , we will be checking MAX_SPECIAL_INPUTS-4, -5, -6 instead.
16909 
16910 	// check one-step freespecial
16911 	for(i = 0; i < self->modeldata.specials_loaded; i++)
16912 	{
16913 		if(self->modeldata.special[i][MAX_SPECIAL_INPUTS-3]==1 && self->modeldata.special[i][0]==m && value == 0)
16914 		{
16915 			if(check_costmove(self->modeldata.special[i][MAX_SPECIAL_INPUTS-(2+value)], 1))
16916 			{
16917 				self->modeldata.valid_special = i;
16918 				return 1;    // Valid combo found, go ahead and return
16919 			}
16920 			else return 0;    // Found, but cost more health than the player had
16921 		}
16922 		else if(self->modeldata.special[i][MAX_SPECIAL_INPUTS-6]==1 && self->modeldata.special[i][0]==m &&
16923 			self->modeldata.special[i][MAX_SPECIAL_INPUTS-10] <= self->animation->animhits &&
16924 				self->modeldata.special[i][MAX_SPECIAL_INPUTS-7] <= self->animpos &&
16925 				self->modeldata.special[i][MAX_SPECIAL_INPUTS-8] >= self->animpos &&
16926 				self->modeldata.special[i][MAX_SPECIAL_INPUTS-9] == self->animnum)
16927 		{
16928 			if(check_costmove(self->modeldata.special[i][MAX_SPECIAL_INPUTS-5], 1))
16929 			{
16930 				self->modeldata.valid_special = i;
16931 				return 1;    // Valid combo found, go ahead and return
16932 			}
16933 			else return 0;    // Found, but cost more health than the player had
16934 		}
16935 	}// end of for
16936 
16937 	if(time > self->movetime) return 0;    // Too much time passed so return 0
16938 
16939 	if(m == FLAG_FORWARD || m==FLAG_BACKWARD || m==FLAG_MOVEUP || m==FLAG_MOVEDOWN){   // direction keys
16940 		for(i = 0; i < self->modeldata.specials_loaded; i++)
16941 		{
16942 			if( self->modeldata.special[i][MAX_SPECIAL_INPUTS-(3+value)]>self->movestep &&
16943 				self->modeldata.special[i][(int)self->movestep] == self->lastmove &&
16944 				self->modeldata.special[i][(int)self->movestep+1] == m )
16945 			{
16946 
16947 				self->modeldata.special[i][MAX_SPECIAL_INPUTS-(1+value)] = 1;    // Marks all valid directional combos with a 1
16948 				found = 1;    // There is at least 1 valid combo, so return found
16949 			}
16950 			else self->modeldata.special[i][MAX_SPECIAL_INPUTS-(1+value)] = 0;    // Marks all invalid directional combos with a 0
16951 		}//end of for
16952 
16953 		return found;    // Returns 1 if found, otherwise returns 0
16954 	}
16955 	else// action buttons
16956 	{
16957 		for(i = 0; i < self->modeldata.specials_loaded; i++)
16958 		{
16959 			if(self->modeldata.special[i][MAX_SPECIAL_INPUTS-1] && self->modeldata.special[i][self->movestep+1] == m && value == 0)
16960 			{    // Checks only valid directional combos to see if the action button matches
16961 				if(check_costmove(self->modeldata.special[i][MAX_SPECIAL_INPUTS-2], 1))
16962 				{
16963 					self->modeldata.valid_special = i;    // Says which one is valid and returns that it was found
16964 					return 1;    // Valid combo found, go ahead and return
16965 				}
16966 				else return 0;    // Found, but cost more health than the player had
16967 			}
16968 			else if(self->modeldata.special[i][MAX_SPECIAL_INPUTS-4] && self->modeldata.special[i][self->movestep+1] == m  &&
16969 				self->modeldata.special[i][MAX_SPECIAL_INPUTS-10] <= self->animation->animhits &&
16970 				self->modeldata.special[i][MAX_SPECIAL_INPUTS-7] <= self->animpos &&
16971 				self->modeldata.special[i][MAX_SPECIAL_INPUTS-8] >= self->animpos &&
16972 				self->modeldata.special[i][MAX_SPECIAL_INPUTS-9] == self->animnum)
16973 			{    // Checks only valid directional combos to see if the action button matches
16974 				if(check_costmove(self->modeldata.special[i][MAX_SPECIAL_INPUTS-5], 1))
16975 				{
16976 					self->modeldata.valid_special = i;    // Says which one is valid and returns that it was found
16977 					return 1;    // Valid combo found, go ahead and return
16978 				}
16979 				else return 0;    // Found, but cost more health than the player had
16980 			}
16981 		}// end of for
16982 
16983 		return 0;    // No valid combos found, return 0
16984 	}
16985 }
16986 
16987 
16988 // Function that causes the player to continue to move up or down until the animation has finished playing
common_dodge()16989 void common_dodge()    // New function so players can dodge with up up or down down
16990 {
16991 	if(self->animating)    // Continues to move as long as the player is animating
16992 	{
16993 		if(self->zdir<0) self->zdir = -self->modeldata.speed * 1.75;
16994 		else self->zdir = self->modeldata.speed * 1.75;
16995 		self->xdir = 0;
16996 	}
16997 	else    // Once done animating, returns to thinking
16998 	{
16999 		self->xdir = self->zdir = 0;
17000 		set_idle(self);
17001 		self->takeaction = NULL;
17002 	}
17003 }
17004 
17005 
17006 
17007 // Function created to combine the action taken if either picking up an item, or running into an item that is a
17008 // SUBTYPE_TOUCH, executing the appropriate action based on which type of item is picked up
didfind_item(entity * other)17009 void didfind_item(entity *other)
17010 {    // Function that takes care of items when picked up
17011 	set_opponent(self, other);
17012 
17013 	//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
17014 	if(other->modeldata.reload)
17015 	{
17016 		if(self->weapent && self->weapent->modeldata.typeshot)
17017 		{
17018 			self->weapent->modeldata.shootnum += other->modeldata.reload;
17019 			if(self->weapent->modeldata.shootnum > self->weapent->modeldata.shootnum) self->weapent->modeldata.shootnum = self->weapent->modeldata.shootnum;
17020 			if(SAMPLE_GET >= 0) sound_play_sample(SAMPLE_GET, 0, savedata.effectvol,savedata.effectvol, 100);
17021 		}
17022 		else
17023 		{
17024 			addscore(self->playerindex, other->modeldata.score);
17025 			if(SAMPLE_GET2 >= 0) sound_play_sample(SAMPLE_GET2, 0, savedata.effectvol,savedata.effectvol, 100);
17026 		}
17027 	}
17028 	//end of weapons items section
17029 	else if(other->modeldata.score)
17030 	{
17031 		addscore(self->playerindex, other->modeldata.score);
17032 
17033 		if(SAMPLE_GET2 >= 0) sound_play_sample(SAMPLE_GET2, 0, savedata.effectvol,savedata.effectvol, 100);
17034 	}
17035 	else if(other->health)
17036 	{
17037 		self->health += other->health;
17038 
17039 		if(self->health > self->modeldata.health) self->health = self->modeldata.health;
17040 
17041 		other->health = 0;
17042 
17043 		if(SAMPLE_GET >= 0) sound_play_sample(SAMPLE_GET, 0, savedata.effectvol,savedata.effectvol, 100);
17044 	}
17045 	else if(other->modeldata.mp)
17046 	{
17047 		self->mp += other->modeldata.mp;
17048 
17049 		if(self->mp > self->modeldata.mp) self->mp = self->modeldata.mp;
17050 
17051 		other->mp = 0;
17052 		sound_play_sample(SAMPLE_GET, 0, savedata.effectvol,savedata.effectvol, 100);
17053 	}
17054 	else if(stricmp(other->modeldata.name, "Time")==0)
17055 	{
17056 		timeleft = level->settime * COUNTER_SPEED;    // Feb 24, 2005 - This line moved here to set custom time
17057 
17058 		if(SAMPLE_GET2 >= 0) sound_play_sample(SAMPLE_GET2, 0, savedata.effectvol,savedata.effectvol, 100);
17059 	}
17060 	else if(other->modeldata.makeinv)
17061 	{    // Mar 2, 2005 - New item makes player invincible
17062 		self->invincible = 1;
17063 		self->invinctime = time + ABS(other->modeldata.makeinv);
17064 		self->blink = (other->modeldata.makeinv>0);
17065 
17066 		if(SAMPLE_GET2 >= 0) sound_play_sample(SAMPLE_GET2, 0, savedata.effectvol,savedata.effectvol, 100);
17067 	}
17068 	else if(other->modeldata.smartbomb)
17069 	{    // Damages everything on the screen
17070 		smart_bomb(self, other->modeldata.smartbomb);
17071 
17072 		if(SAMPLE_GET2 >= 0) sound_play_sample(SAMPLE_GET2, 0, savedata.effectvol,savedata.effectvol, 100);
17073 	}
17074 	else if(other->modeldata.subtype == SUBTYPE_WEAPON)
17075 	{
17076 		dropweapon(0);
17077 		self->weapent = other;
17078 		set_weapon(self, other->modeldata.weapnum, 0);
17079 
17080 		if(self->modeldata.animal)  // UTunnels: well, ride, not get. :)
17081 		{
17082 			self->direction = other->direction;
17083 			self->x = other->x;
17084 			self->z = other->z;
17085 		}
17086 
17087 		if(!other->modeldata.typeshot && self->modeldata.typeshot) other->modeldata.typeshot = 1;
17088 
17089 		if(SAMPLE_GET >= 0) sound_play_sample(SAMPLE_GET, 0, savedata.effectvol,savedata.effectvol, 100);
17090 	}
17091 	else if(other->modeldata.subtype == SUBTYPE_PROJECTILE)
17092 	{
17093 		dropweapon(0);
17094 		self->weapent = other;
17095 
17096 		if(SAMPLE_GET >= 0) sound_play_sample(SAMPLE_GET, 0, savedata.effectvol,savedata.effectvol, 100);
17097 	}
17098 	else if(other->modeldata.credit)
17099 	{
17100 		if(!noshare) credits++;
17101 		else player[(int)self->playerindex].credits++;
17102 
17103 		if(SAMPLE_1UP >= 0) sound_play_sample(SAMPLE_1UP, 0, savedata.effectvol,savedata.effectvol, 100);
17104 	}
17105 	else
17106 	{
17107 		// Must be a 1up then.
17108 		player[(int)self->playerindex].lives++;
17109 
17110 		if(SAMPLE_1UP >= 0) sound_play_sample(SAMPLE_1UP, 0, savedata.effectvol,savedata.effectvol, 100);
17111 	}
17112 
17113 	if(other->modeldata.subtype != SUBTYPE_WEAPON && other->modeldata.subtype != SUBTYPE_PROJECTILE)
17114 	{
17115 		other->takeaction = suicide;
17116 		if(!other->modeldata.instantitemdeath)
17117 			 other->nextthink = time + GAME_SPEED * 3;
17118 	}
17119 	other->z = 100000;
17120 }
17121 
player_fall_check()17122 void player_fall_check()
17123 {
17124 	if(autoland != 2 && (player[(int)self->playerindex].keys & (FLAG_MOVEUP|FLAG_JUMP)) == (FLAG_MOVEUP|FLAG_JUMP))
17125 	{
17126 		player[(int)self->playerindex].playkeys ^= (FLAG_MOVEUP|FLAG_JUMP);
17127 		self->damage_on_landing=-2; // mark it, so we will play land animation when hit the ground
17128 	}
17129 }
17130 
player_grab_check()17131 void player_grab_check()
17132 {
17133 	entity * other = self->link;
17134 
17135 	if(other == NULL || (self->modeldata.grabfinish && self->animating && !self->grabwalking)) return;
17136 
17137 	if(self->base != other->base)
17138 	{       // Change this from ->a to ->base
17139 		ent_unlink(self);
17140 		set_idle(self);
17141 		self->takeaction = NULL;
17142 		return;
17143 	}
17144 	  // OX cancel checking.
17145 	if(self->animation->cancel==3)
17146 	{
17147 		if((player[(int)self->playerindex].playkeys & FLAG_ATTACK) && check_combo(FLAG_ATTACK))
17148 		{
17149 			player[(int)self->playerindex].playkeys -= FLAG_ATTACK;
17150 			ent_unlink(self);
17151 			self->attacking = 1;
17152 			self->takeaction = common_attack_proc;
17153 			return;
17154 		}
17155 		if((player[(int)self->playerindex].playkeys & FLAG_ATTACK2) && check_combo(FLAG_ATTACK2))
17156 		{
17157 			player[(int)self->playerindex].playkeys -= FLAG_ATTACK2;
17158 			ent_unlink(self);
17159 			self->attacking = 1;
17160 			self->takeaction = common_attack_proc;
17161 			return;
17162 		}
17163 		if((player[(int)self->playerindex].playkeys & FLAG_ATTACK3) && check_combo(FLAG_ATTACK3))
17164 		{
17165 			player[(int)self->playerindex].playkeys -= FLAG_ATTACK3;
17166 			ent_unlink(self);
17167 			self->attacking = 1;
17168 			self->takeaction = common_attack_proc;
17169 			return;
17170 		}
17171 		if((player[(int)self->playerindex].playkeys & FLAG_ATTACK4) && check_combo(FLAG_ATTACK4))
17172 		{
17173 			player[(int)self->playerindex].playkeys -= FLAG_ATTACK4;
17174 			ent_unlink(self);
17175 			self->attacking = 1;
17176 			self->takeaction = common_attack_proc;
17177 			return;
17178 		}
17179 		if((player[(int)self->playerindex].playkeys & FLAG_JUMP) && check_combo(FLAG_JUMP))
17180 		{
17181 			player[(int)self->playerindex].playkeys -= FLAG_JUMP;
17182 			ent_unlink(self);
17183 			self->attacking = 1;
17184 			self->takeaction = common_attack_proc;
17185 			return;
17186 		}
17187 		if((player[(int)self->playerindex].playkeys & FLAG_SPECIAL) && check_combo(FLAG_SPECIAL))
17188 		{
17189 			player[(int)self->playerindex].playkeys -= FLAG_SPECIAL;
17190 			ent_unlink(self);
17191 			self->attacking = 1;
17192 			self->takeaction = common_attack_proc;
17193 			return;
17194 		}
17195 	}
17196 	// End cancel checking
17197 
17198 	if(player_check_special()) return;
17199 
17200 	if(!nolost && self->modeldata.weaploss[0] <= 0) dropweapon(1);
17201 
17202 	// grabturn code
17203 	if(self->animation == self->modeldata.animation[ANI_GRABTURN])
17204 	{
17205 		// still turning? don't bother with anything else
17206 		if(self->animating) return;
17207 
17208 		// done turning? switch directions and return to grab animation
17209 		else
17210 		{
17211 			if(self->direction)
17212 			{
17213 				self->direction = 0;
17214 				other->direction = 1;
17215 			}
17216 			else
17217 			{
17218 				self->direction = 1;
17219 				other->direction = 0;
17220 			}
17221 			ent_set_anim(self, ANI_GRAB, 0);
17222 			set_pain(other, -1, 0);
17223 			update_frame(self, self->animation->numframes-1);
17224 			update_frame(other, other->animation->numframes-1);
17225 			other->x = self->x + (((self->direction * 2) - 1) * self->modeldata.grabdistance);
17226 		}
17227 	}
17228 
17229 	self->attacking = 0; //for checking
17230 	self->grabwalking = 0;
17231 	if(self->direction ?
17232 		(player[(int)self->playerindex].keys & FLAG_MOVELEFT) :
17233 		(player[(int)self->playerindex].keys & FLAG_MOVERIGHT))
17234 	{
17235 		// initiating grabturn
17236 		if(self->modeldata.grabturn)
17237 		{
17238 				// start animation if it exists...
17239 				if(validanim(self,ANI_GRABTURN))
17240 				{
17241 					ent_set_anim(self, ANI_GRABTURN, 0);
17242 					if(validanim(other,ANI_GRABBEDTURN)) ent_set_anim(other, ANI_GRABBEDTURN, 0);
17243 					else if(validanim(other,ANI_GRABBED)) ent_set_anim(other, ANI_GRABBED, 0);
17244 					else ent_set_anim(other, ANI_PAIN, 0);
17245 					other->xdir = other->zdir = self->xdir = self->zdir = 0;
17246 					other->x = self->x;
17247 					return;
17248 				}
17249 
17250 				// otherwise, just turn around
17251 				else
17252 				{
17253 					if(self->direction)
17254 					{
17255 						self->direction = 0;
17256 						other->direction = 1;
17257 					}
17258 					else
17259 					{
17260 						self->direction = 1;
17261 						other->direction = 0;
17262 					}
17263 					ent_set_anim(self, ANI_GRAB, 0);
17264 					set_pain(other, -1, 0);
17265 					update_frame(self, self->animation->numframes-1);
17266 					update_frame(other, other->animation->numframes-1);
17267 					other->x = self->x + (((self->direction * 2) - 1) * self->modeldata.grabdistance);
17268 				}
17269 		}
17270 		else if(!validanim(self,ANI_GRABWALK) && time > self->releasetime)
17271 		{
17272 			// Release
17273 			ent_unlink(self);
17274 			set_idle(self);
17275 			self->takeaction = NULL;
17276 			return;
17277 		}
17278 	}
17279 	else self->releasetime = time + (GAME_SPEED/2);
17280 
17281 	if((player[(int)self->playerindex].playkeys & FLAG_ATTACK) &&
17282 		(self->direction ?
17283 		 (player[(int)self->playerindex].keys & FLAG_MOVELEFT) :
17284 		 (player[(int)self->playerindex].keys & FLAG_MOVERIGHT)))
17285 	{
17286 		player[(int)self->playerindex].playkeys -= FLAG_ATTACK;
17287 		if(validanim(self,ANI_GRABBACKWARD))
17288 			 dograbattack(4);
17289 		else if(validanim(self,ANI_THROW))
17290 		{
17291 			 if(self->modeldata.throwframewait >= 0)
17292 				  doprethrow();
17293 			 else
17294 				  dothrow();
17295 		}
17296 		else
17297 			 dograbattack(0);
17298 	}
17299 	// grab forward
17300 	else if((player[(int)self->playerindex].playkeys & FLAG_ATTACK) &&
17301 		validanim(self,ANI_GRABFORWARD) &&
17302 		(!self->direction ?
17303 		 (player[(int)self->playerindex].keys & FLAG_MOVELEFT) :
17304 		 (player[(int)self->playerindex].keys & FLAG_MOVERIGHT)))
17305 	{
17306 		player[(int)self->playerindex].playkeys -= FLAG_ATTACK;
17307 		dograbattack(1);
17308 	}
17309 	// grab up
17310 	else if((player[(int)self->playerindex].playkeys & FLAG_ATTACK) &&
17311 		validanim(self, ANI_GRABUP) && (player[(int)self->playerindex].keys & FLAG_MOVEUP))
17312 	{
17313 		player[(int)self->playerindex].playkeys -= FLAG_ATTACK;
17314 		dograbattack(2);
17315 	}
17316 	// grab down
17317 	else if((player[(int)self->playerindex].playkeys & FLAG_ATTACK) &&
17318 		validanim(self,ANI_GRABDOWN) && (player[(int)self->playerindex].keys & FLAG_MOVEDOWN))
17319 	{
17320 		player[(int)self->playerindex].playkeys -= FLAG_ATTACK;
17321 		dograbattack(3);
17322 	}
17323 	// normal grab attack
17324 	else if((player[(int)self->playerindex].playkeys & FLAG_ATTACK) && validanim(self,ANI_GRABATTACK))
17325 	{
17326 		player[(int)self->playerindex].playkeys -= FLAG_ATTACK;
17327 		dograbattack(0);
17328 	}
17329 	// Vaulting.
17330 	else if((player[(int)self->playerindex].playkeys & FLAG_JUMP) && validanim(self,ANI_VAULT))
17331 	{
17332 		player[(int)self->playerindex].playkeys -= FLAG_JUMP;
17333 		dovault();
17334 	}
17335 	// grab attack finisher
17336 	else if(player[(int)self->playerindex].playkeys & (FLAG_JUMP|FLAG_ATTACK))
17337 	{
17338 		player[(int)self->playerindex].playkeys -= player[(int)self->playerindex].playkeys&(FLAG_JUMP|FLAG_ATTACK);
17339 
17340 		// Perform final blow
17341 		if(validanim(self,ANI_GRABATTACK2) || validanim(self,ANI_ATTACK3))
17342 			dograbattack(-1);
17343 		else
17344 		{
17345 			self->attacking = 1;
17346 			memset(self->combostep, 0, sizeof(int)*5);
17347 			self->takeaction = common_grabattack;
17348 			tryjump(self->modeldata.jumpheight, self->modeldata.jumpspeed, 0, ANI_JUMP);
17349 		}
17350 	}
17351 
17352 	// grab walk code
17353 	else if(validanim(self,ANI_GRABWALK)  // check if grabwalk animation exists
17354 
17355 		 // if entity is still animating anything besides a grabwalk variant, don't let them move
17356 		 && (!self->animating || self->animation == self->modeldata.animation[ANI_GRABWALK]
17357 		 || self->animation == self->modeldata.animation[ANI_GRABWALKUP]
17358 		 || self->animation == self->modeldata.animation[ANI_GRABWALKDOWN]
17359 		 || self->animation == self->modeldata.animation[ANI_GRABBACKWALK])){
17360 
17361 		 // z axis movement
17362 		if(PLAYER_MIN_Z != PLAYER_MAX_Z)
17363 		{
17364 			if(player[(int)self->playerindex].keys & FLAG_MOVEUP)
17365 			{
17366 				if(self->modeldata.grabwalkspeed) self->zdir = -self->modeldata.grabwalkspeed/2;
17367 				else self->zdir = -self->modeldata.speed/2;
17368 			}
17369 			else if(player[(int)self->playerindex].keys & FLAG_MOVEDOWN)
17370 			{
17371 				if(self->modeldata.grabwalkspeed) self->zdir = self->modeldata.grabwalkspeed/2;
17372 				else self->zdir = self->modeldata.speed/2;
17373 			}
17374 			else if(!(player[(int)self->playerindex].keys & (FLAG_MOVEUP|FLAG_MOVEDOWN)))
17375 				self->zdir = 0;
17376 		}
17377 
17378 		// x axis movement
17379 		if(player[(int)self->playerindex].keys & FLAG_MOVELEFT)
17380 		{
17381 			if(self->modeldata.grabwalkspeed) self->xdir = -self->modeldata.grabwalkspeed;
17382 			else self->xdir = -self->modeldata.speed;
17383 		}
17384 
17385 		else if(player[(int)self->playerindex].keys & FLAG_MOVERIGHT)
17386 		{
17387 			if(self->modeldata.grabwalkspeed) self->xdir = self->modeldata.grabwalkspeed;
17388 			else self->xdir = self->modeldata.speed;
17389 		}
17390 		else if(!((player[(int)self->playerindex].keys & FLAG_MOVELEFT) || (player[(int)self->playerindex].keys & FLAG_MOVERIGHT)) )
17391 			self->xdir = 0;
17392 
17393 		// setting the animations based on the velocity set above
17394 		if(self->xdir || self->zdir){
17395 			if(((self->xdir > 0 && !self->direction) || (self->xdir < 0 && self->direction)) && validanim(self,ANI_GRABBACKWALK))
17396 				ent_set_anim(self, ANI_GRABBACKWALK, 0);
17397 			else if(self->zdir < 0 && validanim(self,ANI_GRABWALKUP)) ent_set_anim(self, ANI_GRABWALKUP, 0);
17398 			else if(self->zdir > 0 && validanim(self,ANI_GRABWALKDOWN)) ent_set_anim(self, ANI_GRABWALKDOWN, 0);
17399 			else ent_set_anim(self, ANI_GRABWALK, 0);
17400 			if(self->animation == self->modeldata.animation[ANI_GRABWALKUP] && validanim(other,ANI_GRABBEDWALKUP))
17401 				ent_set_anim(other, ANI_GRABBEDWALKUP, 0);
17402 			else if(self->animation == self->modeldata.animation[ANI_GRABWALKDOWN] && validanim(other,ANI_GRABBEDWALKDOWN))
17403 				ent_set_anim(other, ANI_GRABBEDWALKDOWN, 0);
17404 			else if(self->animation == self->modeldata.animation[ANI_GRABBACKWALK] && validanim(other,ANI_GRABBEDBACKWALK))
17405 				ent_set_anim(other, ANI_GRABBEDBACKWALK, 0);
17406 			else if(validanim(other,ANI_GRABBEDWALK)) ent_set_anim(other, ANI_GRABBEDWALK, 0);
17407 			else if (validanim(other,ANI_GRABBED)) ent_set_anim(other, ANI_GRABBED, 0);
17408 			else ent_set_anim(other, ANI_PAIN, 0);
17409 		}
17410 		else{
17411 			ent_set_anim(self, ANI_GRAB, 0);
17412 			if (validanim(other,ANI_GRABBED)) ent_set_anim(other, ANI_GRABBED, 0);
17413 			else ent_set_anim(other, ANI_PAIN, 0);
17414 		}
17415 		// use check_link_move to set velocity, don't change it here
17416 		other->zdir = other->xdir = 0;
17417 		self->grabwalking = 1;
17418 	}
17419 		 player_preinput();
17420 
17421 	if(self->attacking)  self->releasetime = time + (GAME_SPEED/2); // reset releasetime when do attacks
17422 }
17423 
17424 
player_jump_check()17425 void player_jump_check()
17426 {
17427 	int candospecial = 0;
17428 	if(!noaircancel || !self->animating || self->animnum == self->jumpid)
17429 	{
17430 		//air special, copied and changed from Fugue's code
17431 		if((!level->nospecial || level->nospecial == 3) && player[(int)self->playerindex].playkeys & FLAG_SPECIAL){
17432 
17433 			if(validanim(self,ANI_JUMPSPECIAL))
17434 			{
17435 				if(check_energy(1, ANI_JUMPSPECIAL))
17436 				{
17437 					if(!healthcheat) self->mp -= self->modeldata.animation[ANI_JUMPSPECIAL]->energycost.cost;
17438 					candospecial = 1;
17439 				}
17440 				else if(check_energy(0, ANI_JUMPSPECIAL))
17441 				{
17442 					if(!healthcheat) self->health -= self->modeldata.animation[ANI_JUMPSPECIAL]->energycost.cost;
17443 					candospecial = 1;
17444 				}
17445 				else if(validanim(self,ANI_JUMPCANT))
17446 				{
17447 					player[(int)self->playerindex].playkeys -= FLAG_SPECIAL;
17448 					ent_set_anim(self, ANI_JUMPCANT, 0);
17449 					self->tossv = 0;
17450 				}
17451 
17452 				if(candospecial)
17453 				{
17454 					player[(int)self->playerindex].playkeys -= FLAG_SPECIAL;
17455 					ent_set_anim(self, ANI_JUMPSPECIAL, 0);
17456 					self->attacking = 1;
17457 					self->xdir = self->zdir = 0;                         // Kill movement when the special starts
17458 					self->tossv = 0;
17459 				}
17460 			}
17461 		}//end of jumpspecial
17462 
17463 		//jumpattacks, up down forward normal....we don't check energy cost
17464 		else if(player[(int)self->playerindex].playkeys & FLAG_ATTACK){
17465 			player[(int)self->playerindex].playkeys -= FLAG_ATTACK;
17466 			self->attacking = 1;
17467 			//OX cancel checking of attack button for compatibility
17468 			if(self->animation->cancel==3 && check_combo(FLAG_ATTACK))
17469 			{
17470 				//player[(int)self->playerindex].playkeys -= FLAG_ATTACK;
17471 				self->jumping = 1;
17472 				self->takeaction = common_jump;
17473 				return;
17474 			}
17475 			// End cancel check.
17476 
17477 			else if((player[(int)self->playerindex].keys & FLAG_MOVEDOWN) && validanim(self,ANI_JUMPATTACK2)) ent_set_anim(self, ANI_JUMPATTACK2, 0);
17478 			else if((player[(int)self->playerindex].keys & FLAG_MOVEUP) && validanim(self,ANI_JUMPATTACK3)) ent_set_anim(self, ANI_JUMPATTACK3, 0);
17479 			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
17480 			else if(self->xdir != 0 && validanim(self,ANI_JUMPFORWARD)) ent_set_anim(self, ANI_JUMPFORWARD, 0);    // If moving and set, do this attack
17481 			else if(validanim(self,ANI_JUMPATTACK)) ent_set_anim(self, ANI_JUMPATTACK, 0);
17482 		}//end of jumpattack
17483 	}
17484 	if(self->modeldata.jumpmovex&1) //flip?
17485 	{
17486 	   if((player[(int)self->playerindex].keys & FLAG_MOVELEFT)) self->direction = 0;
17487 	   else if((player[(int)self->playerindex].keys & FLAG_MOVERIGHT)) self->direction = 1;
17488 	}
17489 	if(self->modeldata.jumpmovex&2) //move?
17490 	{
17491 	   if(((player[(int)self->playerindex].keys & FLAG_MOVELEFT)&&self->xdir>0) ||
17492 		  ((player[(int)self->playerindex].keys & FLAG_MOVERIGHT)&&self->xdir<0))	self->xdir = -self->xdir;
17493 	}
17494 	if(self->modeldata.jumpmovex&4) //Move x if vertical jump?
17495 	{
17496 		if(((player[(int)self->playerindex].keys & FLAG_MOVELEFT)&&self->xdir>0) ||
17497 		  ((player[(int)self->playerindex].keys & FLAG_MOVERIGHT)&&self->xdir<0))	self->xdir = -self->xdir;
17498 
17499 		if((player[(int)self->playerindex].keys & FLAG_MOVELEFT) && (!self->xdir))
17500 		{
17501 			self->xdir -= self->modeldata.speed;
17502 		}
17503 		else if((player[(int)self->playerindex].keys & FLAG_MOVERIGHT) && (!self->xdir))
17504 		{
17505 			self->xdir = self->modeldata.speed;
17506 		}
17507 	}
17508 	if(self->modeldata.jumpmovez&2) //z move?
17509 	{
17510 	   if(((player[(int)self->playerindex].keys & FLAG_MOVEUP)&&self->zdir>0) ||
17511 		  ((player[(int)self->playerindex].keys & FLAG_MOVEDOWN)&&self->zdir<0)) self->zdir = -self->zdir;
17512 	}
17513 	if(self->modeldata.jumpmovez&4) //Move z if vertical jump?
17514 	{
17515 		if((player[(int)self->playerindex].keys & FLAG_MOVELEFT)) self->direction = 0;
17516 	   else if((player[(int)self->playerindex].keys & FLAG_MOVERIGHT)) self->direction = 1;
17517 
17518 		if(((player[(int)self->playerindex].keys & FLAG_MOVEUP)&&self->zdir>0) ||
17519 		  ((player[(int)self->playerindex].keys & FLAG_MOVEDOWN)&&self->zdir<0)) self->zdir = -self->zdir;
17520 
17521 		if((player[(int)self->playerindex].keys & FLAG_MOVEUP) && (!self->zdir))
17522 		{
17523 			self->zdir -= (0.5 * self->modeldata.speed);
17524 		}
17525 		else if((player[(int)self->playerindex].keys & FLAG_MOVEDOWN) && (!self->zdir))
17526 		{
17527 			self->zdir = (0.5 * self->modeldata.speed);
17528 		}
17529 	}
17530 
17531 	//OX Rest of cancel checking
17532 
17533 	if(self->animation->cancel==3)
17534 		{
17535 			if((player[(int)self->playerindex].playkeys & FLAG_JUMP) && check_combo(FLAG_JUMP))
17536 			{
17537 				player[(int)self->playerindex].playkeys -= FLAG_JUMP;
17538 				self->jumping = 1;
17539 				self->takeaction = common_jump;
17540 				return;
17541 			}
17542 			if((player[(int)self->playerindex].playkeys & FLAG_SPECIAL) && check_combo(FLAG_SPECIAL))
17543 			{
17544 				player[(int)self->playerindex].playkeys -= FLAG_SPECIAL;
17545 				self->jumping = 1;
17546 				self->takeaction = common_jump;
17547 				return;
17548 			}
17549 			if((player[(int)self->playerindex].playkeys & FLAG_ATTACK2) && check_combo(FLAG_ATTACK2))
17550 			{
17551 				player[(int)self->playerindex].playkeys -= FLAG_ATTACK2;
17552 				//set_jumping(self);
17553 				self->jumping = 1;
17554 				self->takeaction = common_jump;
17555 				return;
17556 			}
17557 			if((player[(int)self->playerindex].playkeys & FLAG_ATTACK3) && check_combo(FLAG_ATTACK3))
17558 			{
17559 				player[(int)self->playerindex].playkeys -= FLAG_ATTACK3;
17560 				self->jumping = 1;
17561 				self->takeaction = common_jump;
17562 				return;
17563 			}
17564 			if((player[(int)self->playerindex].playkeys & FLAG_ATTACK4) && check_combo(FLAG_ATTACK4))
17565 			{
17566 				player[(int)self->playerindex].playkeys -= FLAG_ATTACK4;
17567 				self->jumping = 1;
17568 				self->takeaction = common_jump;
17569 				return;
17570 			}
17571 		}
17572 
17573 	// End cancel checking.
17574 
17575 	player_preinput();
17576 }
17577 
player_pain_check()17578 void player_pain_check()
17579 {
17580 	if(player_check_special())  self->inpain = 0;
17581 	player_preinput();
17582 }
17583 
17584 // check riseattack input up+attack
player_lie_check()17585 void player_lie_check()
17586 {
17587 	if(validanim(self,ANI_RISEATTACK) &&
17588 	   (player[(int)self->playerindex].playkeys & FLAG_ATTACK) &&
17589 	   (player[(int)self->playerindex].keys & FLAG_MOVEUP) &&
17590 	   (self->health > 0 && time > self->staydown.riseattack_stall))
17591 	{
17592 		player[(int)self->playerindex].playkeys -= FLAG_ATTACK;
17593 		if((player[(int)self->playerindex].keys & FLAG_MOVELEFT))
17594 		{
17595 			self->direction = 0;
17596 		}
17597 		if((player[(int)self->playerindex].keys & FLAG_MOVERIGHT))
17598 		{
17599 			self->direction = 1;
17600 		}
17601 		self->stalltime = 0;
17602 		set_riseattack(self, self->damagetype, 0);
17603 	}
17604 	player_preinput();
17605 }
17606 
player_charge_check()17607 void player_charge_check()
17608 {
17609 	if(!((player[(int)self->playerindex].keys&FLAG_JUMP)&&
17610 		 (player[(int)self->playerindex].keys&FLAG_SPECIAL)))
17611 	{
17612 		self->charging = 0;
17613 		set_idle(self);
17614 		self->takeaction = NULL;
17615 	}
17616 }
17617 
player_preinput()17618 void player_preinput()
17619 {
17620 	float altdiff ; // Used to check that
17621 	int notinair;   // entity is not in the air
17622 
17623 	if(player[(int)self->playerindex].playkeys & FLAG_MOVEUP)
17624 	{
17625 		player[(int)self->playerindex].playkeys -= FLAG_MOVEUP;
17626 		self->lastdir = 0;
17627 
17628 		if(check_combo(FLAG_MOVEUP)) ++self->movestep;    // Check the combo and increase movestep if valid
17629 		else self->movestep = 0;
17630 
17631 		self->lastmove = FLAG_MOVEUP;
17632 		self->movetime = time + (GAME_SPEED/4);
17633 		return ;
17634 	}
17635 	if(player[(int)self->playerindex].playkeys & FLAG_MOVEDOWN)
17636 	{
17637 		player[(int)self->playerindex].playkeys -= FLAG_MOVEDOWN;
17638 		self->lastdir = 0;
17639 
17640 		if(check_combo(FLAG_MOVEDOWN)) ++self->movestep;    // Check the combo and increase movestep if valid
17641 		else self->movestep = 0;
17642 
17643 		self->lastmove = FLAG_MOVEDOWN;
17644 		self->movetime = time + (GAME_SPEED/4);
17645 		return ;
17646 	}
17647 	if((player[(int)self->playerindex].playkeys & FLAG_MOVELEFT))
17648 	{
17649 		player[(int)self->playerindex].playkeys -= FLAG_MOVELEFT;
17650 		self->lastdir = FLAG_MOVELEFT;
17651 
17652 		if(!self->direction && check_combo(FLAG_FORWARD))  ++self->movestep;    // Check direction to distinguish forward/backward movements
17653 		else if(self->direction && check_combo(FLAG_BACKWARD))  ++self->movestep;    // Check direction to distinguish forward/backward movements
17654 		else self->movestep = 0;
17655 
17656 		if(self->direction) self->lastmove = FLAG_BACKWARD;
17657 		else self->lastmove = FLAG_FORWARD;
17658 
17659 		self->movetime = time + (GAME_SPEED/4);
17660 		return ;
17661 	}
17662 	if((player[(int)self->playerindex].playkeys & FLAG_MOVERIGHT))
17663 	{
17664 		player[(int)self->playerindex].playkeys -= FLAG_MOVERIGHT;
17665 		self->lastdir = FLAG_MOVERIGHT;
17666 
17667 		if(!self->direction && check_combo(FLAG_BACKWARD))  ++self->movestep;    // Check direction to distinguish forward/backward movements
17668 		else if(self->direction && check_combo(FLAG_FORWARD))  ++self->movestep;    // Check direction to distinguish forward/backward movements
17669 		else self->movestep = 0;
17670 
17671 		if(!self->direction) self->lastmove = FLAG_BACKWARD;
17672 		else self->lastmove = FLAG_FORWARD;
17673 
17674 		self->movetime = time + (GAME_SPEED/4);
17675 		return ;
17676 	}
17677 
17678 	// OX Cancel checking.
17679 
17680 	altdiff = diff(self->a, self->base);
17681 	notinair = (self->landed_on_platform?altdiff<5:altdiff<2);
17682 
17683 	if(self->attacking && self->animation->cancel==3 && notinair)
17684 		{
17685 			if((player[(int)self->playerindex].playkeys & FLAG_ATTACK) && check_combo(FLAG_ATTACK))
17686 			{
17687 				player[(int)self->playerindex].playkeys -= FLAG_ATTACK;
17688 				self->attacking = 1;
17689 			    self->takeaction = common_attack_proc;
17690 				return;
17691 			}
17692 			if((player[(int)self->playerindex].playkeys & FLAG_JUMP) && check_combo(FLAG_JUMP))
17693 			{
17694 				player[(int)self->playerindex].playkeys -= FLAG_JUMP;
17695 				self->attacking = 1;
17696 			    self->takeaction = common_attack_proc;
17697 				return;
17698 			}
17699 			if((player[(int)self->playerindex].playkeys & FLAG_SPECIAL) && check_combo(FLAG_SPECIAL))
17700 			{
17701 				player[(int)self->playerindex].playkeys -= FLAG_SPECIAL;
17702 				self->attacking = 1;
17703 			    self->takeaction = common_attack_proc;
17704 				return;
17705 			}
17706 			if((player[(int)self->playerindex].playkeys & FLAG_ATTACK2) && check_combo(FLAG_ATTACK2))
17707 			{
17708 				player[(int)self->playerindex].playkeys -= FLAG_ATTACK2;
17709 				self->attacking = 1;
17710 			    self->takeaction = common_attack_proc;
17711 				return;
17712 			}
17713 			if((player[(int)self->playerindex].playkeys & FLAG_ATTACK3) && check_combo(FLAG_ATTACK3))
17714 			{
17715 				player[(int)self->playerindex].playkeys -= FLAG_ATTACK3;
17716 				self->attacking = 1;
17717 			    self->takeaction = common_attack_proc;
17718 				return;
17719 			}
17720 			if((player[(int)self->playerindex].playkeys & FLAG_ATTACK4) && check_combo(FLAG_ATTACK4))
17721 			{
17722 				player[(int)self->playerindex].playkeys -= FLAG_ATTACK4;
17723 				self->attacking = 1;
17724 			    self->takeaction = common_attack_proc;
17725 				return;
17726 			}
17727 		}
17728 
17729 	// End cancel checking.
17730  }
17731 
player_think()17732 void player_think()
17733 {
17734 	int action = 0;		// 1=walking, 2=up, 3=down, 4=running
17735 	int bkwalk = 0;   //backwalk
17736 	entity *other = NULL;
17737 	float altdiff ;
17738 	float seta ;
17739 	int notinair;
17740 
17741 	if(player[(int)self->playerindex].ent != self || self->dead) return;
17742 
17743 	seta = (float)(self->animation->seta?self->animation->seta[self->animpos]:-1);
17744 	// check endlevel item
17745 	if((other = find_ent_here(self, self->x, self->z, TYPE_ENDLEVEL)) && self->a -
17746 		(seta >= 0? seta:0) == other->a)
17747 	{
17748 		if(!reached[0] && !reached[1] && !reached[2] && !reached[3]) addscore(self->playerindex, other->modeldata.score);
17749 		reached[(int)self->playerindex] = 1;
17750 
17751 		if (!other->modeldata.subtype ||(other->modeldata.subtype == SUBTYPE_BOTH &&
17752 			(reached[0]+reached[1]+reached[2]+reached[3]) >= (count_ents(TYPE_PLAYER))))
17753 		{
17754 			level_completed = 1;
17755 
17756 			if(other->modeldata.branch) strncpy( branch_name, other->modeldata.branch, MAX_NAME_LEN); //now, you can branch to another level
17757 			return;
17758 		}
17759 	}
17760 
17761 	if(time > player[(int)self->playerindex].ent->rushtime)
17762 	{
17763 		player[(int)self->playerindex].ent->rush[0] = 0;
17764 		player[(int)self->playerindex].ent->rushtime = 0;
17765 	}
17766 
17767 	if(self->charging)
17768 	{
17769 		player_charge_check();
17770 		return;
17771 	}
17772 
17773 	if(self->inpain || (self->link && !self->grabbing))
17774 	{
17775 		player_pain_check();
17776 		return;
17777 	}
17778 
17779 	// falling? check for landing
17780 	if(self->projectile == 2)
17781 	{
17782 		player_fall_check();
17783 		return;
17784 	}
17785 
17786 	// grab section, dont move if still animating
17787 	if(self->grabbing && !self->attacking && self->takeaction!=common_throw_wait)
17788 	{
17789 		player_grab_check();
17790 		return;
17791 	}
17792 
17793 	// jump section
17794 	if(self->jumping)
17795 	{
17796 		player_jump_check();
17797 		return;
17798 	}
17799 
17800 	if(self->drop && self->a==self->base && !self->tossv)
17801 	{
17802 		player_lie_check();
17803 		return;
17804 	}
17805 
17806 
17807 	// cant do anything if busy
17808 	if(!self->idling && !(self->animation->idle && self->animation->idle[self->animpos]))
17809 	{
17810 		player_preinput();
17811 		return;
17812 	}
17813 
17814 	// Check if entity is under a platform
17815 	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) )
17816 	{
17817 		ent_set_anim(self, ANI_DUCK, 1);
17818 		self->takeaction = common_stuck_underneath;
17819 		return;
17820 	}
17821 
17822 	altdiff = diff(self->a, self->base);
17823 	notinair = (self->landed_on_platform?altdiff<5:altdiff<2);
17824 
17825 	// Changed the way combos are checked so combos can be customized
17826 	if(player[(int)self->playerindex].playkeys & FLAG_MOVEUP)
17827 	{
17828 		player[(int)self->playerindex].playkeys -= FLAG_MOVEUP;
17829 		self->lastdir = 0;
17830 		if(time < self->movetime && self->lastmove==FLAG_MOVEUP && validanim(self,ANI_ATTACKUP) && notinair)
17831 		{    // New u u combo attack
17832 			set_attacking(self);
17833 			self->combostep[0] = 0;
17834 			self->xdir = self->zdir = 0;
17835 			ent_set_anim(self, ANI_ATTACKUP, 0);
17836 			self->takeaction = common_attack_proc;
17837 			return;
17838 		}
17839 		else if(time < self->movetime && self->lastmove==FLAG_MOVEUP && validanim(self,ANI_DODGE) && notinair)
17840 		{    // New dodge move like on SOR3
17841 			self->combostep[0] = 0;
17842 			self->idling = 0;
17843 			self->zdir = (float)-0.1;
17844 			ent_set_anim(self, ANI_DODGE, 0);
17845 			self->takeaction = common_dodge;
17846 			return;
17847 		}
17848 		else if(check_combo(FLAG_MOVEUP)) ++self->movestep;    // Check the combo and increase movestep if valid
17849 		else self->movestep = 0;
17850 
17851 		self->lastmove = FLAG_MOVEUP;
17852 		self->movetime = time + (GAME_SPEED/4);
17853 	}
17854 
17855 	if(player[(int)self->playerindex].playkeys & FLAG_MOVEDOWN)
17856 	{
17857 		player[(int)self->playerindex].playkeys -= FLAG_MOVEDOWN;
17858 		self->lastdir = 0;
17859 		if(self->lastmove==FLAG_MOVEDOWN && validanim(self,ANI_ATTACKDOWN) && time < self->movetime && notinair)
17860 		{    // New d d combo attack
17861 			set_attacking(self);
17862 			self->xdir = self->zdir = 0;
17863 			self->combostep[0] = 0;
17864 			ent_set_anim(self, ANI_ATTACKDOWN, 0);
17865 			self->takeaction = common_attack_proc;
17866 			return;
17867 		}
17868 		else if(time < self->movetime && self->lastmove == FLAG_MOVEDOWN && validanim(self,ANI_DODGE) && notinair)
17869 		{    // New dodge move like on SOR3
17870 			self->combostep[0] = 0;
17871 			self->idling = 0;
17872 			self->zdir = (float)0.1;          //used for checking
17873 			ent_set_anim(self, ANI_DODGE, 0);
17874 			self->takeaction = common_dodge;
17875 			return;
17876 		}
17877 		else if(check_combo(FLAG_MOVEDOWN))  ++self->movestep;    // Check the combo and increase movestep if valid
17878 		else self->movestep = 0;
17879 
17880 		self->lastmove = FLAG_MOVEDOWN;
17881 		self->movetime = time + (GAME_SPEED/4);
17882 	}
17883 
17884 	// Left/right movement for combos is more complicated because forward/backward is relative to the direction the player is facing
17885 	// Checks on current direction have to be made before and after executing the combo to make sure they get the right one
17886 	if((player[(int)self->playerindex].playkeys & FLAG_MOVELEFT))
17887 	{
17888 		player[(int)self->playerindex].playkeys -= FLAG_MOVELEFT;
17889 		if(validanim(self,ANI_RUN) && !self->direction && time < self->movetime && self->lastdir==FLAG_MOVELEFT)
17890 			self->running = 1;    // Player begins to run
17891 
17892 		else if(validanim(self,ANI_ATTACKFORWARD) && !self->direction && time < self->movetime && self->lastdir==FLAG_MOVELEFT)
17893 		{
17894 			set_attacking(self);
17895 			self->xdir = self->zdir = 0;
17896 			self->combostep[0] = 0;
17897 			ent_set_anim(self, ANI_ATTACKFORWARD, 0);
17898 			self->takeaction = common_attack_proc;
17899 			return;
17900 		}
17901 		else if(!self->direction && check_combo(FLAG_FORWARD))  ++self->movestep;    // Check direction to distinguish forward/backward movements
17902 		else if(self->direction && check_combo(FLAG_BACKWARD))  ++self->movestep;    // Check direction to distinguish forward/backward movements
17903 		else self->movestep = 0;
17904 
17905 		if(self->direction) self->lastmove = FLAG_BACKWARD;
17906 		else self->lastmove = FLAG_FORWARD;
17907 		self->lastdir = FLAG_MOVELEFT;
17908 
17909 		self->movetime = time + (GAME_SPEED/4);
17910 	}
17911 
17912 	if((player[(int)self->playerindex].playkeys & FLAG_MOVERIGHT))
17913 	{
17914 		player[(int)self->playerindex].playkeys -= FLAG_MOVERIGHT;
17915 		if(validanim(self,ANI_RUN) && self->direction && time < self->movetime &&  self->lastdir==FLAG_MOVERIGHT)
17916 			self->running = 1;    // Player begins to run
17917 
17918 		else if(validanim(self,ANI_ATTACKFORWARD) &&self->direction && time < self->movetime &&  self->lastdir==FLAG_MOVERIGHT)
17919 		{
17920 			set_attacking(self);
17921 			self->xdir = self->zdir = 0;
17922 			self->combostep[0] = 0;
17923 			ent_set_anim(self, ANI_ATTACKFORWARD, 0);
17924 			self->takeaction = common_attack_proc;
17925 			return;
17926 		}
17927 		else if(!self->direction && check_combo(FLAG_BACKWARD))  ++self->movestep;    // Check direction to distinguish forward/backward movements
17928 		else if(self->direction && check_combo(FLAG_FORWARD))  ++self->movestep;    // Check direction to distinguish forward/backward movements
17929 		else self->movestep = 0;
17930 
17931 		if(!self->direction) self->lastmove = FLAG_BACKWARD;
17932 		else self->lastmove = FLAG_FORWARD;
17933 		self->lastdir = FLAG_MOVERIGHT;
17934 
17935 		self->movetime = time + (GAME_SPEED/4);
17936 	}
17937 
17938 	if(!ajspecial && (player[(int)self->playerindex].playkeys & FLAG_JUMP) && validanim(self,ANI_ATTACKBOTH))
17939 	{
17940 		if((player[(int)self->playerindex].keys & FLAG_ATTACK) && notinair)
17941 		{
17942 			player[(int)self->playerindex].playkeys -= FLAG_JUMP;
17943 			set_attacking(self);
17944 			self->xdir = self->zdir = 0;
17945 			self->combostep[0] = 0;
17946 			self->movestep = 0;
17947 			self->stalltime = 0;    // If attack is pressed, holding down attack to execute attack3 is no longer valid
17948 			ent_set_anim(self, ANI_ATTACKBOTH, 0);
17949 			self->takeaction = common_attack_proc;
17950 			return;
17951 		}
17952 	}
17953 
17954 	if((player[(int)self->playerindex].playkeys & FLAG_JUMP) &&  validanim(self,ANI_CHARGE))
17955 	{
17956 		if((player[(int)self->playerindex].playkeys & FLAG_SPECIAL) && notinair)
17957 		{
17958 			self->combostep[0] = 0;
17959 			self->movestep = 0;
17960 			self->xdir = self->zdir = 0;
17961 			self->stalltime = 0;
17962 			set_charging(self);
17963 			ent_set_anim(self, ANI_CHARGE, 0);
17964 			self->takeaction = common_charge;
17965 			return;
17966 		}
17967 	}
17968 
17969 	if(player[(int)self->playerindex].playkeys & FLAG_SPECIAL )    //    The special button can now be used for freespecials
17970 	{
17971 		if( validanim(self,ANI_SPECIAL2) && notinair &&
17972 			(!self->direction ?
17973 			(player[(int)self->playerindex].keys & FLAG_MOVELEFT) :
17974 			 (player[(int)self->playerindex].keys & FLAG_MOVERIGHT))  )
17975 		{
17976 			if(check_costmove(ANI_SPECIAL2, 0))
17977 			{
17978 				player[(int)self->playerindex].playkeys -= FLAG_SPECIAL;
17979 				return;
17980 			}
17981 		}
17982 
17983 		if(check_combo(FLAG_SPECIAL))
17984 		{
17985 			player[(int)self->playerindex].playkeys -= FLAG_SPECIAL;
17986 			return;
17987 		}
17988 
17989 		if(validanim(self,ANI_BLOCK) && !self->modeldata.holdblock && notinair)    // New block code for players
17990 		{
17991 			player[(int)self->playerindex].playkeys -= FLAG_SPECIAL;
17992 			self->xdir = self->zdir = 0;
17993 			set_blocking(self);
17994 			self->combostep[0] = 0;
17995 			self->movestep = 0;
17996 			ent_set_anim(self, ANI_BLOCK, 0);
17997 			self->takeaction = common_block;
17998 			return;
17999 		}
18000 	}
18001 
18002 	if(notinair && player_check_special()) return;    // So you don't perform specials falling off the edge
18003 
18004 	if((player[(int)self->playerindex].releasekeys & FLAG_ATTACK))
18005 	{
18006 		if(self->stalltime  && notinair &&
18007 	      ((validanim(self,ANI_CHARGEATTACK) && self->stalltime+(GAME_SPEED*self->modeldata.animation[ANI_CHARGEATTACK]->chargetime) < time) ||
18008 		   (!validanim(self,ANI_CHARGEATTACK) && self->stalltime+(GAME_SPEED*self->modeldata.animation[animattacks[self->modeldata.atchain[self->modeldata.chainlength-1]-1]]->chargetime) < time)))
18009 		{
18010 			set_attacking(self);
18011 			self->xdir = self->zdir = 0;
18012 			self->combostep[0] = 0;
18013 
18014 			if(validanim(self,ANI_CHARGEATTACK)) ent_set_anim(self, ANI_CHARGEATTACK, 0);
18015 			else ent_set_anim(self, animattacks[self->modeldata.atchain[self->modeldata.chainlength-1]-1], 0);
18016 
18017 			if(SAMPLE_PUNCH >= 0) sound_play_sample(SAMPLE_PUNCH, 0, savedata.effectvol,savedata.effectvol, 100);
18018 
18019 			self->stalltime = 0;
18020 			self->takeaction = common_attack_proc;
18021 			return;
18022 		}
18023 		self->stalltime = 0;
18024 	}
18025 
18026 	if((player[(int)self->playerindex].playkeys & FLAG_ATTACK)  && notinair)
18027 	{
18028 		player[(int)self->playerindex].playkeys -= FLAG_ATTACK;
18029 		self->stalltime = 0;    // Disable the attack3 stalltime
18030 
18031 		if(player[(int)self->playerindex].keys & FLAG_MOVEDOWN && validanim(self, ANI_DUCKATTACK) && PLAYER_MIN_Z == PLAYER_MAX_Z)
18032 		{
18033 			set_attacking(self);
18034 			self->xdir = self->zdir = 0;
18035 			self->combostep[0] = 0;
18036 			ent_set_anim(self, ANI_DUCKATTACK, 0);
18037 			self->takeaction = common_attack_proc;
18038 			return;
18039 		}
18040 
18041 		if(self->running && validanim(self,ANI_RUNATTACK))    // New run attack code section
18042 		{
18043 			player[(int)self->playerindex].playkeys -= FLAG_SPECIAL;
18044 			set_attacking(self);
18045 			self->xdir = self->zdir = 0;
18046 			self->combostep[0] = 0;
18047 			self->running = 0;
18048 			ent_set_anim(self, ANI_RUNATTACK, 0);
18049 			self->takeaction = common_attack_proc;
18050 			return;
18051 		}
18052 
18053 		// Perform special move, Now checks custom combos
18054 		if(check_combo(FLAG_ATTACK))
18055 		{
18056 			//player[(int)self->playerindex].playkeys -= FLAG_SPECIAL;
18057 			return;
18058 		}
18059 
18060 		if(validanim(self,ANI_ATTACKBACKWARD) && time < self->movetime - (GAME_SPEED/10) &&
18061 			!self->movestep && self->lastmove == FLAG_BACKWARD)    // New back attacks
18062 		{
18063 			set_attacking(self);
18064 			self->xdir = self->zdir = 0;
18065 			if(self->direction && (player[(int)self->playerindex].keys & FLAG_MOVERIGHT)) self->direction = 0;    // Since the back part of the combo will flip the player, need to flip them back around
18066 			else if(!self->direction && (player[(int)self->playerindex].keys & FLAG_MOVELEFT)) self->direction = 1;    // Since the back part of the combo will flip the player, need to flip them back around
18067 
18068 			self->combostep[0] = 0;
18069 			ent_set_anim(self, ANI_ATTACKBACKWARD, 0);
18070 			self->takeaction = common_attack_proc;
18071 			return;
18072 		}
18073 
18074 		if( (other = find_ent_here(self, self->x, self->z, TYPE_ITEM)) && ! isSubtypeTouch(other) && !other->blink &&
18075 			diff(self->a - (seta >= 0) * seta , other->a)<0.1  )
18076 		{
18077 			if( validanim(self,ANI_GET) && // so we wont get stuck
18078 				 //dont pickup a weapon that is not in weapon list
18079 				!(( isSubtypeWeapon(other) && self->modeldata.weapon && (*self->modeldata.weapon)[other->modeldata.weapnum-1]<0) ||
18080 				//if on an real animal, can't pick up weapons
18081 				(self->modeldata.animal==2 && isSubtypeWeapon(other))))
18082 			{
18083 				didfind_item(other);
18084 				self->xdir = self->zdir = 0;
18085 				set_getting(self);
18086 				ent_set_anim(self, ANI_GET, 0);
18087 				self->takeaction = common_get;
18088 				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.
18089 				return;
18090 			}
18091 		}
18092 
18093 		// Use stalltime to charge end-move
18094 		self->stalltime = time;
18095 		self->xdir = self->zdir = 0;
18096 
18097 		if(!validanim(self,ANI_ATTACK1) && validanim(self,ANI_JUMP))
18098 		{
18099 			// This is for Mighty
18100 			self->combostep[0] = 0;
18101 			tryjump(self->modeldata.jumpheight, self->modeldata.jumpspeed, 0, ANI_JUMP);
18102 			return;
18103 		}
18104 		if( self->weapent &&
18105 			self->weapent->modeldata.subtype == SUBTYPE_PROJECTILE &&
18106 			validanim(self,ANI_THROWATTACK)  )
18107 		{
18108 			set_attacking(self);
18109 			ent_set_anim(self, ANI_THROWATTACK, 0);
18110 			self->takeaction = common_attack_proc;
18111 		}
18112 		else if(perform_atchain())
18113 		{
18114 			if(SAMPLE_PUNCH >= 0 && self->attacking) sound_play_sample(SAMPLE_PUNCH, 0, savedata.effectvol,savedata.effectvol, 100);
18115 		}
18116 
18117 		return;
18118 	}
18119 	// 7-1-2005 spawn projectile end
18120 
18121 	// Mighty hass no attack animations, he just jumps.
18122 	if(player[(int)self->playerindex].playkeys & FLAG_JUMP  && notinair)
18123 	{    // Added !inair(self) so players can't jump when falling into holes
18124 		player[(int)self->playerindex].playkeys -= FLAG_JUMP;
18125 
18126 		if(self->running)
18127 		{
18128 			//Slide
18129 			if((player[(int)self->playerindex].keys & FLAG_MOVEDOWN) && validanim(self,ANI_RUNSLIDE))
18130 			{
18131 				set_attacking(self);
18132 				self->xdir = self->zdir = 0;
18133 				self->combostep[0] = 0;
18134 				self->running = 0;
18135 				ent_set_anim(self, ANI_RUNSLIDE, 0);
18136 				self->takeaction = common_attack_proc;
18137 				return;
18138 			}
18139 
18140 			if(validanim(self,ANI_RUNJUMP))
18141 				tryjump(self->modeldata.runjumpheight, self->modeldata.jumpspeed*self->modeldata.runjumpdist, (self->modeldata.jumpmovez)?self->zdir:0, ANI_RUNJUMP);
18142 			else if(validanim(self,ANI_FORWARDJUMP))
18143 				tryjump(self->modeldata.runjumpheight, self->modeldata.jumpspeed*self->modeldata.runjumpdist, (self->modeldata.jumpmovez)?self->zdir:0, ANI_FORWARDJUMP);
18144 			else if(validanim(self,ANI_JUMP))
18145 				tryjump(self->modeldata.runjumpheight, self->modeldata.jumpspeed*self->modeldata.runjumpdist, (self->modeldata.jumpmovez)?self->zdir:0, ANI_JUMP);
18146 		}
18147 		else
18148 		{
18149 			if(check_combo(FLAG_JUMP))
18150 			{    // Jump can now be used with freespecials
18151 				//player[(int)self->playerindex].playkeys -= FLAG_SPECIAL;
18152 				return;
18153 			}
18154 			else
18155 			{
18156 				//Slide
18157 				if((player[(int)self->playerindex].keys & FLAG_MOVEDOWN) && validanim(self,ANI_SLIDE))
18158 				{
18159 					set_attacking(self);
18160 					self->xdir = self->zdir = 0;
18161 					self->combostep[0] = 0;
18162 					self->running = 0;
18163 					ent_set_anim(self, ANI_SLIDE, 0);
18164 					self->takeaction = common_attack_proc;
18165 					return;
18166 				}
18167 
18168 				if(!(player[(int)self->playerindex].keys & (FLAG_MOVELEFT|FLAG_MOVERIGHT)) && validanim(self,ANI_JUMP))
18169 				{
18170 					tryjump(self->modeldata.jumpheight, 0, (self->modeldata.jumpmovez)?self->zdir:0, ANI_JUMP);
18171 					return;
18172 				}
18173 				else if((player[(int)self->playerindex].keys & FLAG_MOVELEFT)) self->direction = 0;
18174 				else if((player[(int)self->playerindex].keys & FLAG_MOVERIGHT)) self->direction = 1;
18175 
18176 				if(validanim(self,ANI_FORWARDJUMP))
18177 					tryjump(self->modeldata.jumpheight, self->modeldata.jumpspeed, (self->modeldata.jumpmovez)?self->zdir:0, ANI_FORWARDJUMP);
18178 				else if(validanim(self,ANI_JUMP)) tryjump(self->modeldata.jumpheight, self->modeldata.jumpspeed, (self->modeldata.jumpmovez)?self->zdir:0, ANI_JUMP);
18179 			}
18180 		}
18181 		return;
18182 	}
18183 
18184 	if(validanim(self,ANI_BLOCK) && self->modeldata.holdblock &&
18185 	   player[(int)self->playerindex].keys & FLAG_SPECIAL && notinair)
18186 	{
18187 		player[(int)self->playerindex].playkeys -= FLAG_SPECIAL;
18188 		if(!self->blocking )
18189 		{
18190 			self->blocking = 1;
18191 			self->xdir = self->zdir = 0;
18192 			ent_set_anim(self, ANI_BLOCK, 0);
18193 		}
18194 		return;
18195 	}
18196 	else
18197 	{
18198 		self->blocking = 0;
18199 	}
18200 
18201 	// check attack2 - attack4 freespecial
18202 	if(notinair)
18203 	{
18204 		if((player[(int)self->playerindex].playkeys & FLAG_ATTACK2) && check_combo(FLAG_ATTACK2))
18205 		{
18206 			player[(int)self->playerindex].playkeys -= FLAG_ATTACK2;
18207 			return;
18208 		}
18209 		if((player[(int)self->playerindex].playkeys & FLAG_ATTACK3) && check_combo(FLAG_ATTACK3))
18210 		{
18211 			player[(int)self->playerindex].playkeys -= FLAG_ATTACK3;
18212 			return;
18213 		}
18214 		if((player[(int)self->playerindex].playkeys & FLAG_ATTACK4) && check_combo(FLAG_ATTACK4))
18215 		{
18216 			player[(int)self->playerindex].playkeys -= FLAG_ATTACK4;
18217 			return;
18218 		}
18219 	}
18220 
18221 	if(PLAYER_MIN_Z != PLAYER_MAX_Z)
18222 	{    // More of a platform feel
18223 		if(player[(int)self->playerindex].keys & FLAG_MOVEUP)
18224 		{
18225 			if(!self->modeldata.runupdown ) self->running = 0;    // Quits running if player presses up (or the up animation exists
18226 
18227 			if(validanim(self,ANI_UP) && !self->running)
18228 			{
18229 				action = 2;
18230 				self->zdir = -self->modeldata.speed/2;    // Used for up animation
18231 			}
18232 			else if(self->running)
18233 			{
18234 				action = 4;
18235 				 self->zdir = -self->modeldata.runspeed/2;    // Moves up at a faster rate running
18236 			}
18237 			else
18238 			{
18239 				action = 1;
18240 				self->zdir = -self->modeldata.speed/2;
18241 			}
18242 		}
18243 		else if(player[(int)self->playerindex].keys & FLAG_MOVEDOWN)
18244 		{
18245 			if(!self->modeldata.runupdown ) self->running = 0;    // Quits running if player presses down (or the down animation exists
18246 
18247 			if(validanim(self,ANI_DOWN) && !self->running )
18248 			{
18249 				action = 3;
18250 				self->zdir = self->modeldata.speed/2;    // Used for down animation
18251 			}
18252 			else if(self->running)
18253 			{
18254 				action = 4;
18255 				self->zdir = self->modeldata.runspeed/2;    // Moves down at a faster rate running
18256 			}
18257 			else
18258 			{
18259 				action = 1;
18260 				self->zdir = self->modeldata.speed/2;
18261 			}
18262 		}
18263 		else if(!(player[(int)self->playerindex].keys & (FLAG_MOVEUP|FLAG_MOVEDOWN)))
18264 			self->zdir = 0;
18265 	}
18266 	else if(validanim(self,ANI_DUCK) && player[(int)self->playerindex].keys & FLAG_MOVEDOWN  && notinair)
18267 	{
18268 		ent_set_anim(self, ANI_DUCK, 0);
18269 		self->xdir = self->zdir = 0;
18270 		return;
18271 	}
18272 
18273 	if(player[(int)self->playerindex].keys & FLAG_MOVELEFT)
18274 	{
18275 		if(self->direction)
18276 		{
18277 			self->running = 0;    // Quits running if player changes direction
18278 			if(self->modeldata.turndelay && !self->turntime)
18279 				self->turntime = time + self->modeldata.turndelay;
18280 			else if(self->turntime && time >= self->turntime)
18281 			{
18282 				self->turntime = 0;
18283 				if(validanim(self,ANI_TURN))
18284 				{
18285 					set_turning(self);
18286 					ent_set_anim(self, ANI_TURN, 0);
18287 					self->takeaction = common_turn;
18288 					return;
18289 				}
18290 				self->direction = 0;
18291 			}
18292 			else if(!self->modeldata.turndelay && validanim(self,ANI_TURN))
18293 			{
18294 				set_turning(self);
18295 				ent_set_anim(self, ANI_TURN, 0);
18296 				self->takeaction = common_turn;
18297 				return;
18298 			}
18299 			else if(!self->turntime) self->direction = 0;
18300 		}
18301 		else  self->turntime = 0;
18302 
18303 		if(self->running)
18304 		{
18305 			action = 4;
18306 			self->xdir = -self->modeldata.runspeed;    // If running, player moves at a faster rate
18307 		}
18308 		else if(action!=2 && action != 3)
18309 		{
18310 			action = 1;
18311 			self->xdir = -self->modeldata.speed;
18312 		}
18313 		else
18314 		{
18315 			self->xdir = -self->modeldata.speed;
18316 		}
18317 	}
18318 	else if(player[(int)self->playerindex].keys & FLAG_MOVERIGHT)
18319 	{
18320 		if(!self->direction)
18321 		{
18322 			self->running = 0;    // Quits running if player changes direction
18323 			if(self->modeldata.turndelay && !self->turntime)
18324 				self->turntime = time + self->modeldata.turndelay;
18325 			else if(self->turntime && time >= self->turntime)
18326 			{
18327 				self->turntime = 0;
18328 				if(validanim(self,ANI_TURN))
18329 				{
18330 					set_turning(self);
18331 					ent_set_anim(self, ANI_TURN, 0);
18332 					self->takeaction = common_turn;
18333 					return;
18334 				}
18335 				self->direction = 1;
18336 			}
18337 			else if(!self->modeldata.turndelay && validanim(self,ANI_TURN))
18338 			{
18339 				set_turning(self);
18340 				ent_set_anim(self, ANI_TURN, 0);
18341 				self->takeaction = common_turn;
18342 				return;
18343 			}
18344 			else if(!self->turntime) self->direction = 1;
18345 		}
18346 		else  self->turntime = 0;
18347 
18348 		if(self->running)
18349 		{
18350 			action = 4;
18351 			self->xdir = self->modeldata.runspeed;    // If running, player moves at a faster rate
18352 		}
18353 		else if(action!=2 && action != 3)
18354 		{
18355 			action = 1;
18356 			self->xdir = self->modeldata.speed;
18357 		}
18358 		else
18359 		{
18360 			self->xdir = self->modeldata.speed;
18361 		}
18362 	}
18363 	else if(!((player[(int)self->playerindex].keys & FLAG_MOVELEFT) ||
18364 		(player[(int)self->playerindex].keys & FLAG_MOVERIGHT)) )
18365 	{
18366 		self->running = 0;    // Player let go of left/right and so quits running
18367 		self->xdir = 0;
18368 		self->turntime = 0;
18369 	}
18370 
18371 	//    ltb 1-18-05  new Item get code to address new subtype
18372 
18373 	if((other = find_ent_here(self, self->x, self->z, TYPE_ITEM)) && isSubtypeTouch(other) && !other->blink &&
18374 		diff(self->a - (seta >= 0) * seta , other->a)<0.1 && action)
18375 	{
18376 		didfind_item(other);    // Added function to clean code up a bit
18377 	}
18378 
18379 	switch(action)
18380 	{
18381 		case 1:
18382 		// back walk feature
18383 			if(level && validanim(self,ANI_BACKWALK))
18384 			{
18385 			if(self->modeldata.facing == 1 || level->facing == 1)  bkwalk = !self->direction;
18386 			else if(self->modeldata.facing == 2 || level->facing == 2) bkwalk = self->direction;
18387 			else if((self->modeldata.facing == 3 || level->facing == 3) && (level->scrolldir & SCROLL_LEFT) && !self->direction ) bkwalk = 1;
18388 			else if((self->modeldata.facing == 3 || level->facing == 3) && (level->scrolldir & SCROLL_RIGHT) && self->direction) bkwalk = 1;
18389 			else if(self->turntime && self->modeldata.turndelay) bkwalk = 1;
18390 			if(bkwalk) common_backwalk_anim(self); //ent_set_anim(self, ANI_BACKWALK, 0);
18391 			else common_walk_anim(self); //ent_set_anim(self, ANI_WALK, 0);    // If neither up nor down exist, set to walk
18392 		}
18393 		else common_walk_anim(self); //ent_set_anim(self, ANI_WALK, 0);    // If neither up nor down exist, set to walk
18394 			break;
18395 		case 2:
18396 			common_up_anim(self); //ent_set_anim(self, ANI_UP, 0);    // Set to up animation if exists
18397 			break;
18398 		case 3:
18399 		    common_down_anim(self); //ent_set_anim(self, ANI_DOWN, 0);    // Set to down animation if exists
18400 			break;
18401 		case 4:
18402 			ent_set_anim(self, ANI_RUN, 0);    // Set to run animation if exists
18403 			break;
18404 		default:
18405 			if(self->idling)
18406 			{
18407 				common_idle_anim(self);
18408 				return;
18409 			}
18410 			break;
18411 	}
18412 	if(action)
18413 	{
18414 		self->takeaction = NULL;
18415 		self->idling = 1;
18416 	}
18417 }
18418 
common_idle_anim(entity * ent)18419 int common_idle_anim(entity* ent)
18420 {
18421 	/*
18422 	common_idle_anim
18423 	Damon Vaughn Caskey
18424 	11012009
18425 	Determine and set appropriate idle animation based on condition and range.
18426 	Returns 1 if any animation is set.
18427 	*/
18428 
18429 	int i;                                                                              //Loop counter.
18430 	int iAni;                                                                           //Animation.
18431 
18432 	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
18433 		ent->xdir = ent->zdir = 0;                                                      //Stop movement.
18434 
18435 	if(validanim(ent,ANI_FAINT) && ent->health <= ent->modeldata.health / 4)            //ANI_FAINT and health at/below 25%?
18436 	{
18437 		ent_set_anim(ent, ANI_FAINT, 0);                                                //Set ANI_FAINT.
18438 		return 1;                                                                       //Return 1 and exit.
18439 	}
18440 	else if(validanim(ent,ANI_SLEEP) && (time >= ent->sleeptime) && ent->animating)     //ANI_SLEEP, sleeptime up and currently animating?
18441 	{
18442 		ent_set_anim(ent, ANI_SLEEP, 0);                                                //Set sleep anim.
18443 		return 1;                                                                       //Return 1 and exit.
18444 	}
18445 	else
18446 	{
18447 		for (i=0; i<max_idles; i++)                                                     //Loop through all idle animations.
18448 		{
18449 			iAni = animidles[i];                                                        //Get current animation.
18450 
18451 			if (validanim(ent, iAni) && iAni != ANI_IDLE)                               //Valid and not ANI_IDLE?
18452 			{
18453 				if (normal_find_target(iAni,0))                                           //Opponent in range of current animation?
18454 				{
18455 					ent_set_anim(ent, iAni, 0);                                         //Set animation.
18456 					return 1;                                                           //Return 1 and exit.
18457 				}
18458 			}
18459 		}
18460 
18461 		if (validanim(ent, ANI_IDLE))
18462 		{
18463 			ent_set_anim(ent, ANI_IDLE, 0);                                             //No alternates were set. Set ANI_IDLE.
18464 			return 1;                                                                   //Return 1 and exit.
18465 		}
18466 	}
18467 
18468 	return 0;
18469 }
18470 
common_walk_anim(entity * ent)18471 int common_walk_anim(entity* ent)
18472 {
18473 	/*
18474 	common_walk_anim
18475 	Damon Vaughn Caskey
18476 	11032009
18477 	Determine and set appropriate walk animation based on condition and range.
18478 	Returns 1 if any animation is set.
18479 	*/
18480 
18481 	int i;                                                                          //Loop counter.
18482 	int iAni;                                                                       //Animation.
18483 
18484 	for (i=0; i<max_walks; i++)                                                     //Loop through all relevant animations.
18485 	{
18486 		iAni = animwalks[i];                                                        //Get current animation.
18487 
18488 		if (validanim(ent, iAni) && iAni != ANI_WALK)                               //Valid and not Default animation??
18489 		{
18490 			if (normal_find_target(iAni,0))                                         //Opponent in range of current animation?
18491 			{
18492 				ent_set_anim(ent, iAni, 0);                                         //Set animation.
18493 				return 1;                                                           //Return 1 and exit.
18494 			}
18495 		}
18496 	}
18497 
18498 	if (validanim(ent, ANI_WALK))
18499 	{
18500 		ent_set_anim(ent, ANI_WALK, 0);                                             //No alternates were set. Set default..
18501 		return 1;                                                                   //Return 1 and exit.
18502 	}
18503 
18504 	return 0;
18505 }
18506 
common_backwalk_anim(entity * ent)18507 int common_backwalk_anim(entity* ent)
18508 {
18509 	/*
18510 	common_backwalk_anim
18511 	Damon Vaughn Caskey
18512 	11032009
18513 	Determine and set appropriate backwalk animation based on condition and range.
18514 	Returns 1 if any animation is set.
18515 	*/
18516 
18517 	int i;                                                                          //Loop counter.
18518 	int iAni;                                                                       //Animation.
18519 
18520 	for (i=0; i<max_backwalks; i++)                                                 //Loop through all relevant animations.
18521 	{
18522 		iAni = animbackwalks[i];                                                    //Get current animation.
18523 
18524 		if (validanim(ent, iAni) && iAni != ANI_BACKWALK)                           //Valid and not Default animation??
18525 		{
18526 			if (normal_find_target(iAni,0))                                         //Opponent in range of current animation?
18527 			{
18528 				ent_set_anim(ent, iAni, 0);                                         //Set animation.
18529 				return 1;                                                           //Return 1 and exit.
18530 			}
18531 		}
18532 	}
18533 
18534 	if (validanim(ent, ANI_BACKWALK))
18535 	{
18536 		ent_set_anim(ent, ANI_BACKWALK, 0);                                         //No alternates were set. Set default..
18537 		return 1;                                                                   //Return 1 and exit.
18538 	}
18539 
18540 	return 0;
18541 }
18542 
common_up_anim(entity * ent)18543 int common_up_anim(entity* ent)
18544 {
18545 	/*
18546 	common_up_anim
18547 	Damon Vaughn Caskey
18548 	11032009
18549 	Determine and set appropriate up animation based on condition and range.
18550 	Returns 1 if any animation is set.
18551 	*/
18552 
18553 	int i;                                                                    //Loop counter.
18554 	int iAni;                                                                 //Animation.
18555 
18556 	for (i=0; i<max_ups; i++)                                                 //Loop through all relevant animations.
18557 	{
18558 		iAni = animups[i];                                                    //Get current animation.
18559 
18560 		if (validanim(ent, iAni) && iAni != ANI_UP)                           //Valid and not Default animation??
18561 		{
18562 			if (normal_find_target(iAni,0))                                   //Opponent in range of current animation?
18563 			{
18564 				ent_set_anim(ent, iAni, 0);                                   //Set animation.
18565 				return 1;                                                     //Return 1 and exit.
18566 			}
18567 		}
18568 	}
18569 
18570 	if (validanim(ent, ANI_UP))
18571 	{
18572 		ent_set_anim(ent, ANI_UP, 0);                                         //No alternates were set. Set default..
18573 		return 1;                                                             //Return 1 and exit.
18574 	}
18575 
18576 	return 0;
18577 }
18578 
common_down_anim(entity * ent)18579 int common_down_anim(entity* ent)
18580 {
18581 	/*
18582 	common_up_anim
18583 	Damon Vaughn Caskey
18584 	11032009
18585 	Determine and set appropriate up animation based on condition and range.
18586 	Returns 1 if any animation is set.
18587 	*/
18588 
18589 	int i;                                                                    //Loop counter.
18590 	int iAni;                                                                 //Animation.
18591 
18592 	for (i=0; i<max_downs; i++)                                               //Loop through all relevant animations.
18593 	{
18594 		iAni = animdowns[i];                                                  //Get current animation.
18595 
18596 		if (validanim(ent, iAni) && iAni != ANI_DOWN)                         //Valid and not Default animation??
18597 		{
18598 			if (normal_find_target(iAni,0))                                   //Opponent in range of current animation?
18599 			{
18600 				ent_set_anim(ent, iAni, 0);                                   //Set animation.
18601 				return 1;                                                     //Return 1 and exit.
18602 			}
18603 		}
18604 	}
18605 
18606 	if (validanim(ent, ANI_DOWN))
18607 	{
18608 		ent_set_anim(ent, ANI_DOWN, 0);                                       //No alternates were set. Set default..
18609 		return 1;                                                             //Return 1 and exit.
18610 	}
18611 
18612 	return 0;
18613 }
18614 
18615 //ammo count goes down
subtract_shot()18616 void subtract_shot()
18617 {
18618 	if(self->weapent && self->weapent->modeldata.shootnum)
18619 	{
18620 		self->weapent->modeldata.shootnum--;
18621 		if(!self->weapent->modeldata.shootnum)
18622 		{
18623 			self->weapent->modeldata.counter = 0;
18624 			dropweapon(0);
18625 		}
18626 	}
18627 
18628 }
18629 
18630 
dropweapon(int flag)18631 void dropweapon(int flag)
18632 {
18633 	int wall;
18634 	entity* other = NULL;
18635 
18636 	if(self->weapent)
18637 	{
18638 		if(self->weapent->modeldata.typeshot || (!self->weapent->modeldata.typeshot && self->weapent->modeldata.shootnum))
18639 		{
18640 			self->weapent->direction = self->direction;//same direction as players, 2007 -2 - 11   by UTunnels
18641 			if(flag < 2) self->weapent->modeldata.counter -= flag;
18642 			self->weapent->z = self->z;
18643 			self->weapent->x = self->x;
18644 			self->weapent->a = self->a;
18645 
18646 			other = check_platform(self->weapent->x, self->weapent->z, self);
18647 			wall = checkwall(self->weapent->x, self->weapent->z);
18648 
18649 			if(other && other != self->weapent)   self->weapent->base += other->a + other->animation->platform[other->animpos][7];
18650 			else if(wall >= 0) self->weapent->base += level->walls[wall][7];
18651 
18652 			if(validanim(self->weapent,ANI_RESPAWN)) ent_set_anim(self->weapent, ANI_RESPAWN, 0);
18653 			else if(validanim(self->weapent,ANI_SPAWN)) ent_set_anim(self->weapent, ANI_SPAWN, 0);
18654 			else ent_set_anim(self->weapent, ANI_IDLE, 0);
18655 
18656 			if(!self->weapent->modeldata.counter)
18657 			{
18658 				if(!self->modeldata.animal)
18659 				{
18660 					self->weapent->blink = 1;
18661 					self->weapent->takeaction = common_lie;
18662 				}
18663 				else{
18664 					self->weapent->modeldata.type = TYPE_NONE;
18665 					self->weapent->think = runanimal;
18666 				}
18667 				self->weapent->nextthink = time + 1;
18668 			}
18669 		}
18670 		self->weapent = NULL;
18671 	}
18672 	if(flag < 2)
18673 	{
18674 		if(self->modeldata.type == TYPE_PLAYER)
18675 		{
18676 			if(player[(int)self->playerindex].weapnum)
18677 				set_weapon(self, player[(int)self->playerindex].weapnum, 0);
18678 			else set_weapon(self, level->setweap, 0);
18679 		}
18680 		else set_weapon(self, 0, 0);
18681 	}
18682 
18683 	if(self->modeldata.weaploss[1]>0)
18684 	{
18685 		set_weapon(self, self->modeldata.weaploss[1], 0);
18686 	}
18687 }
18688 
18689 
player_takedamage(entity * other,s_attack * attack)18690 int player_takedamage(entity *other, s_attack* attack)
18691 {
18692 	s_attack atk;
18693 	//printf("damaged by: '%s' %d\n", other->name, attack->attack_force);
18694 	if(healthcheat)
18695 	{
18696 		memcpy(&atk, attack, sizeof(s_attack));
18697 		atk.attack_force = 0;
18698 		return common_takedamage(other, &atk);
18699 	}
18700 	return common_takedamage(other, attack);
18701 }
18702 
18703 
18704 ////////////////////////////////
18705 
18706 // Called when player re-enters the game.
18707 // Drop all enemies EXCEPT for the linked/frozen ones.
drop_all_enemies()18708 void drop_all_enemies()
18709 {
18710 	int i;
18711 	entity* weapself = self;
18712 	for(i=0; i<ent_max; i++)
18713 	{
18714 		if(ent_list[i]->exists &&
18715 			ent_list[i]->health>0 &&
18716 			ent_list[i]->modeldata.type==TYPE_ENEMY &&
18717 			!ent_list[i]->owner &&    // Don't want to knock down a projectile
18718 			!ent_list[i]->frozen &&    // Don't want to unfreeze a frozen enemy
18719 			!ent_list[i]->modeldata.nomove &&
18720 			!ent_list[i]->modeldata.nodrop &&
18721 			validanim(ent_list[i],ANI_FALL) )
18722 		{
18723 			ent_list[i]->attacking = 0;
18724 			ent_list[i]->projectile = 0;
18725 			ent_list[i]->takeaction = common_fall;//enemy_fall;
18726 			ent_list[i]->damage_on_landing = 0;
18727 			self = ent_list[i];
18728 			ent_unlink(self);
18729 			ent_list[i]->xdir = (self->direction)?(-1.2):1.2;
18730 			dropweapon(1);
18731 			toss(ent_list[i], 2.5 + randf(1));
18732 			set_fall(ent_list[i], ATK_NORMAL, 1, self, 0, 0, 0, 0, 0, 0);
18733 			ent_list[i]->knockdowncount = ent_list[i]->modeldata.knockdowncount;
18734 
18735 			ent_list[i]->knockdowntime = 0;
18736 		}
18737 	}
18738 	self = weapself;
18739 }
18740 
18741 
18742 
18743 // Called when boss dies
kill_all_enemies()18744 void kill_all_enemies()
18745 {
18746 	int i;
18747 	s_attack attack;
18748 	entity * tmpself = NULL;
18749 
18750 	attack = emptyattack;
18751 	attack.attack_type = max_attack_types;
18752 	attack.dropv[0] = (float)3; attack.dropv[1] = (float)1.2; attack.dropv[2] = (float)0;
18753 
18754 	tmpself = self;
18755 	for(i=0; i<ent_max; i++)
18756 	{
18757 		if(  ent_list[i]->exists
18758 			&& ent_list[i]->health>0
18759 			&& ent_list[i]->modeldata.type==TYPE_ENEMY
18760 			&& ent_list[i]->takedamage)
18761 		{
18762 			self = ent_list[i];
18763 			attack.attack_force = self->health;
18764 			self->takedamage(tmpself, &attack);
18765 			self->dead = 1;
18766 		}
18767 	}
18768 	self = tmpself;
18769 }
18770 
18771 
18772 
smart_bomb(entity * e,s_attack * attack)18773 void smart_bomb(entity* e, s_attack* attack)    // New method for smartbombs
18774 {
18775 	int i, hostile, hit=0;
18776 	entity * tmpself = NULL;
18777 
18778 	hostile = e->modeldata.hostile;
18779 	if(e->modeldata.type == TYPE_PLAYER)
18780 		hostile &= ~(TYPE_PLAYER);
18781 
18782 	tmpself = self;
18783 	for(i=0; i<ent_max; i++)
18784 	{
18785 		if( ent_list[i]->exists
18786 			&& ent_list[i] != e
18787 			&& ent_list[i]->health>0
18788 			&& (ent_list[i]->modeldata.type&(e->modeldata.hostile)))
18789 		{
18790 			self = ent_list[i];
18791 			hit = 1; // for nocost, if the bomb doesn't hit, it won't cost energy
18792 			if(self->takedamage)
18793 			{
18794 				//attack.attack_drop = self->modeldata.knockdowncount+1;
18795 				self->takedamage(e, attack);
18796 			}
18797 			else
18798 			{
18799 				self->health -= attack->attack_force;
18800 				if(self->health<=0) kill(self);
18801 			}
18802 		}
18803 	}
18804 	if(nocost && hit && smartbomber) // don't use e, because this can be an item-bomb
18805 	{
18806 		self = smartbomber;
18807 		if(check_energy(1, ANI_SPECIAL))
18808 		{
18809 			self->mp -= self->modeldata.animation[ANI_SPECIAL]->energycost.cost;
18810 		}
18811 		else self->health -= self->modeldata.animation[ANI_SPECIAL]->energycost.cost;
18812 	}
18813 	self = tmpself;
18814 
18815 }
18816 
18817 
18818 ////////////////////////////////
18819 
anything_walk()18820 void anything_walk()
18821 {
18822 	if(self->x < advancex - 80 || self->x > advancex + (videomodes.hRes+80)){
18823 		kill(self);
18824 		return;
18825 	}
18826 	//self->x += self->xdir;
18827 }
18828 
knife_spawn(char * name,int index,float x,float z,float a,int direction,int type,int map)18829 entity * knife_spawn(char *name, int index, float x, float z, float a, int direction, int type, int map)
18830 {
18831 	entity *e = NULL;
18832 
18833 	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;}
18834 	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;}
18835 	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;}
18836 	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;}
18837 	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;}
18838 	else if(index>=0 ||name)                                 {e = spawn(x, z, a, direction, name, index, NULL);                            if(!e) return NULL; e->ptype = 0; e->a = a;}
18839 	else if(type)                                            {e = spawn(x, z, a, direction, "Shot", -1, NULL);                             if(!e) return NULL; e->ptype = 0; e->a = a;}
18840 	else/* if(!type) */                                      {e = spawn(x, z, a, direction, "Knife", -1, NULL);                            if(!e) return NULL; e->ptype = 0; e->a = a;}
18841 
18842 	if(e==NULL) return NULL;
18843 	else if(self->modeldata.type == TYPE_PLAYER) e->modeldata.type = TYPE_SHOT;
18844 	else e->modeldata.type = self->modeldata.type;
18845 
18846 	if(self->animation->energycost.cost > 0 && nocost) self->cantfire = 1;    // Can't fire if still exists on screen
18847 
18848 	if(!e->model->speed && !e->modeldata.nomove) e->modeldata.speed = 2;
18849 	else if(e->modeldata.nomove) e->modeldata.speed = 0;
18850 
18851 	e->owner = self;                                                     // Added so projectiles don't hit the owner
18852 	e->nograb = 1;                                                       // Prevents trying to grab a projectile
18853 	e->attacking = 1;
18854 	//e->direction = direction;
18855 	e->think = common_think;
18856 	e->nextthink = time+1;
18857 	e->trymove = NULL;
18858 	e->takedamage = arrow_takedamage;
18859 	e->takeaction = NULL;
18860 	e->modeldata.aimove = AIMOVE1_ARROW;
18861 	if(!e->modeldata.offscreenkill) e->modeldata.offscreenkill = 200; //default value
18862 	e->modeldata.aiattack = AIATTACK1_NOATTACK;
18863 	e->remove_on_attack = e->modeldata.remove;
18864 	e->autokill = e->modeldata.nomove;
18865 
18866 	ent_set_colourmap(e, map);
18867 
18868 	if(e->ptype) e->base = 0;
18869 	else e->base = a;
18870 
18871 	if(e->modeldata.hostile < 0)   e->modeldata.hostile = self->modeldata.hostile;
18872 	if(e->modeldata.candamage < 0) e->modeldata.candamage = self->modeldata.candamage;
18873 
18874 	e->modeldata.subject_to_wall = e->modeldata.subject_to_platform = e->modeldata.subject_to_hole = e->modeldata.subject_to_gravity = 1;
18875 	e->modeldata.no_adjust_base  = 1;
18876 	return e;
18877 }
18878 
18879 
18880 
bomb_explode()18881 void bomb_explode()
18882 {
18883 	if(self->animating) return;
18884 	kill(self);
18885 }
18886 
18887 
bomb_spawn(char * name,int index,float x,float z,float a,int direction,int map)18888 entity * bomb_spawn(char *name, int index, float x, float z, float a, int direction, int map)
18889 {
18890 	entity *e = NULL;
18891 
18892 	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);
18893 	else if(self->animation->custbomb>=0) e = spawn(x, z, a, direction, NULL, self->animation->custbomb, NULL);
18894 	else if(self->modeldata.bomb>=0) e = spawn(x, z, a, direction, NULL, self->modeldata.bomb, NULL);
18895 	else e = spawn(x, z, a, direction, name, index, NULL);
18896 
18897 	if(e==NULL) return NULL;
18898 
18899 	e->a = a + 0.5;
18900 
18901 	if(self->animation->energycost.cost > 0 && nocost) self->cantfire = 1;    // Can't fire if still exists on screen
18902 
18903 	if(!e->model->speed && !e->modeldata.nomove) e->modeldata.speed = 2;
18904 	else if(e->modeldata.nomove) e->modeldata.speed = 0;
18905 
18906 	e->attacking = 1;
18907 	e->owner = self;                                                     // Added so projectiles don't hit the owner
18908 	e->nograb = 1;                                                       // Prevents trying to grab a projectile
18909 	e->toexplode = 1;                                                    // Set to distinguish exploding projectiles and also so stops falling when hitting an opponent
18910 	ent_set_colourmap(e, map);
18911 	//e->direction = direction;
18912 	toss(e, e->modeldata.jumpheight);
18913 	e->think = common_think;
18914 	e->nextthink = time+1;
18915 	e->trymove = NULL;
18916 	e->takeaction = NULL;
18917 	e->modeldata.aimove = AIMOVE1_BOMB;
18918 	e->modeldata.aiattack = AIATTACK1_NOATTACK;                                    // Well, bomb's attack animation is passive, dont use any A.I. code.
18919 	e->takedamage = common_takedamage;
18920 	e->remove_on_attack = 0;
18921 	e->autokill = e->modeldata.nomove;
18922 
18923 
18924 	// Ok, some old mods use type none, will have troubles.
18925 	// so we give them some default hostile types.
18926 	if(e->modeldata.hostile <0) e->modeldata.hostile = self->modeldata.hostile;
18927 	if(e->modeldata.candamage <0) e->modeldata.candamage = self->modeldata.candamage;
18928 	e->modeldata.no_adjust_base = 0;
18929 	e->modeldata.subject_to_wall = e->modeldata.subject_to_platform = e->modeldata.subject_to_hole = e->modeldata.subject_to_gravity = 1;
18930 	return e;
18931 }
18932 
18933 
18934 // Spawn 3 stars
star_spawn(float x,float z,float a,int direction)18935 int star_spawn(float x, float z, float a, int direction){ // added entity to know which star to load
18936 	entity *e = NULL;
18937 	int i, index = -1;
18938 	char* starname = NULL;
18939 	float fd = (float)((direction ? 2 : -2));
18940 
18941 	//merge enemy/player together, use the same rules
18942 	if(self->weapent && self->weapent->modeldata.subtype==SUBTYPE_PROJECTILE && self->weapent->modeldata.project>=0) index = self->weapent->modeldata.project;
18943 	else if(self->animation->custstar>=0) index = self->animation->custstar; //use any star
18944 	else if(self->modeldata.star>=0) index = self->modeldata.star;
18945 	else starname = "Star"; // this is default star
18946 
18947 	for(i = 0; i<3; i++){
18948 		e = spawn(x, z, a, direction, starname, index, NULL);
18949 		if(e == NULL) return 0;
18950 
18951 		self->attacking = 0;
18952 
18953 		e->takedamage = arrow_takedamage;//enemy_takedamage;    // Players can now hit projectiles
18954 		e->owner = self;    // Added so enemy projectiles don't hit the owner
18955 		e->attacking = 1;
18956 		e->nograb = 1;    // Prevents trying to grab a projectile
18957 		e->xdir = fd/2 * (float)i;
18958 		e->think = common_think;
18959 		e->nextthink = time+1;
18960 		e->trymove = NULL;
18961 		e->takeaction = NULL;
18962 		e->modeldata.aimove = AIMOVE1_STAR;
18963 		e->modeldata.aiattack = AIATTACK1_NOATTACK;
18964 		e->remove_on_attack = e->modeldata.remove;
18965 		e->base = a;
18966 		e->a = a;
18967 		//e->direction = direction;
18968 
18969 		if(e->modeldata.hostile <0) e->modeldata.hostile = self->modeldata.hostile;
18970 		if(e->modeldata.candamage <0) e->modeldata.candamage = self->modeldata.candamage;
18971 
18972 		e->modeldata.subject_to_wall = e->modeldata.subject_to_platform =
18973 		e->modeldata.subject_to_hole = e->modeldata.subject_to_gravity = 1;
18974 		e->modeldata.no_adjust_base = 1;
18975 	}
18976 	return 1;
18977 }
18978 
18979 
18980 
steam_think()18981 void steam_think()
18982 {
18983 	if(!self->animating)
18984 	{
18985 		kill(self);
18986 		return;
18987 	}
18988 
18989 	self->base += 1;
18990 	self->a = self->base;
18991 }
18992 
18993 
18994 
18995 // for the "trap" type   7-1-2005  trap start
trap_think()18996 void trap_think()
18997 {
18998 	if(self->x < advancex-80 || self->x > advancex+(videomodes.hRes+80)){
18999 		//        kill(self);   // 6-2-2005 removed temporarily
19000 		return;
19001 	}
19002 
19003 	self->attacking = 1;
19004 	self->nextthink = time + 1;
19005 }
19006 //    7-1-2005  trap end
19007 
19008 
19009 
19010 
steam_spawn(float x,float z,float a)19011 void steam_spawn(float x, float z, float a){
19012 	entity *e = NULL;
19013 
19014 	e = spawn(x, z, a, 0, "Steam", -1, NULL);
19015 
19016 	if(e==NULL) return;
19017 
19018 	e->base = a;
19019 	e->modeldata.no_adjust_base = 1;
19020 	e->think = steam_think;
19021 }
19022 
19023 
19024 
steamer_think()19025 void steamer_think()
19026 {
19027 	if(self->x < advancex-80 || self->x > advancex+(videomodes.hRes+80)){
19028 		kill(self);
19029 		return;
19030 	}
19031 
19032 	steam_spawn(self->x, self->z, self->a);
19033 	self->nextthink = time + (GAME_SPEED/10) + (rand32()&31);
19034 }
19035 
19036 
19037 
text_think()19038 void text_think(){    // New function so text can be displayed
19039 	 // wait to suicide
19040 	if(!self->animating) kill(self);
19041 }
19042 
19043 ////////////////////////////////
19044 
19045 //homing arrow find its target
19046 // type : target type
homing_find_target(int type)19047 entity * homing_find_target(int type){
19048 	int i, min, max;
19049 	int index = -1;
19050 	//use the walk animation's range
19051 	if(validanim(self,ANI_WALK)){
19052 		min = self->modeldata.animation[ANI_WALK]->range.xmin;
19053 		max = self->modeldata.animation[ANI_WALK]->range.xmax;
19054 	} else {
19055 		min = 0;
19056 		max = 999;
19057 	}
19058 	//find the 'nearest' one
19059 	for(i=0; i<ent_max; i++){
19060 		if( ent_list[i]->exists && ent_list[i] != self //cant target self
19061 			&& (ent_list[i]->modeldata.type & type)
19062 			&& diff(ent_list[i]->x,self->x)+ diff(ent_list[i]->z,self->z) >= min
19063 			&& diff(ent_list[i]->x,self->x)+ diff(ent_list[i]->z,self->z) <= max
19064 			&& ent_list[i]->animation->vulnerable[ent_list[i]->animpos]  )
19065 		{
19066 			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))
19067 				index = i;
19068 		}
19069 	}
19070 	if( index >=0) return ent_list[index];
19071 	return NULL;
19072 }
19073 
19074 
bike_crash()19075 void bike_crash(){
19076 	int i;
19077 	if(self->direction) self->xdir = 2;
19078 	else self->xdir = -2;
19079 	self->nextthink = time + THINK_SPEED / 2;
19080 	for(i=0; i<maxplayers[current_set]; i++) control_rumble(i, 100);
19081 	//if(self->x < advancex-100 || self->x > advancex+(videomodes.hRes+100)) kill(self);
19082 }
19083 
19084 
19085 
biker_takedamage(entity * other,s_attack * attack)19086 int biker_takedamage(entity *other, s_attack* attack)
19087 {
19088 	entity *driver = NULL;
19089 	entity* tempself = NULL;
19090 	if(self->dead) return 0;
19091 	// Fell in a hole
19092 	if(self->a < PIT_DEPTH)
19093 	{
19094 		kill(self);
19095 		return 0;
19096 	}
19097 	if(other!=self)set_opponent(other, self);
19098 
19099 	if(attack->no_pain) // don't drop driver until it is dead, because the attack has no pain effect
19100 	{
19101 		checkdamage(other, attack);
19102 		if(self->health>0) return 1; // not dead yet
19103 	}
19104 
19105 	set_pain(self,  self->damagetype, 1);
19106 	self->attacking = 1;
19107 	if(!self->modeldata.offscreenkill) self->modeldata.offscreenkill = 100;
19108 	self->think = bike_crash;
19109 	self->nextthink = time + THINK_SPEED;
19110 	// well, this is the real entity, the driver who take the damage
19111 	if((driver = drop_driver(self)))
19112 	{
19113 		driver->a = self->a;
19114 		tempself = self;
19115 		self = driver;
19116 		self->drop = 1;
19117 		self->direction = tempself->direction;
19118 		if(self->takedamage) self->takedamage(self, attack);
19119 		else self->health -= attack->attack_force;
19120 		self = tempself;
19121 
19122 	}
19123 	self->health = 0;
19124 	checkdeath();
19125 	return 1;
19126 }
19127 
19128 
19129 
obstacle_fall()19130 void obstacle_fall()
19131 {
19132 	if(inair(self)) return;
19133 
19134 	self->xdir = self->zdir = 0;
19135 	if((!self->animating && validanim(self,ANI_DIE)) || !validanim(self,ANI_DIE)) kill(self);    // Fixed so ANI_DIE can be used
19136 }
19137 
19138 
19139 
obstacle_fly()19140 void obstacle_fly()    // Now obstacles can fly when hit like on Simpsons/TMNT
19141 {
19142 	//self->x += self->xdir * 4;    // Equivelant of speed 40
19143 	if(self->x > advancex+(videomodes.hRes + 200) || self->x < advancex-200) kill(self);
19144 
19145 	self->nextthink = time + 2;
19146 }
19147 
19148 
19149 
obstacle_takedamage(entity * other,s_attack * attack)19150 int obstacle_takedamage(entity *other, s_attack* attack)
19151 {
19152 	if(self->a <= PIT_DEPTH)
19153 	{
19154 		kill(self);
19155 		return 0;
19156 	}
19157 
19158 	self->pain_time = time + (GAME_SPEED / 5);
19159 	set_opponent(other, self);
19160 	if(self->opponent && self->opponent->modeldata.type==TYPE_PLAYER)
19161 	{
19162 		control_rumble(self->opponent->playerindex, 75);
19163 	}
19164 	checkdamage(other, attack);
19165 	self->playerindex = other->playerindex;    // Added so points go to the correct player
19166 	addscore(other->playerindex, attack->attack_force*self->modeldata.multiple);    // Points can now be given for hitting an obstacle
19167 
19168 	if(self->health<=0){
19169 
19170 		checkdeath();
19171 
19172 		if(other->x < self->x) self->xdir = 1;
19173 		else self->xdir = -1;
19174 
19175 		self->attacking = 1;    // So obstacles can explode and hurt players/enemies
19176 
19177 		if(self->modeldata.subtype == SUBTYPE_FLYDIE){    // Now obstacles can fly like on Simpsons/TMNT
19178 			self->xdir *= 4;
19179 			self->think = obstacle_fly;
19180 			ent_set_anim(self, ANI_FALL, 0);
19181 		}
19182 		else{
19183 			self->think = obstacle_fall;
19184 
19185 			if(validanim(self,ANI_DIE)) ent_set_anim(self, ANI_DIE, 0);    //  LTB 1-13-05  Die before toss
19186 			else{
19187 				toss(self, self->modeldata.jumpheight/1.333);
19188 				ent_set_anim(self, ANI_FALL, 0);
19189 			}
19190 
19191 			if(!self->modeldata.nodieblink) self->blink = 1;
19192 		}
19193 	}
19194 
19195 	self->nextthink = time + 1;
19196 	return 1;
19197 }
19198 
19199 
smartspawn(s_spawn_entry * props)19200 entity * smartspawn(s_spawn_entry * props){   // 7-1-2005 Entire section replaced with lord balls code
19201 	entity *e = NULL;
19202 	entity* wp = NULL;
19203 	int playercount;
19204 
19205 	if(props == NULL || level == NULL) return NULL;
19206 
19207 	// Now you can make it so enemies/obstacles/etc only spawn if there are 2 players
19208 	if(props->spawnplayer_count >= (playercount = count_ents(TYPE_PLAYER))){
19209 		if(props->boss) --level->bosses;
19210 		return NULL;
19211 	}
19212 
19213 	if((level->scrolldir&SCROLL_INWARD) || (level->scrolldir&SCROLL_OUTWARD))
19214 		 e = spawn(props->x, props->z + advancey, props->a, props->flip, props->name, props->index, props->model);
19215 	else e = spawn(props->x + advancex, props->z, props->a, props->flip, props->name, props->index, props->model);
19216 
19217 
19218 	if(e == NULL) return NULL;
19219 
19220 	//printf("%s, (%f, %f, %f) - (%f, %f, %f)", props->name, props->x, props->z, props->a, e->x, e->z, e->a);
19221 
19222 	// Alias?
19223 	if(props->alias[0]) strncpy(e->name, props->alias, MAX_NAME_LEN);
19224 	if(props->item) e->item = props->itemindex;
19225 	if(props->itemalias[0]) strncpy(e->itemalias, props->itemalias, MAX_NAME_LEN);
19226 	if(props->itemmap) e->itemmap = props->itemmap;
19227 	if(props->itemhealth) e->itemhealth = props->itemhealth;
19228 	e->itemplayer_count = props->itemplayer_count;
19229 
19230 	if(props->spawntype) e->spawntype = props->spawntype;   //2011_03_23, Pass spawntype.
19231 
19232 	if(props->health[playercount-1] != 0){
19233 		e->health = e->modeldata.health = props->health[playercount-1];
19234 	}
19235 
19236 	if(props->mp != 0){
19237 		e->mp = e->modeldata.mp = props->mp;
19238 	}
19239 
19240 	if(props->score != 0) e->modeldata.score = props->score;    // Overwrite score if exists in the level's. txt file
19241 	if(props->multiple != 0)e->modeldata.multiple = props->multiple;    // Overwrite multiple if exists in the level's .txt file
19242 
19243 	if(!e->map && props->colourmap)
19244 	{
19245 		ent_set_colourmap(e, props->colourmap);
19246 	}
19247 
19248 	if(props->aggression) e->modeldata.aggression = props->aggression;  // Aggression can be changed with spawn points now
19249 	if(props->itemtrans) e->itemtrans = props->itemtrans;
19250 	if(props->alpha) e->modeldata.alpha = props->alpha;
19251 
19252 	// Feb 26, 2005 - Store the original map to be able to restore with dying flash
19253 	if(props->dying){
19254 		e->dying = props->dying;    // Feb 26, 2005 - Used to define which colourmap is used for the dying flash
19255 		e->per1 = props->per1;    // Mar 21, 2005 - Used to store custom percentages
19256 		e->per2 = props->per2;    // Mar 21, 2005 - Used to store custom percentages
19257 	}
19258 
19259 	if(props->nolife) e->modeldata.nolife = props->nolife;    // Overwrite whether live is visible or not
19260 	e->boss = props->boss;
19261 
19262 	if(props->boss && level && level->bossmusic[0])
19263 	{
19264 		music(level->bossmusic, 1, level->bossmusic_offset);
19265 	}
19266 
19267 	// give the entity a weapon item
19268 	if(props->weapon)
19269 	{
19270 		wp = spawn(e->x, 100000, 0, 0, props->weapon, props->weaponindex, props->weaponmodel);
19271 		if(wp){
19272 			//ent_default_init(wp);
19273 			set_weapon(e, wp->modeldata.weapnum, 0);
19274 			e->weapent = wp;
19275 		}
19276 	}
19277 
19278 	//ent_default_init(e);
19279 	execute_onspawn_script(e);
19280 	execute_spawn_script(props, e);
19281 	return e;
19282 }   // 7-1-2005 replaced section ends here
19283 
19284 
19285 
spawnplayer(int index)19286 void spawnplayer(int index)
19287 {
19288 	s_spawn_entry p;
19289 	//s_model * model = NULL;
19290 	int wall;
19291 	int xc, zc, find = 0;
19292 	index &= 3;
19293 
19294 //    model = find_model(player[index].name);
19295 //    if(model == NULL) return;
19296 
19297 	memset(&p, 0, sizeof(s_spawn_entry));
19298 	p.name= player[index].name;
19299 	p.index = -1;
19300 	p.itemindex = -1;
19301 	p.weaponindex = -1;
19302 	p.colourmap = player[index].colourmap;
19303 	p.spawnplayer_count = -1;
19304 
19305 	if(level->scrolldir&SCROLL_LEFT){
19306 		if(level->spawn[index][0]) p.x = (float)(videomodes.hRes - level->spawn[index][0]);
19307 		else p.x = (float)((videomodes.hRes-20) - 30*index);
19308 	}
19309 	else{
19310 		if(level->spawn[index][0]) p.x = (float)(level->spawn[index][0]);
19311 		else p.x = (float)(20 + 30*index);
19312 		p.flip = 1;
19313 	}
19314 	if(level->spawn[index][1]){
19315 		if(level->scrolldir&(SCROLL_INWARD|SCROLL_OUTWARD))
19316 			p.z = (float)(level->spawn[index][1]);
19317 		else p.z = (float)(PLAYER_MIN_Z + level->spawn[index][1]);
19318 	}
19319 	else if(PLAYER_MAX_Z - PLAYER_MIN_Z > 5) p.z = (float)(PLAYER_MIN_Z + 5);
19320 	else p.z = (float)PLAYER_MIN_Z;
19321 	//////////////////checking holes/ walls///////////////////////////////////
19322 	for(xc = 0; xc < videomodes.hRes / 4; xc++){
19323 		if(p.x > videomodes.hRes) p.x -= videomodes.hRes;
19324 		if(p.x < 0) p.x += videomodes.hRes;
19325 		if(PLAYER_MIN_Z==PLAYER_MAX_Z)
19326 		{
19327 			wall = checkwall(advancex + p.x, p.z);
19328 			if(wall >= 0 && level->walls[wall][7] < MAX_WALL_HEIGHT) break; //found
19329 			if(checkhole(advancex + p.x, p.z) || (wall>=0 && level->walls[wall][7] >= MAX_WALL_HEIGHT)) find = 0;
19330 			else break; // found
19331 		}
19332 		else for(zc=0;zc < (PLAYER_MAX_Z - PLAYER_MIN_Z) / 3; zc++, p.z += 3){
19333 			if(p.z > PLAYER_MAX_Z) p.z -= PLAYER_MAX_Z - PLAYER_MIN_Z;
19334 			if(p.z < PLAYER_MIN_Z) p.z += PLAYER_MAX_Z - PLAYER_MIN_Z;
19335 			wall = checkwall(advancex + p.x, p.z);
19336 			if(wall >= 0 && level->walls[wall][7] < MAX_WALL_HEIGHT) {find = 1; break;}
19337 			else if(wall >=0 && level->walls[wall][7] >= MAX_WALL_HEIGHT) continue;
19338 			if(checkhole(advancex + p.x, p.z)) continue;
19339 			find = 1;
19340 			break;
19341 		}
19342 		if(find) break;
19343 		p.x += (level->scrolldir&SCROLL_LEFT)?-4:4;
19344 	}
19345 	///////////////////////////////////////////////////////////////////////
19346 	currentspawnplayer = index;
19347 	player[index].ent = smartspawn(&p);
19348 
19349 	if(player[index].ent==NULL) shutdown(1, "Fatal: unable to spawn player from '%s'", &p.name);
19350 
19351 	player[index].ent->playerindex = index;
19352 	if(nomaxrushreset[4] >= 1) player[index].ent->rush[1] = nomaxrushreset[index];
19353 	else player[index].ent->rush[1] = 0;
19354 
19355 	if(player[index].spawnhealth) player[index].ent->health = player[index].spawnhealth + 5;
19356 	if(player[index].ent->health > player[index].ent->modeldata.health) player[index].ent->health = player[index].ent->modeldata.health;
19357 
19358 	//mp little recorver after a level by tails
19359 	if(player[index].spawnmp) player[index].ent->mp = player[index].spawnmp + 2;
19360 	if(player[index].ent->mp > player[index].ent->modeldata.mp) player[index].ent->mp = player[index].ent->modeldata.mp;
19361 
19362 	if(player[index].weapnum) set_weapon(player[index].ent, player[index].weapnum, 0);
19363 	else set_weapon(player[index].ent, level->setweap, 0);
19364 }
19365 
19366 
19367 
19368 
19369 
time_over()19370 void time_over()
19371 {
19372 	int i;
19373 	s_attack attack;
19374 
19375 	attack = emptyattack;
19376 	attack.attack_type = max_attack_types;
19377 	attack.dropv[0] = (float)3; attack.dropv[1] = (float)1.2; attack.dropv[2] = (float)0;
19378 	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
19379 	else if(!level_completed)
19380 	{
19381 		endgame = 1;
19382 		for(i=0; i<4; i++)
19383 		{
19384 			if(player[i].ent)
19385 			{
19386 				endgame = 0;
19387 				self = player[i].ent;
19388 				attack.attack_force = self->health;
19389 				self->takedamage(self, &attack);
19390 			}
19391 		}
19392 
19393 		if(SAMPLE_TIMEOVER >= 0) sound_play_sample(SAMPLE_TIMEOVER, 0, savedata.effectvol,savedata.effectvol, 100);
19394 
19395 		timeleft = level->settime * COUNTER_SPEED;    // Feb 24, 2005 - This line moved here to set custom time
19396 		if(!endgame)showtimeover = 1;
19397 	}
19398 }
19399 
19400 
19401 // ----------------------- Update functions ------------------------------
19402 
update_scroller()19403 void update_scroller(){
19404 	float to=0;
19405 	int i, againstend = 0;
19406 	int numplay=0; //4player
19407 	float tx = advancex, ty = advancey;
19408 	static int scrolladd = 0;
19409 	scrolldx = scrolldy = 0;
19410 
19411 	if(time < level->advancetime || freezeall) return;    // Added freezeall so backgrounds/scrolling don't update if animations are frozen
19412 
19413 /*
19414 	//level->advancetime = time + (GAME_SPEED/100);    // Changed so scrolling speeds up for faster players
19415 	level->advancetime = time  -
19416 		((player[0].ent && (player[0].ent->modeldata.speed >= 12 || player[0].ent->modeldata.runspeed >= 12)) ||
19417 		 (player[1].ent && (player[1].ent->modeldata.speed >= 12 || player[1].ent->modeldata.runspeed >= 12)) ||
19418 		 (player[2].ent && (player[2].ent->modeldata.speed >= 12 || player[2].ent->modeldata.runspeed >= 12)) ||
19419 		 (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*/
19420 
19421 	level->advancetime = time;
19422 
19423 	if(level_completed) return;
19424 
19425 	if(current_spawn>=level->numspawns && !findent(TYPE_ENEMY) &&
19426 	((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))
19427 	){
19428 		if(!findent(TYPE_ENDLEVEL) && ((!findent(TYPE_ITEM) && !findent(TYPE_OBSTACLE) && level->type) || level->type != 1)){    // Feb 25, 2005 - Added so obstacles
19429 			level_completed = 1;                                                // can be used for bonus levels
19430 		}
19431 	}
19432 	else if(count_ents(TYPE_ENEMY) < groupmin){
19433 		while(count_ents(TYPE_ENEMY) < groupmax &&
19434 			current_spawn<level->numspawns &&
19435 			level->pos >= level->spawnpoints[current_spawn].at
19436 			){
19437 				if(level->spawnpoints[current_spawn].musicfade){
19438 					musicfade[0] = (float)level->spawnpoints[current_spawn].musicfade;
19439 					musicfade[1] = (float)savedata.musicvol;
19440 				}
19441 				else if(level->spawnpoints[current_spawn].music[0]){
19442 					strncpy(musicname, level->spawnpoints[current_spawn].music, 128);
19443 					musicoffset = level->spawnpoints[current_spawn].musicoffset;
19444 					musicloop = 1;
19445 				}
19446 				else if(level->spawnpoints[current_spawn].wait){
19447 					level->waiting = 1;
19448 					go_time = 0;
19449 				}
19450 				else if(level->spawnpoints[current_spawn].groupmin || level->spawnpoints[current_spawn].groupmax){
19451 					groupmin = level->spawnpoints[current_spawn].groupmin;
19452 					groupmax = level->spawnpoints[current_spawn].groupmax;
19453 				}
19454 				else if(level->spawnpoints[current_spawn].nojoin!=0){
19455 					nojoin = (level->spawnpoints[current_spawn].nojoin==1);
19456 				}
19457 				else if(level->spawnpoints[current_spawn].scrollminz ||
19458 					level->spawnpoints[current_spawn].scrollmaxz){
19459 						scrollminz = (float)level->spawnpoints[current_spawn].scrollminz;
19460 						scrollmaxz = (float)level->spawnpoints[current_spawn].scrollmaxz;
19461 						if(!time) advancey = scrollminz; // reset y if spawn at very beginning
19462 					}
19463 				else if(level->spawnpoints[current_spawn].blockade){
19464 					// assume level spawn entry will not roll back, so just change it to 0 here
19465 					if(level->spawnpoints[current_spawn].blockade<0) level->spawnpoints[current_spawn].blockade = 0;
19466 					blockade = (float)level->spawnpoints[current_spawn].blockade;
19467 				}
19468 				else if(level->spawnpoints[current_spawn].palette!=0){
19469 					// assume level spawn entry will not roll back, so just change it to 0 here
19470 					if(level->spawnpoints[current_spawn].palette<0) level->spawnpoints[current_spawn].palette = 0;
19471 					change_system_palette(level->spawnpoints[current_spawn].palette);
19472 				}
19473 				else if(level->spawnpoints[current_spawn].light[1]){ // change light direction for gfxshadow
19474 					light[0] = level->spawnpoints[current_spawn].light[0];
19475 					light[1] = level->spawnpoints[current_spawn].light[1];
19476 				}
19477 				else if(level->spawnpoints[current_spawn].shadowcolor){ // change color for gfxshadow
19478 					shadowcolor = level->spawnpoints[current_spawn].shadowcolor;
19479 					if(shadowcolor==-1) shadowcolor = 0;
19480 					else if(shadowcolor==-2) shadowcolor = -1;
19481 				}
19482 				else if(level->spawnpoints[current_spawn].shadowalpha){ // change color for gfxshadow
19483 					shadowalpha = level->spawnpoints[current_spawn].shadowalpha;
19484 					if(shadowalpha==-1) shadowalpha = 0;
19485 				}
19486 				else smartspawn(&level->spawnpoints[current_spawn]);
19487 				++current_spawn;
19488 			}
19489 	}
19490 
19491 	for(i=0; i<maxplayers[current_set]; i++)
19492 	{
19493 		if(player[i].ent) numplay++;
19494 	}
19495 
19496 	if(level->waiting){
19497 		// Wait for all enemies to be defeated
19498 		if(!findent(TYPE_ENEMY))
19499 		{
19500 			level->waiting = 0;
19501 			if(level->noreset<=1) timeleft = level->settime * COUNTER_SPEED;    // Feb 24, 2005 - This line moved here to set custom time
19502 			go_time = time + 3*GAME_SPEED;
19503 		}
19504 	}
19505 	if(numplay == 0) return;
19506 
19507 
19508 
19509 	if(!level->waiting)
19510 	{
19511 		if(level->scrolldir&SCROLL_RIGHT){
19512 
19513 			againstend = (level->width<=videomodes.hRes);
19514 
19515 			for(i=0; i<maxplayers[current_set]; i++)
19516 			{
19517 				if(player[i].ent)
19518 				{
19519 					to += (int)player[i].ent->x;
19520 				}
19521 			}
19522 
19523 			to /= numplay;
19524 			to -= (videomodes.hRes/2);
19525 
19526 			to += level->cameraxoffset;
19527 
19528 			if((level->scrolldir&SCROLL_BACK) && to < blockade) to = blockade;
19529 
19530 			if(to > advancex){
19531 				if(to > advancex+level->scrollspeed) to = advancex+level->scrollspeed;
19532 				advancex = (float)to;
19533 			}
19534 
19535 			if(level->scrolldir&SCROLL_BACK){    // Can't go back to the beginning
19536 
19537 				if(to < advancex && to > blockade){
19538 					if(to < advancex-level->scrollspeed) to = advancex-level->scrollspeed;
19539 					advancex = (float)to;
19540 				}
19541 			}
19542 
19543 			if(advancex < 0) advancex = 0;
19544 			if(advancex > level->width-videomodes.hRes) {
19545 				advancex = (float)level->width-videomodes.hRes;
19546 				againstend = 1;
19547 			}
19548 
19549 			if(againstend) level->pos++;
19550 			else level->pos = (int)advancex;
19551 
19552 
19553 		}
19554 		else if(level->scrolldir&SCROLL_LEFT){
19555 
19556 			againstend = (level->width<=videomodes.hRes);
19557 
19558 			for(i=0; i<maxplayers[current_set]; i++)
19559 			{
19560 				if(player[i].ent)
19561 				{
19562 					to += (int)player[i].ent->x;
19563 				}
19564 			}
19565 
19566 			to /= numplay;
19567 			to -= (videomodes.hRes/2);
19568 
19569 			to += level->cameraxoffset;
19570 
19571 			if(to < advancex){
19572 				if(to < advancex-level->scrollspeed) {
19573 					to = advancex-level->scrollspeed;
19574 					againstend = 1;
19575 				}
19576 				advancex = (float)to;
19577 			}
19578 			if(level->scrolldir&SCROLL_BACK){    // Can't go back to the beginning
19579 
19580 				if(to > advancex){
19581 					if(to > advancex+level->scrollspeed) to = advancex+level->scrollspeed;
19582 					advancex = (float)to;
19583 				}
19584 			}
19585 			if(advancex > level->width-videomodes.hRes) advancex = (float)level->width-videomodes.hRes;
19586 			if((level->scrolldir&SCROLL_BACK) && level->width- videomodes.hRes - advancex < blockade) advancex = level->width- videomodes.hRes - blockade;
19587 			if(advancex < 0) advancex = 0;
19588 
19589 			if(againstend) level->pos++;
19590 			else level->pos = (int)((level->width-videomodes.hRes) - advancex);
19591 		}
19592 		else if(level->scrolldir&SCROLL_OUTWARD){ // z scroll only
19593 
19594 			for(i=0; i<maxplayers[current_set]; i++)
19595 			{
19596 				if(player[i].ent)
19597 				{
19598 					to += (int)player[i].ent->z;
19599 				}
19600 			}
19601 
19602 			to /= numplay;
19603 			to -= (videomodes.vRes/2);
19604 
19605 			to += level->cameraxoffset;
19606 
19607 			if(to > advancey){
19608 				if(to > advancey+level->scrollspeed) to = advancey+level->scrollspeed;
19609 				advancey = (float)to;
19610 			}
19611 
19612 			if(level->scrolldir&SCROLL_BACK){    // Can't go back to the beginning
19613 
19614 				if(to < advancey){
19615 					if(to < advancey-level->scrollspeed) to = advancey-level->scrollspeed;
19616 					advancey = (float)to;
19617 				}
19618 			}
19619 
19620 			if(advancey > panel_height-videomodes.vRes) {
19621 				advancey = (float)panel_height-videomodes.vRes;
19622 				againstend = 1;
19623 			}
19624 
19625 			if((level->scrolldir&SCROLL_BACK) && advancey < blockade) advancey = blockade;
19626 			if(advancey < 4) advancey = 4;
19627 
19628 			if(againstend) level->pos++;
19629 			else level->pos = (int)advancey;
19630 		}
19631 		else if(level->scrolldir&SCROLL_INWARD){
19632 			for(i=0; i<maxplayers[current_set]; i++)
19633 			{
19634 				if(player[i].ent)
19635 				{
19636 					to += (int)player[i].ent->z;
19637 				}
19638 			}
19639 
19640 			to /= numplay;
19641 			to -= (videomodes.vRes/2);
19642 
19643 			to += level->camerazoffset;
19644 
19645 			if(to < advancey){
19646 				if(to < advancey-level->scrollspeed){
19647 					to = advancey-level->scrollspeed;
19648 					againstend = 1;
19649 				}
19650 				advancey = (float)to;
19651 			}
19652 			if(level->scrolldir&SCROLL_BACK){    // Can't go back to the beginning
19653 
19654 				if(to > advancey){
19655 					if(to > advancey+level->scrollspeed) to = advancey+level->scrollspeed;
19656 					advancey = (float)to;
19657 				}
19658 			}
19659 			if(advancey > panel_height-videomodes.vRes) advancey = (float)panel_height-videomodes.vRes;
19660 			if((level->scrolldir&SCROLL_BACK) && panel_height- videomodes.vRes - advancey < blockade) advancey = panel_height- videomodes.vRes - blockade;
19661 			if(advancey < 4) advancey = 4;
19662 
19663 			if(againstend) level->pos++;
19664 			else level->pos = (int)((panel_height-videomodes.vRes) - advancey);
19665 		}
19666 		//up down, elevator stage
19667 		else if(level->scrolldir&(SCROLL_UP|SCROLL_DOWN))
19668 		{
19669 			//advancey += 0.5;
19670 			if(scrolladd==1)
19671 			{
19672 				scrolladd=0;
19673 				advancey++;
19674 			}
19675 			else
19676 			{
19677 				scrolladd++;
19678 			}
19679 			level->pos = (int)advancey;
19680 		}
19681 	}//if(!level->waiting)
19682 
19683 	// z auto-scroll, 2007 - 2 - 10 by UTunnels
19684 	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
19685 	{
19686 		for(i=0, to=0; i<maxplayers[current_set]; i++)
19687 		{
19688 			if(player[i].ent)
19689 			{
19690 				to += (int)(player[i].ent->z - (cameratype==1?player[i].ent->a:0));
19691 			}
19692 		}
19693 
19694 		to /= numplay;
19695 		to -= (videomodes.vRes/2);
19696 
19697 		to += level->camerazoffset;
19698 
19699 		// new scroll limit
19700 		if(scrollmaxz && to > scrollmaxz) to = scrollmaxz;
19701 		if(scrollminz && to < scrollminz) to = scrollminz;
19702 
19703 		if(to > advancey){
19704 			if(to > advancey+level->scrollspeed) to = advancey+level->scrollspeed;
19705 			advancey = (float)to;
19706 		}
19707 
19708 		if(to < advancey){
19709 			if(to < advancey-level->scrollspeed) to = advancey-level->scrollspeed;
19710 			advancey = (float)to;
19711 		}
19712 
19713 		if(advancey > panel_height - 16 -videomodes.vRes) advancey = (float)(panel_height - 16 -videomodes.vRes);
19714 		if(advancey < 4) advancey = 4;
19715 	}
19716 	// now x auto scroll
19717 	else if((level->scrolldir&SCROLL_INWARD) || (level->scrolldir&SCROLL_OUTWARD))
19718 	{
19719 		for(i=0, to=0; i<maxplayers[current_set]; i++)
19720 		{
19721 			if(player[i].ent)
19722 			{
19723 				to += (int)player[i].ent->x;
19724 			}
19725 		}
19726 
19727 		to /= numplay;
19728 		to -= (videomodes.hRes/2);
19729 
19730 		to += level->cameraxoffset;
19731 
19732 		// new scroll limit
19733 		if(scrollmaxz && to > scrollmaxz) to = scrollmaxz;
19734 		if(scrollminz && to < scrollminz) to = scrollminz;
19735 
19736 		if(to > advancex){
19737 			if(to > advancex+level->scrollspeed) to = advancex+level->scrollspeed;
19738 			advancex = (float)to;
19739 		}
19740 
19741 		if(to < advancex){
19742 			if(to < advancex-level->scrollspeed) to = advancex-level->scrollspeed;
19743 			advancex = (float)to;
19744 		}
19745 
19746 		if(advancex > level->width - videomodes.hRes) advancex = (float)(level->width - videomodes.hRes);
19747 		if(advancex < 0) advancex = 0;
19748 	}
19749 	//end of z auto-scroll
19750 	// global value for type_panel
19751 	scrolldx = advancex - tx;
19752 	scrolldy = advancey - ty;
19753 }
19754 
19755 
applybglayers(s_screen * pbgscreen)19756 void applybglayers(s_screen* pbgscreen)
19757 {
19758 	int index, x, z, i, j, k, l, timevar;
19759 	s_bglayer* bglayer;
19760 	float rocktravel;
19761 	int width, height;
19762 	s_drawmethod screenmethod;
19763 
19764 	if(!textbox){
19765 		rocktravel = (level->rocking)?((time-traveltime)/((float)GAME_SPEED/30)):0; // no like in real life, maybe
19766 		if(level->bgspeed<0) rocktravel = -rocktravel;
19767 		bgtravelled += (time-traveltime)*level->bgspeed/30*4 + rocktravel;
19768 	}else texttime += time-traveltime;
19769 
19770 	timevar = time - texttime;
19771 
19772 	for(index = 0; index < level->numbglayers; index++)
19773 	{
19774 		bglayer = level->bglayers+index;
19775 
19776 
19777 		if(!bglayer->xrepeat || !bglayer->zrepeat || !bglayer->enabled) continue;
19778 
19779 		width = bglayer->width + bglayer->xspacing;
19780 		height = bglayer->height + bglayer->zspacing;
19781 
19782 		x = (int)(bglayer->xoffset + (advancex)*(bglayer->xratio) - advancex - bgtravelled * (1-bglayer->xratio) * bglayer->bgspeedratio);
19783 
19784 		if(level->scrolldir&SCROLL_UP)
19785 			z = (int)(4 + videomodes.vRes + (advancey+4)*bglayer->zratio - bglayer->zoffset - height*bglayer->zrepeat + height + bglayer->zspacing);
19786 		else
19787 			z = (int)(4 + bglayer->zoffset + (advancey-4)* bglayer->zratio - advancey);
19788 
19789 		if(x<0) {
19790 			i = (-x)/width;
19791 			x %= width;
19792 		} else i = 0;
19793 
19794 		if(z<0){
19795 			j = (-z)/height;
19796 			z %= height;
19797 		} else j = 0;
19798 
19799 		screenmethod=bglayer->drawmethod;
19800 		screenmethod.table = (pixelformat==PIXEL_x8)?(current_palette>0?(level->palettes[current_palette-1]):NULL):NULL;
19801 		screenmethod.water.wavetime =  (int)(timevar*screenmethod.water.wavespeed);
19802 		for(; j<bglayer->zrepeat && z<videomodes.vRes; z+=height, j++)
19803 		{
19804 			for(k=i, l=x; k<bglayer->xrepeat && l<videomodes.hRes + (screenmethod.water.watermode==3?0:screenmethod.water.amplitude*2); l+=width, k++)
19805 			{
19806 				if(bglayer->type==bg_screen)
19807 					 putscreen(pbgscreen, bglayer->screen, l, z, &screenmethod);
19808 				else if(bglayer->type==bg_sprite)
19809 					putsprite(l, z, bglayer->sprite, pbgscreen, &screenmethod);
19810 
19811 				//printf("#%d %d %d %d\n", index, l, z, width);
19812 
19813 			}
19814 		}
19815 	}
19816 
19817 	//printf("**************\n");
19818 	traveltime = time;
19819 }
19820 
applyfglayers(s_screen * pbgscreen)19821 void applyfglayers(s_screen* pbgscreen)
19822 {
19823 	int index, x, z, i, j, k, l, timevar;
19824 	s_fglayer* fglayer;
19825 	int width, height;
19826 	s_drawmethod screenmethod;
19827 
19828 	timevar = time - texttime;
19829 
19830 	for(index = 0; index < level->numfglayers; index++)
19831 	{
19832 		fglayer = level->fglayers+index;
19833 
19834 
19835 		if(!fglayer->xrepeat || !fglayer->zrepeat || !fglayer->enabled) continue;
19836 
19837 		width = fglayer->width + fglayer->xspacing;
19838 		height = fglayer->height + fglayer->zspacing;
19839 
19840 		x = (int)(fglayer->xoffset + (advancex)*(fglayer->xratio) - advancex - bgtravelled * (1-fglayer->xratio) * fglayer->bgspeedratio);
19841 
19842 		if(level->scrolldir&SCROLL_UP)
19843 			z = (int)(4 + videomodes.vRes + (advancey+4)*fglayer->zratio - fglayer->zoffset - height*fglayer->zrepeat + height + fglayer->zspacing);
19844 		else
19845 			z = (int)(4 + fglayer->zoffset + (advancey-4)* fglayer->zratio - advancey);
19846 
19847 		if(x<0) {
19848 			i = (-x)/width;
19849 			x %= width;
19850 		} else i = 0;
19851 
19852 		if(z<0){
19853 			j = (-z)/height;
19854 			z %= height;
19855 		} else j = 0;
19856 
19857 		screenmethod=fglayer->drawmethod;
19858 		screenmethod.table = (pixelformat==PIXEL_x8)?(current_palette>0?(level->palettes[current_palette-1]):NULL):NULL;
19859 		screenmethod.water.wavetime =  (int)(timevar*screenmethod.water.wavespeed);
19860 		for(; j<fglayer->zrepeat && z<videomodes.vRes; z+=height, j++)
19861 		{
19862 			for(k=i, l=x; k<fglayer->xrepeat && l<videomodes.hRes + (screenmethod.water.watermode==3?0:screenmethod.water.amplitude*2); l+=width, k++)
19863 			{
19864 				if(fglayer->type==fg_screen)
19865 					 spriteq_add_screen(l, z, FRONTPANEL_Z + fglayer->z, fglayer->screen, &screenmethod, 0);
19866 				else if(fglayer->type==fg_sprite)
19867 					spriteq_add_frame(l, z, FRONTPANEL_Z + fglayer->z, fglayer->sprite, &screenmethod, 0);
19868 
19869 			}
19870 		}
19871 	}
19872 }
19873 
19874 
19875 
19876 
draw_scrolled_bg()19877 void draw_scrolled_bg(){
19878 	int i = 0;
19879 	int inta ;
19880 	int poop = 0;
19881 	int index = 0;
19882 	int fix_y = 0;
19883 	unsigned char neonp[32];//3*8
19884 	static float oldadvx=0, oldadvy=0;
19885 	static int   oldpal = 0;
19886 	static int neon_count = 0;
19887 	static int rockpos = 0;
19888 	static int rockoffssine[32] = {
19889 		2, 2, 3, 4, 5, 6, 7, 7,
19890 			8, 8, 9, 9, 9, 9, 8, 8,
19891 			7, 7, 6, 5, 4, 3, 2, 2,
19892 			1, 1, 0, 0, 0, 0, 1, 1
19893 	};   // normal rock
19894 	static int rockoffsshake[32] = {
19895 		2, 2, 2, 2, 2, 2, 2, 2,
19896 			2, 2, 0, 4, 2, 0, 4, 2,
19897 			2, 2, 2, 2, 2, 2, 2, 2,
19898 			2, 2, 0, 4, 2, 0, 4, 2,
19899 	};   // slow, constant jarring rock, like on a train
19900 	static int rockoffsrumble[32] = {
19901 		2, 2, 3, 3, 2, 2, 3, 3,
19902 			2, 2, 3, 3, 2, 3, 2, 3,
19903 			2, 2, 3, 3, 2, 2, 3, 3,
19904 			2, 2, 3, 3, 2, 3, 2, 3,
19905 	};   // fast, constant rumbling, like in/on a van or trailer
19906 	s_screen*  pbgscreen;
19907 	s_drawmethod screenmethod=plainmethod, *pscreenmethod=&screenmethod;
19908 	int pb = pixelbytes[(int)screenformat];
19909 
19910 	if(pixelformat==PIXEL_x8)
19911 	{
19912 		screenmethod.table = current_palette? level->palettes[current_palette-1]: NULL;
19913 	}
19914 
19915 
19916 	if(bgbuffer)
19917 	{
19918 			if(((level->rocking || level->bgspeed)&& !pause) ||
19919 			   oldadvx!=advancex || oldadvy != advancey || current_palette!=oldpal)
19920 					bgbuffer_updated = 0;
19921 			else {
19922 					// temporary fix for bglayer water
19923 					for(i=0; i<level->numbglayers; i++){
19924 							if(level->bglayers[i].drawmethod.water.watermode){
19925 									bgbuffer_updated = 0;
19926 									break;
19927 							}
19928 					}
19929 			}
19930 			oldadvx = advancex;
19931 			oldadvy = advancey;
19932 			oldpal = current_palette;
19933 	}
19934 	else bgbuffer_updated = 0;
19935 
19936 	if(bgbuffer)  pbgscreen = bgbuffer_updated?vscreen:bgbuffer;
19937 	else          pbgscreen = vscreen;
19938 
19939 	if(!bgbuffer_updated && level->numbglayers>0)
19940 	{
19941 		clearscreen(pbgscreen);
19942 		applybglayers(pbgscreen);
19943 	}
19944 
19945 	applyfglayers(pbgscreen);
19946 
19947 	pscreenmethod->alpha = 0;
19948 	pscreenmethod->transbg = 0;
19949 
19950 	if(bgbuffer)
19951 	{
19952 		putscreen(vscreen, bgbuffer, 0, 0, NULL);
19953 	}
19954 
19955 	bgbuffer_updated = 1;
19956 
19957 	if(level->rocking){
19958 		rockpos = (time/(GAME_SPEED/8)) & 31;
19959 		if(level->rocking == 1)         gfx_y_offset = level->quake - 4 - rockoffssine[rockpos];
19960 		else if(level->rocking == 2) gfx_y_offset = level->quake - 4 - rockoffsshake[rockpos];
19961 		else if(level->rocking == 3) gfx_y_offset = level->quake - 4 - rockoffsrumble[rockpos];
19962 	}
19963 	else if(time){
19964 		if(level->quake >= 0) gfx_y_offset = level->quake - 4;
19965 		else           gfx_y_offset = level->quake + 4;
19966 	}
19967 
19968 	gfx_y_offset += gfx_y_offset_adj;   //2011_04_03, DC: Apply modder adjustment.
19969 
19970 	if(level->scrolldir!=SCROLL_UP && level->scrolldir!=SCROLL_DOWN) gfx_y_offset -= (int)(advancey - 4);
19971 
19972 	// Draw 3 layers: screen, normal and neon
19973 	if(panels_loaded && panel_width){
19974 		if(time>=neon_time && !freezeall){    // Added freezeall so neon lights don't update if animations are frozen
19975 			if(pixelformat==PIXEL_8) // under 8bit mode just cycle the palette from 128 to 135
19976 			{
19977 				for(i=0; i<8; i++)  neontable[128+i] = 128 + ((i+neon_count) & 7);
19978 			}
19979 			else if(pixelformat==PIXEL_x8) // copy palette under 24bit mode
19980 			{
19981 				if(pscreenmethod->table)
19982 				{
19983 					memcpy(neonp, pscreenmethod->table+128*pb, 8*pb);
19984 					memcpy(pscreenmethod->table+128*pb, neonp+2*pb, 6*pb);
19985 					memcpy(pscreenmethod->table+(128+6)*pb, neonp, 2*pb);
19986 				}
19987 				else
19988 				{
19989 					memcpy(neonp, neontable+128*pb, 8*pb);
19990 					memcpy(neontable+128*pb, neonp+2*pb, 6*pb);
19991 					memcpy(neontable+(128+6)*pb, neonp, 2*pb);
19992 				}
19993 			}
19994 			neon_time = time + (GAME_SPEED/3);
19995 			neon_count += 2;
19996 		}
19997 
19998 		if(level->scrolldir==SCROLL_UP || level->scrolldir==SCROLL_DOWN) inta = 0;
19999 		else inta = (int)advancex;
20000 
20001 		poop = inta / panel_width;
20002 		inta %= panel_width;
20003 		for(i=-inta; i<=videomodes.hRes && poop>=0 && poop<level->numpanels; i+=panel_width){
20004 			index = level->order[poop];
20005 			pscreenmethod->table = (pixelformat==PIXEL_x8 && current_palette)?level->palettes[current_palette-1]:NULL;
20006 			if(panels[index].sprite_normal)
20007 			{
20008 				pscreenmethod->alpha = 0;
20009 				spriteq_add_frame(i+gfx_x_offset,gfx_y_offset, PANEL_Z, panels[index].sprite_normal, pscreenmethod, 0);
20010 			}
20011 			if(panels[index].sprite_neon)
20012 			{
20013 				if(pixelformat!=PIXEL_x8 || current_palette<=0)
20014 					pscreenmethod->table = neontable;
20015 				spriteq_add_frame(i+gfx_x_offset,gfx_y_offset, NEONPANEL_Z, panels[index].sprite_neon, pscreenmethod, 0);
20016 			}
20017 			if(panels[index].sprite_screen)
20018 			{
20019 				pscreenmethod->alpha = BLEND_SCREEN+1;
20020 				spriteq_add_frame(i+gfx_x_offset,gfx_y_offset, SCREENPANEL_Z, panels[index].sprite_screen, pscreenmethod, 0);
20021 			}
20022 			poop++;
20023 		}
20024 	}
20025 
20026 	pscreenmethod->alpha = 0;
20027 
20028 	for(i=0; i<level->numholes; i++) spriteq_add_sprite((int)(level->holes[i][0]-advancex+gfx_x_offset),(int)(level->holes[i][1] - level->holes[i][6] + 4 + gfx_y_offset), HOLE_Z, holesprite, pscreenmethod, 0);
20029 
20030 	if(frontpanels_loaded){
20031 
20032 		if(level->scrolldir==SCROLL_UP || level->scrolldir==SCROLL_DOWN) inta = 0;
20033 		else{
20034 			inta = (int)(advancex * 1.4);
20035 			fix_y = (int)(advancey - 4);
20036 		}
20037 		poop = inta / frontpanels[0]->width;
20038 		inta %= frontpanels[0]->width;
20039 		for(i=-inta; i<=videomodes.hRes; i+=frontpanels[0]->width){
20040 			poop %= frontpanels_loaded;
20041 			spriteq_add_frame(i+gfx_x_offset,gfx_y_offset + fix_y, FRONTPANEL_Z, frontpanels[poop], pscreenmethod, 0);
20042 			poop++;
20043 		}
20044 	}
20045 
20046 	if(level->quake!=0 && time>=level->quaketime){
20047 		level->quake /= 2;
20048 		level->quaketime = time + (GAME_SPEED/25);
20049 	}
20050 }
20051 
20052 #ifndef DISABLE_MOVIE
movie_openfile(int save)20053 void movie_openfile(int save)
20054 {
20055 	char path[256] = {""};
20056 	char tmpname[256] = {""};
20057 	moviebuffer = malloc(sizeof(*moviebuffer)*MOVIEBUF_LEN);
20058 	if(!moviebuffer) return ;
20059 	memset(moviebuffer, 0, sizeof(*moviebuffer)*MOVIEBUF_LEN);
20060 	getBasePath(path, "Saves", 0);
20061 	getPakName(tmpname, 3);
20062 	strcat(path, tmpname);
20063 	if(save) moviefile = fopen(path, "wb");
20064 	else moviefile = fopen(path, "rb");
20065 	if(moviefile == NULL) return;
20066 	if(save)
20067 	{
20068 		movielog = 1;
20069 		movieplay = 0;
20070 		movieloglen = 0;
20071 		moviebufptr = 0;
20072 	}
20073 	else
20074 	{
20075 		fseek(moviefile, 0, SEEK_END);
20076 		movielen = ftell(moviefile);
20077 		movielen /= sizeof(*moviebuffer);
20078 		fseek(moviefile, 0, SEEK_SET);
20079 		movielog = 0;
20080 		movieplay = 1;
20081 		movieloglen = 0;
20082 		moviebufptr = MOVIEBUF_LEN;
20083 	}
20084 }
20085 
movie_flushbuf()20086 void movie_flushbuf()
20087 {
20088 	int disCcWarns;
20089 	if(!moviefile || !moviebuffer) return;
20090 	disCcWarns = fwrite(moviebuffer, sizeof(*moviebuffer), MOVIEBUF_LEN, moviefile);
20091 	memset(moviebuffer, 0, sizeof(*moviebuffer)*MOVIEBUF_LEN);
20092 	moviebufptr = 0;
20093 }
20094 
movie_closefile()20095 void movie_closefile()
20096 {
20097 	if(moviefile) fclose(moviefile);
20098 	if(moviebuffer) free(moviebuffer);
20099 	moviebuffer = NULL;
20100 	moviefile = NULL;
20101 	moviebufptr = 0;
20102 	movielog = 0;
20103 	movieplay = 0;
20104 }
20105 
movie_update(s_playercontrols ** pctrls)20106 void movie_update(s_playercontrols ** pctrls)
20107 {
20108 	int p;
20109 	int disCcWarns;
20110 	if(!moviefile || !moviebuffer) return;
20111 	if(moviebufptr==MOVIEBUF_LEN)
20112 	{
20113 		moviebufptr = 0;
20114 		if(movieloglen<=movielen)
20115 		{
20116 			disCcWarns = fread(moviebuffer, sizeof(*moviebuffer), MOVIEBUF_LEN, moviefile);
20117 			movieloglen += MOVIEBUF_LEN;
20118 		}
20119 		else
20120 		{
20121 			movie_closefile();
20122 			return;
20123 		}
20124 	}
20125 	for(p=0; p<4; p++)
20126 	{
20127 		playercontrolpointers[p]->keyflags = moviebuffer[moviebufptr][p][0];
20128 		playercontrolpointers[p]->newkeyflags = moviebuffer[moviebufptr][p][1];
20129 	}
20130 	seed = moviebuffer[moviebufptr][4][0];
20131 	interval = moviebuffer[moviebufptr][4][1];
20132 	moviebufptr++;
20133 }
20134 
movie_save(s_playercontrols ** pctrls)20135 void movie_save(s_playercontrols ** pctrls)
20136 {
20137 	int p;
20138 	if(!moviefile || !moviebuffer) return;
20139 	if(moviebufptr==MOVIEBUF_LEN)
20140 	{
20141 		movie_flushbuf();
20142 		movieloglen += MOVIEBUF_LEN;
20143 	}
20144 	for(p=0; p<4; p++)
20145 	{
20146 		moviebuffer[moviebufptr][p][0] = playercontrolpointers[p]->keyflags;
20147 		moviebuffer[moviebufptr][p][1] = playercontrolpointers[p]->newkeyflags;
20148 	}
20149 	moviebuffer[moviebufptr][4][0] = seed;
20150 	moviebuffer[moviebufptr][4][1] = interval;
20151 	moviebufptr++;
20152 }
20153 
20154 #endif
20155 
20156 
inputrefresh()20157 void inputrefresh()
20158 {
20159 	int p;
20160 
20161 #ifndef DISABLE_MOVIE
20162 	int moviestop = 0;
20163 	if(movieplay)
20164 	{
20165 		control_update(playercontrolpointers, maxplayers[current_set]);
20166 		for(p=0; p<maxplayers[current_set]; p++)
20167 		{
20168 			if(playercontrolpointers[p]->newkeyflags & FLAG_ESC)
20169 			{
20170 				moviestop = 1;
20171 				break;
20172 			}
20173 		}
20174 		if(!moviestop)
20175 		{
20176 			movie_update(playercontrolpointers);
20177 			font_printf(2, 2, 1, 0, "Playing movie, frames: %d/%d", movieloglen + moviebufptr-MOVIEBUF_LEN, movielen);
20178 		}
20179 		else
20180 		{
20181 			movie_closefile();
20182 		}
20183 	}
20184 	else
20185 	{
20186 #endif
20187 		 control_update(playercontrolpointers, maxplayers[current_set]);
20188 		 interval = timer_getinterval(GAME_SPEED); // so interval can be logged into movie
20189 		 if(interval > GAME_SPEED) interval = GAME_SPEED/GAME_SPEED;
20190 		 if(interval > GAME_SPEED/4) interval = GAME_SPEED/4;
20191 
20192 #ifndef DISABLE_MOVIE
20193 	}
20194 
20195 	if(movielog && !pause)
20196 	{
20197 		movie_save(playercontrolpointers);
20198 		font_printf(2, 2, 1, 0, "Recording movie, frames: %d", movieloglen + moviebufptr);
20199 	}
20200 #endif
20201 	bothkeys = 0;
20202 	bothnewkeys = 0;
20203 
20204 	for(p=0; p<maxplayers[current_set]; p++)
20205 	{
20206 		player[p].releasekeys = (playercontrolpointers[p]->keyflags|player[p].keys) - playercontrolpointers[p]->keyflags;
20207 		player[p].keys = playercontrolpointers[p]->keyflags;
20208 		player[p].newkeys = playercontrolpointers[p]->newkeyflags;
20209 		player[p].playkeys |= player[p].newkeys;
20210 		player[p].playkeys &= player[p].keys;
20211 
20212 		bothkeys |= player[p].keys;
20213 		bothnewkeys |= player[p].newkeys;
20214 #ifndef DISABLE_MOVIE
20215 		if(movielog && (bothnewkeys & FLAG_ESC) && !pause)
20216 		{
20217 			movie_flushbuf();
20218 			movie_closefile();
20219 		}
20220 #endif
20221 	}
20222 
20223 }
20224 
execute_keyscripts()20225 void execute_keyscripts()
20226 {
20227 	int p;
20228 	for(p=0; p<maxplayers[current_set]; p++)
20229 	{
20230 		if(!pause && (level||selectScreen) && (player[p].newkeys || (keyscriptrate && player[p].keys) || player[p].releasekeys)){
20231 			if(level){
20232 				execute_level_key_script(p);
20233 				execute_entity_key_script(player[p].ent);
20234 			}
20235 			execute_key_script(p);
20236 			execute_key_script_all(p);
20237 		}
20238 	}
20239 }
20240 
execute_updatescripts()20241 void execute_updatescripts()
20242 {
20243 	Script* ptempscript = pcurrentscript;
20244 	if(Script_IsInitialized(&update_script))
20245 	{
20246 		Script_Execute(&(update_script));
20247 	}
20248 	pcurrentscript = ptempscript;
20249 	if(level && Script_IsInitialized(&(level->update_script)))
20250 	{
20251 		Script_Execute(&(level->update_script));
20252 	}
20253 	pcurrentscript = ptempscript;
20254 }
20255 
execute_updatedscripts()20256 void execute_updatedscripts()
20257 {
20258 	Script* ptempscript = pcurrentscript;
20259 	if(Script_IsInitialized(&updated_script))
20260 	{
20261 		Script_Execute(&(updated_script));
20262 	}
20263 	pcurrentscript = ptempscript;
20264 	if(level && Script_IsInitialized(&(level->updated_script)))
20265 	{
20266 		Script_Execute(&(level->updated_script));
20267 	}
20268 	pcurrentscript = ptempscript;
20269 }
20270 
draw_textobjs()20271 void draw_textobjs()
20272 {
20273 	int i;
20274 	s_textobj* textobj;
20275 	if(!level) return;
20276 	for(i = 0;i < LEVEL_MAX_TEXTOBJS;i++)
20277 	{
20278 		 textobj = level->textobjs + i;
20279 
20280 		if(textobj->t && textobj->t <= time)		//If a time was set and passed, remove the text object.
20281 		{
20282 			level->textobjs[i].t	= 0;
20283 			level->textobjs[i].x	= 0;
20284 			level->textobjs[i].y	= 0;
20285 			level->textobjs[i].font = 0;
20286 			level->textobjs[i].z	= 0;
20287 			if(level->textobjs[i].text)
20288 			{
20289 				free(level->textobjs[i].text);
20290 				level->textobjs[i].text = NULL;
20291 			}
20292 		}
20293 		else
20294 		{
20295 			if(textobj->text)
20296 			  font_printf(textobj->x, textobj->y, textobj->font, textobj->z, textobj->text);
20297 		}
20298 	}
20299 }
20300 
20301 
20302 
update(int ingame,int usevwait)20303 void update(int ingame, int usevwait)
20304 {
20305 
20306 	newtime = 0;
20307 	inputrefresh();
20308 
20309 	if ((!pause && ingame == 1) || alwaysupdate) execute_updatescripts();
20310 
20311 	if(!pause)
20312 	{
20313 		if(ingame == 1 || selectScreen) execute_keyscripts();
20314 
20315 		if((level_completed && !level->noslow && !tospeedup) || slowmotion[0])
20316 		{
20317 			if(slowmotion[1] == slowmotion[2]) newtime = time + interval;
20318 		}
20319 		else newtime = time + interval;
20320 
20321 		slowmotion[2]++;
20322 		if(slowmotion[2] == (slowmotion[1] + 1))
20323 		{
20324 			slowmotion[2] = 0;
20325 			if(slowmotion[0] > 1) slowmotion[1] = slowmotion[0];
20326 		}
20327 		if(newtime > time + 100) newtime = time + 100;
20328 
20329 		while(time < newtime)
20330 		{
20331 			if(ingame == 1)
20332 			{
20333 				update_scroller();
20334 				if(!freezeall)
20335 				{
20336 					if(level->settime > 0 || (!player[0].ent && !player[1].ent && !player[2].ent && !player[3].ent))
20337 					{
20338 						if(timeleft>0) --timeleft;
20339 						else if((level->settime > 0 && !player[0].joining && !player[1].joining && !player[2].joining && !player[3].joining) ||
20340 								(((!noshare && credits < 1) || (noshare && player[0].credits < 1 && player[1].credits < 1 && player[2].credits <1 && player[3].credits <1))
20341 								 && !player[0].joining && !player[1].joining && !player[2].joining && !player[3].joining )
20342 								)
20343 						{
20344 							time_over();
20345 						}
20346 					}
20347 				}
20348 			}
20349 			if(ingame==1 || selectScreen) update_ents();
20350 			++time;
20351 		}
20352 
20353 	}
20354 
20355 	if(ingame==1 &&
20356 #ifndef DISABLE_MOVIE
20357 		!movieplay &&
20358 #endif
20359 		!pause && !nopause &&
20360 	   ((player[0].ent && (player[0].newkeys & FLAG_START)) ||
20361 		(player[1].ent && (player[1].newkeys & FLAG_START)) ||
20362 		(player[2].ent && (player[2].newkeys & FLAG_START)) ||
20363 		(player[3].ent && (player[3].newkeys & FLAG_START)))
20364 	)
20365 	{
20366 		sound_pause_music(1);
20367 		sound_pause_sample(1);
20368 		sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
20369 		spriteq_lock();
20370 		pausemenu();
20371 	}
20372 
20373 
20374 	// gfx section
20375 	if(ingame == 1)
20376 	{
20377 		draw_scrolled_bg();
20378 		predrawstatus();
20379 		drawstatus();
20380 	}
20381 
20382 	if(ingame == 1 || alwaysupdate)
20383 	{
20384 		execute_updatedscripts();
20385 		draw_textobjs();
20386 	}
20387 
20388 
20389 	if(!ingame)
20390 	{
20391 		clearscreen(vscreen);
20392 		if(background) putscreen(vscreen, background, 0, 0, NULL);
20393 	}
20394 
20395 	if(ingame==1 || selectScreen) display_ents();
20396 
20397 	if(zoom_scale_x)
20398 	{
20399 		if(!zoombuffer) zoombuffer = allocscreen(vscreen->width, vscreen->height, vscreen->pixelformat);
20400 		copyscreen(zoombuffer, vscreen);
20401 		spriteq_draw(zoombuffer, 0, MIN_INT, zoom_z);
20402 		zoomscreen(vscreen, zoombuffer, zoom_center_x, zoom_center_y, zoom_scale_x, zoom_scale_y);
20403 		spriteq_draw(vscreen, 0, zoom_z + 1, MAX_INT);
20404 	}
20405 	else
20406 	{
20407 		if(zoombuffer)
20408 		{
20409 			freescreen(&zoombuffer);
20410 			zoombuffer = NULL;
20411 		}
20412 		spriteq_draw(vscreen, 0, MIN_INT, MAX_INT); // notice, always draw sprites at the very end of other methods
20413 	}
20414 /*
20415 	if(gosprite>=0){
20416 		s_sprite* go = sprite_map[gosprite].sprite;
20417 		int h, v;
20418 		for(v=0; v<go->height && v<vscreen->height; v++){
20419 			for(h=0; h<go->width && h<vscreen->width; h++){
20420 				((unsigned char*)vscreen->data)[v*vscreen->width+h] = sprite_get_pixel(go, h, v);
20421 			}
20422 		}
20423 	}
20424 */
20425 	if(pause!=2 && !noscreenshot && (bothnewkeys&FLAG_SCREENSHOT)) screenshot(vscreen, getpal, 1);
20426 
20427 	// Debug stuff, should not appear on screenshot
20428 	if(debug_time==0xFFFFFFFF) debug_time = time + GAME_SPEED * 5;
20429 	if(time<debug_time && debug_msg[0])
20430 	{
20431 		spriteq_clear();
20432 		font_printf(0,230, 0, 0, debug_msg);
20433 		spriteq_draw(vscreen, (ingame==0), MIN_INT, MAX_INT);
20434 	}
20435 	else
20436 	{
20437 		debug_msg[0] = 0;
20438 #ifdef DEBUG_MODE
20439 		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);
20440 #endif
20441 	}
20442 
20443 	if(usevwait) vga_vwait();
20444 	video_copy_screen(vscreen);
20445 
20446 	spriteq_clear();
20447 
20448 	check_music();
20449 	sound_update_music();
20450 }
20451 
20452 
20453 
20454 
20455 // ----------------------------------------------------------------------
20456 /* Plombo 9/4/2010: New function that can use brightness/gamma correction
20457  * independent from the global palette on platforms where it's available.
20458  * Hardware accelerated brightness/gamma correction is available on Wii and
20459  * OpenGL platforms using TEV and GLSL, respectively. Returns 1 on success, 0 on
20460  * error. */
set_color_correction(int gm,int br)20461 int set_color_correction(int gm, int br)
20462 {
20463 #if WII
20464 	vga_set_color_correction(gm, br);
20465 	return 1;
20466 #elif SDL
20467 	if(opengl)
20468 	{
20469 		vga_set_color_correction(gm, br);
20470 		return 1;
20471 	}
20472 	else if(screenformat == PIXEL_8)
20473 	{
20474 		palette_set_corrected(pal, savedata.gamma,savedata.gamma,savedata.gamma, savedata.brightness,savedata.brightness,savedata.brightness);
20475 		return 1;
20476 	}
20477 	else return 0;
20478 #else
20479 	if(screenformat == PIXEL_8)
20480 	{
20481 		palette_set_corrected(pal, savedata.gamma,savedata.gamma,savedata.gamma, savedata.brightness,savedata.brightness,savedata.brightness);
20482 		return 1;
20483 	}
20484 	else return 0;
20485 #endif
20486 }
20487 
20488 // 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)20489 static void _fade_screen(s_screen* screen, int gr, int gg, int gb, int br, int bg, int bb)
20490 {
20491 	int i, len = screen->width*screen->height;
20492 	int pb = pixelbytes[(int)screenformat];
20493 	unsigned c, r, g, b;
20494 
20495 
20496 	if(gr<-255) gr = -255;
20497 	else if(gr>255) gr = 255;
20498 	if(gg<-255) gg = -255;
20499 	else if(gg>255) gg = 255;
20500 	if(gb<-255) gb = -255;
20501 	else if(gb>255) gb = 255;
20502 
20503 	if(br<-255) br = -255;
20504 	else if(br>255) br = 255;
20505 	if(bg<-255) bg = -255;
20506 	else if(bg>255) bg = 255;
20507 	if(bb<-255) bb = -255;
20508 	else if(bb>255) bb = 255;
20509 
20510 	if(pb==2) for(i=0; i<len; i++)
20511 	{
20512 		c = ((unsigned short*)screen->data)[i];
20513 		b = (c>>11)*0xFF/0x1F;
20514 		g = ((c&0x7E0)>>5)*0xFF/0x3F;
20515 		r = (c&0x1F)*0xFF/0x1F;
20516 		((unsigned short*)screen->data)[i] = colour16(gbcorrect(r, gr, br), gbcorrect(g, gg, bg), gbcorrect(b, gb, bb));
20517 	}
20518 	else for(i=0; i<len; i++){
20519 		screen->data[i*pb] =   gbcorrect(screen->data[i*pb],   gr, br);
20520 		screen->data[i*pb+1] = gbcorrect(screen->data[i*pb+1], gg, bg);
20521 		screen->data[i*pb+2] = gbcorrect(screen->data[i*pb+2], gb, bb);
20522 	}
20523 }
20524 
20525 // Simple palette fade / vscreen fade
fade_out(int type,int speed)20526 void fade_out(int type, int speed)
20527 {
20528 	int i, j = 0;
20529 	int b, g = 0;
20530 	u32 interval = 0;
20531 	unsigned char* thepal = NULL;
20532 	int current = speed ? speed : fade;
20533 
20534 	if(pixelformat==PIXEL_8)
20535 	{
20536 		if(current_palette && level) thepal = level->palettes[current_palette - 1];
20537 		else thepal = pal;
20538 	}
20539 
20540 	for(i=0, j=0; j<64; )
20541 	{
20542 		while(j<=i)
20543 		{
20544 			if(!type || type == 1)
20545 			{
20546 				b = ((savedata.brightness+256) * (64-j) / 64) - 256;
20547 				g = 256 - ((savedata.gamma+256) * (64-j) / 64);
20548 				vga_vwait();
20549 				if(!set_color_correction(g, b))
20550 					_fade_screen(vscreen, g,savedata.gamma,savedata.gamma, b,b,b);
20551 			}
20552 			j++;
20553 			if(!type || type == 1)
20554 			{
20555 				video_copy_screen(vscreen);
20556 			}
20557 		}
20558 		if(!type || type == 2)
20559 		{
20560 			sound_update_music();
20561 	        if(!musicoverlap) sound_volume_music(savedata.musicvol*(64-j)/64, savedata.musicvol*(64-j)/64);
20562 		}
20563 		interval = timer_getinterval(current);
20564 		if(interval > current) interval = current/60;
20565 		if(interval > current/4) interval = current/4;
20566 		i += interval;
20567 	}
20568 
20569 	if(!type || type == 2)
20570 	{
20571 		if(!musicoverlap) sound_close_music();
20572 	}
20573 
20574 	if(!type || type == 1)
20575 	{
20576 		clearscreen(vscreen);
20577 		video_copy_screen(vscreen);
20578 	    vga_vwait();
20579 		//the black screen, so we return to normal palette
20580 		set_color_correction(savedata.gamma, savedata.brightness);
20581 	}
20582 }
20583 
20584 
20585 
apply_controls()20586 void apply_controls(){
20587 	int p;
20588 
20589 	for(p=0; p<4; p++){
20590 		control_setkey(playercontrolpointers[p], FLAG_ESC,        CONTROL_ESC);
20591 		control_setkey(playercontrolpointers[p], FLAG_MOVEUP,     savedata.keys[p][SDID_MOVEUP]);
20592 		control_setkey(playercontrolpointers[p], FLAG_MOVEDOWN,   savedata.keys[p][SDID_MOVEDOWN]);
20593 		control_setkey(playercontrolpointers[p], FLAG_MOVELEFT,   savedata.keys[p][SDID_MOVELEFT]);
20594 		control_setkey(playercontrolpointers[p], FLAG_MOVERIGHT,  savedata.keys[p][SDID_MOVERIGHT]);
20595 		control_setkey(playercontrolpointers[p], FLAG_ATTACK,     savedata.keys[p][SDID_ATTACK]);
20596 		control_setkey(playercontrolpointers[p], FLAG_ATTACK2,    savedata.keys[p][SDID_ATTACK2]);
20597 		control_setkey(playercontrolpointers[p], FLAG_ATTACK3,    savedata.keys[p][SDID_ATTACK3]);
20598 		control_setkey(playercontrolpointers[p], FLAG_ATTACK4,    savedata.keys[p][SDID_ATTACK4]);
20599 		control_setkey(playercontrolpointers[p], FLAG_JUMP,       savedata.keys[p][SDID_JUMP]);
20600 		control_setkey(playercontrolpointers[p], FLAG_SPECIAL,    savedata.keys[p][SDID_SPECIAL]);
20601 		control_setkey(playercontrolpointers[p], FLAG_START,      savedata.keys[p][SDID_START]);
20602 		control_setkey(playercontrolpointers[p], FLAG_SCREENSHOT, savedata.keys[p][SDID_SCREENSHOT]);
20603 	}
20604 }
20605 
20606 
20607 
20608 // ----------------------------------------------------------------------
20609 
display_credits()20610 void display_credits()
20611 {
20612 	u32 finishtime = time + 10 * GAME_SPEED;
20613 	int done = 0;
20614 
20615 	if(savedata.logo != 1) return;
20616 	fade_out(0, 0);
20617 	unload_background();
20618 
20619 	bothnewkeys = 0;
20620 
20621 	while(!done)
20622 	{
20623 		font_printf(videomodes.hShift + 140, videomodes.vShift + 3,   2, 0, "Credits");
20624 		font_printf(videomodes.hShift + 125, videomodes.vShift + 25,  1, 0, "Beats Of Rage");
20625 		font_printf(videomodes.hShift + 133, videomodes.vShift + 35,  0, 0, "Senile Team");
20626 
20627 		font_printf(videomodes.hShift + 138, videomodes.vShift + 55,  1, 0, "OpenBOR");
20628 		font_printf(videomodes.hShift + 150, videomodes.vShift + 65,  0, 0, "SX");
20629 		font_printf(videomodes.hShift + 70,  videomodes.vShift + 75,  0, 0, "CGRemakes");
20630 		font_printf(videomodes.hShift + 205, videomodes.vShift + 75,  0, 0, "Fugue");
20631 		font_printf(videomodes.hShift + 70,  videomodes.vShift + 85,  0, 0, "uTunnels");
20632 		font_printf(videomodes.hShift + 205, videomodes.vShift + 85,  0, 0, "Kirby");
20633 		font_printf(videomodes.hShift + 70,  videomodes.vShift + 95,  0, 0, "LordBall");
20634 		font_printf(videomodes.hShift + 205, videomodes.vShift + 95,  0, 0, "Tails");
20635 		font_printf(videomodes.hShift + 70,  videomodes.vShift + 105, 0, 0, "KBAndressen");
20636 		font_printf(videomodes.hShift + 205, videomodes.vShift + 105, 0, 0, "Damon Caskey");
20637 		font_printf(videomodes.hShift + 70,  videomodes.vShift + 115, 0, 0, "Plombo");
20638 		font_printf(videomodes.hShift + 205, videomodes.vShift + 115, 0, 0, "Orochi_X");
20639 
20640 		font_printf(videomodes.hShift + 138, videomodes.vShift + 125, 1, 0, "Consoles");
20641 		font_printf(videomodes.hShift + 70,  videomodes.vShift + 135, 0, 0, "PSP, PS3, Linux, OSX");
20642 		font_printf(videomodes.hShift + 205, videomodes.vShift + 135, 0, 0, "SX");
20643 		font_printf(videomodes.hShift + 70,  videomodes.vShift + 145, 0, 0, "Dingoo");
20644 		font_printf(videomodes.hShift + 205, videomodes.vShift + 145, 0, 0, "Shin-NiL");
20645 		font_printf(videomodes.hShift + 70,  videomodes.vShift + 155, 0, 0, "Windows");
20646 		font_printf(videomodes.hShift + 205, videomodes.vShift + 155, 0, 0, "SX & Nazo");
20647 		font_printf(videomodes.hShift + 70,  videomodes.vShift + 165, 0, 0, "GamePark");
20648 		font_printf(videomodes.hShift + 205, videomodes.vShift + 165, 0, 0, "SX & Lemon");
20649 		font_printf(videomodes.hShift + 70,  videomodes.vShift + 175, 0, 0, "DreamCast");
20650 		font_printf(videomodes.hShift + 205, videomodes.vShift + 175, 0, 0, "SX & Neill Corlett");
20651 		font_printf(videomodes.hShift + 70,  videomodes.vShift + 185, 0, 0, "MS XBoX");
20652 		font_printf(videomodes.hShift + 205, videomodes.vShift + 185, 0, 0, "SX & XPort");
20653 		font_printf(videomodes.hShift + 70,  videomodes.vShift + 195, 0, 0, "Wii");
20654 		font_printf(videomodes.hShift + 205, videomodes.vShift + 195, 0, 0, "SX & Plombo");
20655 
20656 		font_printf(videomodes.hShift + 133, videomodes.vShift + 215, 1, 0, "Menu Design");
20657 		font_printf(videomodes.hShift + 70,  videomodes.vShift + 225, 0, 0, "SX");
20658 		font_printf(videomodes.hShift + 205, videomodes.vShift + 225, 0, 0, "Fightn Words");
20659 
20660 		update(2,0);
20661 
20662 		done |= (time > finishtime);
20663 		done |= (bothnewkeys & (FLAG_START+FLAG_ESC));
20664 	}
20665 	fade = 75;
20666 	fade_out(0, 0);
20667 }
20668 
20669 
shutdown(int status,char * msg,...)20670 void shutdown(int status, char *msg, ...)
20671 {
20672 	char buf[1024] = "";
20673 	va_list arglist;
20674 	int i;
20675 
20676 	static int shuttingdown = 0;
20677 
20678 	if(shuttingdown) return;
20679 
20680 	shuttingdown = 1;
20681 
20682 	//printf("savedata.logo %d\n", savedata.logo);
20683 
20684 	va_start(arglist, msg);
20685 	vsprintf(buf, msg, arglist);
20686 	va_end(arglist);
20687 
20688 	if(!disablelog)
20689 	{
20690 		switch(status)
20691 		{
20692 		case 0:
20693 			printf("\n************ Shutting Down ************\n\n");
20694 			break;
20695 		default:
20696 			printf("\n********** An Error Occurred **********"
20697 				"\n*            Shutting Down            *\n\n");
20698 			break;
20699 		}
20700 	}
20701 
20702 	if(!disablelog) printf("%s", buf);
20703 
20704 
20705 	getRamStatus(BYTES);
20706 	savesettings();
20707 
20708 	if(status != 2) display_credits();
20709 	if(startup_done) term_videomodes();
20710 
20711 	if(!disablelog) printf("Release level data");
20712 	if (startup_done) unload_levelorder();
20713 	if(!disablelog) printf("...........");
20714 	if(startup_done) unload_level();
20715 	if(!disablelog) printf("\tDone!\n");
20716 
20717 	if(!disablelog) printf("Release graphics data");
20718 	if(!disablelog) printf("..");
20719 	if(startup_done) freescreen(&vscreen); // allocated by init_videomodes
20720 	if(startup_done && pixelformat==PIXEL_x8) for(i=0; i<MAX_BLENDINGS; i++) free(blendtables[i]);
20721 	if(!disablelog) printf("..");
20722 	if(startup_done) freescreen(&background);
20723 	if(!disablelog) printf("..");
20724 #if WII
20725 	if(startup_done) for(i=0; i<MAX_CACHED_BACKGROUNDS; i++) freescreen(&bg_cache[i]);
20726 	if(!disablelog) printf("..");
20727 #endif
20728 	if(startup_done) freesprites();
20729 	if(!disablelog) printf("..");
20730 	if(startup_done) unload_all_fonts();
20731 	if(!disablelog) printf("\tDone!\n");
20732 
20733 
20734 	if(!disablelog) printf("Release game data............\n\n");
20735 
20736 	if(startup_done) free_ents();
20737 	if(startup_done) free_models();
20738 	if(startup_done) free_modelcache();
20739 	if(startup_done) clear_scripts();
20740 	if(!disablelog) printf("\nRelease game data............\tDone!\n");
20741 
20742 	if(!disablelog) printf("Release timer................");
20743 	if(startup_done) borTimerExit();
20744 	if(!disablelog) printf("\tDone!\n");
20745 
20746 	if(!disablelog) printf("Release input hardware.......");
20747 	if(startup_done) control_exit();
20748 	if(!disablelog) printf("\tDone!\n");
20749 
20750 	if(!disablelog) printf("Release sound system.........");
20751 	if(startup_done) sound_exit();
20752 	if(!disablelog) printf("\tDone!\n");
20753 
20754 	if(!disablelog) printf("Release FileCaching System...");
20755 	if(startup_done) pak_term();
20756 	if(!disablelog) printf("\tDone!\n");
20757 
20758 	if(modelcmdlist)
20759 		freeCommandList(modelcmdlist); // moved here because list is not initialized if shutdown is initiated from inside the menu
20760 	if(modelstxtcmdlist)
20761 		freeCommandList(modelstxtcmdlist);
20762 	if(levelcmdlist)
20763 		freeCommandList(levelcmdlist);
20764 	if(levelordercmdlist)
20765 		freeCommandList(levelordercmdlist);
20766 
20767 	freeModelList();
20768 
20769 	freefilenamecache();
20770 
20771 
20772 	if(!disablelog) printf("\n**************** Done *****************\n\n");
20773 
20774 	if(!disablelog) printf("%s", buf);
20775 	#ifdef DEBUG
20776 	assert(status == 0); // this way we can haz backtrace.
20777 	#endif
20778 
20779 	shuttingdown = 0;
20780 	exit(status);
20781 }
20782 
20783 
20784 #if XBOX || DC
guistartup()20785 void guistartup(){
20786 	int i;
20787 
20788 	if(!font_load(0, "menu/font1", packfile, 0)) shutdown(1, "Unable to load font #1!\n");
20789 	if(!font_load(1, "menu/font2", packfile, 0)) shutdown(1, "Unable to load font #2!\n");
20790 	if(!font_load(2, "menu/font3", packfile, 0)) shutdown(1, "Unable to load font #3!\n");
20791 
20792 
20793 	borTimerInit();
20794 
20795 	control_init(2);
20796 	apply_controls();
20797 
20798 	init_videomodes(0);
20799 	if(!video_set_mode(videomodes)) shutdown(1, "Unable to set video mode: %d x %d!\n", videomodes.hRes, videomodes.vRes);
20800 
20801 	for(i=0; i<256; i++) neontable[i] = i;
20802 }
20803 #endif
20804 
startup()20805 void startup(){
20806 	int i;
20807 
20808 	printf("FileCaching System Init......\t");
20809 	if(pak_init()) printf("Enabled\n");
20810 	else           printf("Disabled\n");
20811 
20812 #if PSP
20813 	if(savedata.pspcpuspeed<0) savedata.pspcpuspeed = 2;
20814 	if(savedata.pspcpuspeed>2) savedata.pspcpuspeed = 0;
20815 	switch(savedata.pspcpuspeed){
20816 		case 0:
20817 			scePowerSetClockFrequency(222, 222, 111);
20818 			break;
20819 		case 1:
20820 			scePowerSetClockFrequency(266, 266, 133);
20821 			break;
20822 		case 2:
20823 			scePowerSetClockFrequency(333, 333, 166);
20824 			break;
20825 	}
20826 #endif
20827 
20828 	loadHighScoreFile();
20829 	clearSavedGame();
20830 
20831 	init_videomodes(1);
20832 	if(!video_set_mode(videomodes)) shutdown(1, "Unable to set video mode: %d x %d!\n", videomodes.hRes, videomodes.vRes);
20833 
20834 	printf("Loading menu.txt.............\t");
20835 	load_menu_txt();
20836 	printf("Done!\n");
20837 
20838 	printf("Loading fonts................\t");
20839 	load_all_fonts();
20840 	printf("Done!\n");
20841 
20842 	printf("Timer init...................\t");
20843 	borTimerInit();
20844 	printf("Done!\n");
20845 
20846 	printf("Initialize Sound..............\t");
20847 	if(savedata.usesound && sound_init(12)){
20848 		if(load_special_sounds()) printf("Done!\n");
20849 		else printf("\n");
20850 		if(!sound_start_playback(savedata.soundbits,savedata.soundrate)) printf("Warning: can't play sound at %u Hz!\n", savedata.soundrate);
20851 		SB_setvolume(SB_MASTERVOL, 15);
20852 		SB_setvolume(SB_VOICEVOL, savedata.soundvol);
20853 	}
20854 	else shutdown(1, "Unable to Initialize Sound.\n");
20855 
20856 	printf("Loading sprites..............\t");
20857 	load_special_sprites();
20858 	printf("Done!\n");
20859 
20860 	printf("Loading level order..........\t");
20861 	load_levelorder();
20862 	printf("Done!\n");
20863 
20864 	printf("Loading script settings......\t");
20865 	load_script_setting();
20866 	printf("Done!\n");
20867 
20868 	printf("Loading scripts..............\t");
20869 	load_scripts();
20870 	printf("Done!\n");
20871 
20872 	printf("Loading models...............\n\n");
20873 	load_models();
20874 
20875 	printf("Object engine init...........\t");
20876 	if(!alloc_ents()) shutdown(1, "Not enough memory for game objects!\n");
20877 	printf("Done!\n");
20878 
20879 	printf("Input init...................\t");
20880 	control_init(savedata.usejoy);
20881 	apply_controls();
20882 	printf("Done!\n");
20883 
20884 #if WII
20885 	printf("Caching backgrounds..........\t");
20886 	cache_all_backgrounds();
20887 	printf("Done!\n");
20888 #endif
20889 
20890 	printf("\n\n");
20891 
20892 	if(pixelformat==PIXEL_x8)
20893 		create_blend_tables_x8(blendtables);
20894 
20895 	for(i=0; i<MAX_PAL_SIZE/4; i++) neontable[i] = i;
20896 	if(savedata.logo++ > 10) savedata.logo = 0;
20897 	savesettings();
20898 	startup_done = 1;
20899 
20900 }
20901 
20902 
update_backbuffer(s_screen * backbuffer,s_screen ** gifbuffer)20903 static void update_backbuffer(s_screen* backbuffer, s_screen** gifbuffer){
20904 	int i, l = backbuffer->width*backbuffer->height;
20905 	unsigned short *ps16, *ppr16, *ppg16, *ppb16;
20906 	unsigned int *ps32, *ppr32, *ppg32, *ppb32;
20907 	switch(screenformat){
20908 	case PIXEL_16:
20909 		ps16 = (unsigned short*)(backbuffer->data);
20910 		ppr16 = (unsigned short*)(gifbuffer[0]->data);
20911 		ppg16 = (unsigned short*)(gifbuffer[1]->data);
20912 		ppb16 = (unsigned short*)(gifbuffer[2]->data);
20913 		for(i=0; i<l; i++){
20914 			ps16[i] =  ppr16[i]|ppg16[i]|ppb16[i];
20915 		}
20916 		break;
20917 	case PIXEL_32:
20918 		ps32 = (unsigned int*)(backbuffer->data);
20919 		ppr32 = (unsigned int*)(gifbuffer[0]->data);
20920 		ppg32 = (unsigned int*)(gifbuffer[1]->data);
20921 		ppb32 = (unsigned int*)(gifbuffer[2]->data);
20922 		for(i=0; i<l; i++){
20923 			ps32[i] = ppr32[i]|ppg32[i]|ppb32[i];
20924 			//printf(" %u %u %u\n", ppr32[i], ppg32[i], ppb32[i]);
20925 		}
20926 		break;
20927 	}
20928 
20929 }
20930 
20931 
20932 
20933 
20934 // ----------------------------------------------------------------------------
20935 
20936 // Returns 0 on error, -1 on escape
playgif(char * filename,int x,int y,int noskip)20937 int playgif(char *filename, int x, int y, int noskip){
20938 	unsigned char gifpal[3][1024] ;
20939 	char tname[256] = {""};
20940 	int code[3];
20941 	int delay[3];
20942 	u32 milliseconds;
20943 	u32 nextframe[3];
20944 	u32 lasttime;
20945 	u32 temptime, tempnewtime; // temporary patch for ingame gif play
20946 	int done;
20947 	int frame = 0;
20948 	int synctosound = 0;
20949 	s_screen* backbuffer = NULL, *gifbuffer[3] = {NULL, NULL, NULL}, *tempbg = background;
20950 	static anigif_info info[3];
20951 	int isRGB = (pixelformat==PIXEL_x8);
20952 
20953 	strcpy(tname, filename);
20954 	if(stricmp(tname + strlen(tname)-4, ".gif")==0) tname[strlen(tname)-4] = 0;
20955 
20956 	strcat(tname, "_.gif");
20957 
20958 	if(isRGB){
20959 		tname[strlen(tname)-5] = 'r';
20960 		if(testpackfile(tname, packfile)<0) isRGB = 0;
20961 		tname[strlen(tname)-5] = 'g';
20962 		if(testpackfile(tname, packfile)<0) isRGB = 0;
20963 		tname[strlen(tname)-5] = 'b';
20964 		if(testpackfile(tname, packfile)<0) isRGB = 0;
20965 	}
20966 
20967 
20968 
20969 	background = gifbuffer[0] = allocscreen(videomodes.hRes, videomodes.vRes, screenformat);
20970 	clearscreen(background);
20971 	info->noblackenbg = (info+1)->noblackenbg = (info+2)->noblackenbg = isRGB;
20972 
20973 	if(isRGB) {
20974 		backbuffer = allocscreen(videomodes.hRes, videomodes.vRes, screenformat);
20975 		gifbuffer[1] = allocscreen(videomodes.hRes, videomodes.vRes, screenformat);
20976 		clearscreen(gifbuffer[1]);
20977 		gifbuffer[2] = allocscreen(videomodes.hRes, videomodes.vRes, screenformat);
20978 		clearscreen(gifbuffer[2]);
20979 		background = NULL;
20980 	}
20981 	standard_palette(1);
20982 
20983 	if(!isRGB){
20984 		if(!anigif_open(filename, packfile, gifpal[0], info))
20985 			goto playgif_error;
20986 	}else{
20987 		tname[strlen(tname)-5] = 'r';
20988 		if(!anigif_open(tname, packfile, gifpal[0], info)) goto playgif_error;
20989 		tname[strlen(tname)-5] = 'g';
20990 		if(!anigif_open(tname, packfile, gifpal[1], info+1)) goto playgif_error;
20991 		tname[strlen(tname)-5] = 'b';
20992 		if(!anigif_open(tname, packfile, gifpal[2], info+2)) goto playgif_error;
20993 	}
20994 
20995 	temptime = time;
20996 	tempnewtime = newtime;
20997 	time = 0;
20998 	lasttime = 0;
20999 	milliseconds = 0;
21000 	nextframe[0] = nextframe[1] = nextframe[2] = 0;
21001 	delay[0] = delay[1] = delay[2] = 100;
21002 	code[0] = code[1] = code[2] = ANIGIF_DECODE_RETRY;
21003 	done = 0;
21004 	synctosound = (sound_getinterval() != 0xFFFFFFFF);
21005 
21006 	while(!done){
21007 		//printf("gif\n");
21008 		if(milliseconds >= nextframe[0]){
21009 			if(code[0] != ANIGIF_DECODE_END){
21010 				while((code[0] = anigif_decode(gifbuffer[0], delay, x, y, gifpal[0], info)) == ANIGIF_DECODE_RETRY);
21011 				// if(code == ANIGIF_DECODE_FRAME){
21012 				// Set time for next frame
21013 				nextframe[0] += delay[0] * 10;
21014 			// }
21015 			}
21016 			else done |= 1;
21017 		}
21018 		if(code[0] == ANIGIF_DECODE_END) break;
21019 
21020 		if(isRGB){
21021 			//g
21022 			if(milliseconds >= nextframe[1]){
21023 				if(code[1] != ANIGIF_DECODE_END){
21024 					while((code[1] = anigif_decode(gifbuffer[1], delay+1, x, y, gifpal[1], info+1)) == ANIGIF_DECODE_RETRY);
21025 					nextframe[1] += delay[1] * 10;
21026 				}
21027 				else done |= 1;
21028 			}
21029 			//b
21030 			if(milliseconds >= nextframe[2]){
21031 				if(code[2] != ANIGIF_DECODE_END){
21032 					while((code[2] = anigif_decode(gifbuffer[2], delay+2, x, y, gifpal[2], info+2)) == ANIGIF_DECODE_RETRY);
21033 					nextframe[2] += delay[2] * 10;
21034 				}
21035 				else done |= 1;
21036 			}
21037 			if(backbuffer) update_backbuffer(backbuffer, gifbuffer);
21038 		}
21039 
21040 		if(backbuffer){
21041 			spriteq_add_screen(0,0,0,backbuffer,NULL,0);
21042 		}
21043 
21044 		if(frame==0){
21045 			vga_vwait();
21046 			if(background)
21047 				palette_set_corrected(gifpal[0], savedata.gamma,savedata.gamma,savedata.gamma, savedata.brightness,savedata.brightness,savedata.brightness);
21048 			update(0,0);
21049 		}
21050 		else update(0,1);
21051 
21052 		++frame;
21053 
21054 		if(synctosound){
21055 			milliseconds += sound_getinterval();
21056 			if(milliseconds==0xFFFFFFFF) synctosound = 0;
21057 		}
21058 		if(!synctosound) milliseconds += (time-lasttime) * 1000 / GAME_SPEED;
21059 		lasttime = time;
21060 
21061 		if(!noskip && (bothnewkeys & (FLAG_ESC | FLAG_ANYBUTTON))) done = 1;
21062 	}
21063 	anigif_close(info);
21064 	if(isRGB){
21065 		anigif_close(info+1);
21066 		anigif_close(info+2);
21067 	}
21068 
21069 	time = temptime;
21070 	newtime = tempnewtime;
21071 
21072 	if(backbuffer) freescreen(&backbuffer);
21073 	if(gifbuffer[0]) freescreen(&(gifbuffer[0]));
21074 	if(gifbuffer[1]) freescreen(&(gifbuffer[1]));
21075 	if(gifbuffer[2]) freescreen(&(gifbuffer[2]));
21076 	background = tempbg;
21077 	if(bothnewkeys & (FLAG_ESC | FLAG_ANYBUTTON)) return -1;
21078 	return 1;
21079 
21080 playgif_error:
21081 	if(info->handle>=0) anigif_close(info);
21082 	if((info+1)->handle>=0) anigif_close(info+1);
21083 	if((info+2)->handle>=0) anigif_close(info+2);
21084 	if(backbuffer) freescreen(&backbuffer);
21085 	if(gifbuffer[0]) freescreen(&(gifbuffer[0]));
21086 	if(gifbuffer[1]) freescreen(&(gifbuffer[1]));
21087 	if(gifbuffer[2]) freescreen(&(gifbuffer[2]));
21088 	background = tempbg;
21089 	return 0;
21090 }
21091 
21092 
21093 
21094 
21095 
playscene(char * filename)21096 void playscene(char *filename)
21097 {
21098 	char *buf;
21099 	size_t size;
21100 	int pos;
21101 	char * command = NULL;
21102 	char giffile[256];
21103 	int x=0, y=0, skipone=0, noskip=0;
21104 	int closing = 0;
21105 
21106 	ArgList arglist;
21107 	char argbuf[MAX_ARG_LEN+1] = "";
21108 
21109 	// Read file
21110 	if(buffer_pakfile(filename, &buf, &size)!=1) return;
21111 
21112 	currentScene = filename;
21113 
21114 	// Now interpret the contents of buf line by line
21115 	pos = 0;
21116 	while(buf[pos]){
21117 	    ParseArgs(&arglist,buf+pos,argbuf);
21118 		command = GET_ARG(0);
21119 		if(command[0]){
21120 			if(!closing && stricmp(command, "music")==0){
21121 				music(GET_ARG(1), GET_INT_ARG(2), atol(GET_ARG(3)));
21122 			}
21123 			else if(!closing && stricmp(command, "animation")==0){
21124 				strcpy(giffile, GET_ARG(1));
21125 				x = GET_INT_ARG(2);
21126 				y = GET_INT_ARG(3);
21127 				skipone = GET_INT_ARG(4);
21128 				noskip = GET_INT_ARG(5);
21129 				if(playgif(giffile, x, y, noskip) == -1 && !skipone) closing = 1;
21130 			}
21131 			else if(stricmp(command, "silence")==0){
21132 				sound_close_music();
21133 			}
21134 		}
21135 		// Go to next non-blank line
21136 	pos += getNewLineStart(buf + pos);
21137 	}
21138 	if(buf != NULL){
21139 		free(buf);
21140 		buf = NULL;
21141 	}
21142 	currentScene = NULL;
21143 }
21144 
21145 
21146 
21147 
21148 // ----------------------------------------------------------------------------
21149 
21150 
21151 
21152 
gameover()21153 void gameover(){
21154 	int done = 0;
21155 	char tmpBuff[128] = {""};
21156 
21157 	music("data/music/gameover", 0, 0);
21158 
21159 	time = 0;
21160 	gameOver = 1;
21161 	while(!done)
21162 	{
21163 		if(custScenes != NULL)
21164 		{
21165 			strcpy(tmpBuff,custScenes);
21166 			strncat(tmpBuff,"gameover.txt", 12);
21167 			if(testpackfile(tmpBuff, packfile) >=0) playscene(tmpBuff);
21168 			else font_printf(_strmidx(3, "GAME OVER"),110+videomodes.vShift, 3, 0, "GAME OVER");
21169 		}
21170 		else
21171 		{
21172 		    if(testpackfile("data/scenes/gameover.txt", packfile) >=0) playscene("data/scenes/gameover.txt");
21173 			else font_printf(_strmidx(3, "GAME OVER"),110+videomodes.vShift, 3, 0, "GAME OVER");
21174 		}
21175 		done |= (time>GAME_SPEED*8 && !sound_query_music(NULL,NULL));
21176 		done |= (bothnewkeys & (FLAG_ESC|FLAG_ANYBUTTON));
21177 		update(0,0);
21178 	}
21179 	gameOver = 0;
21180 }
21181 
21182 
21183 
21184 
hallfame(int addtoscore)21185 void hallfame(int addtoscore)
21186 {
21187 	int done = 0;
21188 	int topten[10] = { 0,0,0,0,0,0,0,0,0,0 };
21189 	u32 score;
21190 	char name[MAX_NAME_LEN+1];
21191 	int i, p, y;
21192 	char tmpBuff[128] = {""};
21193 	s_model *model = NULL;
21194 	int col1 = -8;
21195 	int col2 = 6;
21196 
21197 	hallOfFame = 1;
21198 
21199 	if(hiscorebg)
21200 	{
21201 		// New alternative background path for PSP
21202 		if(custBkgrds != NULL)
21203 		{
21204 			strcpy(tmpBuff,custBkgrds);
21205 			strncat(tmpBuff,"hiscore", 7);
21206 			load_background(tmpBuff, 0);
21207 		}
21208 		else load_cached_background("data/bgs/hiscore", 0);
21209 	}
21210 
21211 	if(addtoscore)
21212 	{
21213 		for(p = 0; p < maxplayers[current_set]; p++)
21214 		{
21215 			model = findmodel(player[p].name);
21216 			if(player[p].score > savescore.highsc[9])
21217 			{
21218 				savescore.highsc[9] = player[p].score;
21219 				strcpy(savescore.hscoren[9], model->name);
21220 				topten[9] = 1;
21221 
21222 				for(i = 8; i >= 0 && player[p].score > savescore.highsc[i]; i--)
21223 				{
21224 					score = savescore.highsc[i];
21225 					strcpy(name, savescore.hscoren[i]);
21226 					savescore.highsc[i] = player[p].score;
21227 					strcpy(savescore.hscoren[i], model->name);
21228 					topten[i] = 1;
21229 					savescore.highsc[i + 1] = score;
21230 					strcpy(savescore.hscoren[i + 1], name);
21231 					topten[i + 1] = 0;
21232 				}
21233 			}
21234 		}
21235 	}
21236 
21237 	time = 0;
21238 
21239 	while(!done)
21240 	{
21241 		y = 60;
21242 		if(!hiscorebg) font_printf(_strmidx(3, "Hall Of Fame"), y-font_heights[3]-10+videomodes.vShift, 3, 0, "Hall Of Fame");
21243 
21244 		for(i = 0; i < 10; i++)
21245 		{
21246 			font_printf(_colx(topten[i], col1), y+videomodes.vShift, topten[i], 0, "%2i.  %s", i+1, savescore.hscoren[i]);
21247 			font_printf(_colx(topten[i], col2), y+videomodes.vShift, topten[i], 0, (scoreformat ? "%09lu" : "%u"), savescore.highsc[i]);
21248 			y += font_heights[topten[i]] + 6;
21249 		}
21250 
21251 		update(0,0);
21252 		done |= (time>GAME_SPEED*8);
21253 		done |= (bothnewkeys & (FLAG_START+FLAG_ESC));
21254 	}
21255 	unload_background();
21256 	hallOfFame = 0;
21257 }
21258 
21259 
21260 
21261 
21262 // Level completed, show bonus stuff
showcomplete(int num)21263 void showcomplete(int num)
21264 {
21265 	int done = 0;
21266 	int i, j, k;
21267 	u32 clearbonus[4] = { 10000, 10000, 10000, 10000 };
21268 	u32 lifebonus[4] = { 10000, 10000, 10000, 10000 };
21269 	u32 rushbonus[4] = { 10000, 10000, 10000, 10000 };
21270 	u32 nexttime = 0;
21271 	u32 finishtime = 0;
21272 	int chan = 0;
21273 	char tmpBuff[128] = {""};
21274 
21275 	showComplete = 1;
21276 
21277 	if(completebg)
21278 	{
21279 		// New alternative background path for PSP
21280 		if(custBkgrds != NULL)
21281 		{
21282 			strcpy(tmpBuff,custBkgrds);
21283 			strncat(tmpBuff,"complete", 8);
21284 			load_background(tmpBuff, 0);
21285 		}
21286 		else load_cached_background("data/bgs/complete", 0);
21287 	}
21288 
21289 	music("data/music/complete", 0, 0);
21290 
21291 	for(i=0; i<maxplayers[current_set]; i++)
21292 	{
21293 		if(rush[0] >= 1 && showrushbonus == 1)
21294 		{
21295 			rushbonus[i] = nomaxrushreset[i] * scbonuses[2];
21296 		}
21297 		if(scbonuses[3] == 1) clearbonus[i] = num * scbonuses[0];
21298 		else clearbonus[i] = scbonuses[0];
21299 		lifebonus[i] = player[i].lives * scbonuses[1];
21300 	}
21301 
21302 	update(0,0);
21303 
21304 	time = 0;
21305 	while(!done)
21306 	{
21307 		if(!scomplete[5]) font_printf(videomodes.hShift+scomplete[0],videomodes.vShift+scomplete[1], 3, 0, "Stage %i Complete!", num);
21308 		else
21309 		{
21310 			font_printf(videomodes.hShift+scomplete[0],videomodes.vShift+scomplete[1], 3, 0, "Stage");
21311 			font_printf(videomodes.hShift+scomplete[2],videomodes.vShift+scomplete[3], 3, 0, "%i",num);
21312 			font_printf(videomodes.hShift+scomplete[4],videomodes.vShift+scomplete[5], 3, 0, "Complete");
21313 		}
21314 
21315 		font_printf(videomodes.hShift+cbonus[0],videomodes.vShift+cbonus[1], 0, 0, "Clear Bonus");
21316 		for(i=0, j=2, k=3; i < maxplayers[current_set]; 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]);
21317 		font_printf(videomodes.hShift+lbonus[0],videomodes.vShift+lbonus[1], 0, 0, "Life bonus");
21318 		for(i=0, j=2, k=3; i < maxplayers[current_set]; 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]);
21319 		if(rush[0] >= 1 && showrushbonus == 1)
21320 		{
21321 			font_printf(videomodes.hShift+rbonus[0],videomodes.vShift+rbonus[1], 0, 0, "Rush Bonus");
21322 			for(i=0, j=2, k=3; i < maxplayers[current_set]; 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]);
21323 		}
21324 		font_printf(videomodes.hShift+tscore[0],videomodes.vShift+tscore[1], 0, 0, "Total Score");
21325 		for(i=0, j=2, k=3; i < maxplayers[current_set]; 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);
21326 
21327 		while(time > nexttime)
21328 		{
21329 			if(!finishtime)    finishtime = time + 4 * GAME_SPEED;
21330 
21331 			for(i=0; i<maxplayers[current_set]; i++)
21332 			{
21333 				if(player[i].lives > 0)
21334 				{
21335 					if(clearbonus[i] > 0)
21336 					{
21337 						addscore(i, 10);
21338 						clearbonus[i] -= 10;
21339 						finishtime = 0;
21340 					}
21341 					else if(lifebonus[i] > 0)
21342 					{
21343 						addscore(i, 10);
21344 						lifebonus[i] -= 10;
21345 						finishtime = 0;
21346 					}
21347 					else if(rush[0] >= 1 && showrushbonus == 1 && (rushbonus[i] > 0))
21348 					{
21349 						addscore(i, 10);
21350 						rushbonus[i] -= 10;
21351 						finishtime = 0;
21352 					}
21353 				}
21354 			}
21355 
21356 			if(!finishtime && !(nexttime&15))
21357 			{
21358 				sound_stop_sample(chan);
21359 				chan = sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol/2,savedata.effectvol/2, 100);
21360 			}
21361 			nexttime++;
21362 		}
21363 
21364 		if(bothnewkeys & (FLAG_ANYBUTTON|FLAG_ESC)) done = 1;
21365 		if(finishtime && time>finishtime) done = 1;
21366 
21367 		update(0,0);
21368 	}
21369 
21370 	// Add remainder of score, incase player skips counter
21371 	for(i=0; i<maxplayers[current_set]; i++)
21372 	{
21373 		if(player[i].lives > 0)
21374 		{
21375 			if(rush[0] >= 1 && showrushbonus == 1)
21376 			{
21377 				addscore(i, rushbonus[i]);
21378 			}
21379 		addscore(i, clearbonus[i]);
21380 		addscore(i, lifebonus[i]);
21381 		}
21382 	}
21383 	unload_background();
21384 
21385 	showComplete = 0;
21386 }
21387 
savelevelinfo()21388 void savelevelinfo()
21389 {
21390 	int i;
21391 	savelevel[current_set].flag = cansave_flag[current_set];
21392 	// don't check flag here save all info, for simple logic
21393 	for(i=0; i<maxplayers[current_set]; i++)
21394 	{
21395 		savelevel[current_set].pLives[i] = player[i].lives;
21396 		savelevel[current_set].pCredits[i] = player[i].credits;
21397 		savelevel[current_set].pScores[i] = player[i].score;
21398 		savelevel[current_set].pSpawnhealth[i] = player[i].spawnhealth;
21399 		savelevel[current_set].pSpawnmp[i] = player[i].spawnmp;
21400 		savelevel[current_set].pWeapnum[i] = player[i].weapnum;
21401 		savelevel[current_set].pColourmap[i] = player[i].colourmap;
21402 		strncpy(savelevel[current_set].pName[i], player[i].name, MAX_NAME_LEN);
21403 	}
21404 	savelevel[current_set].credits = credits;
21405 	savelevel[current_set].level = current_level;
21406 	savelevel[current_set].stage = current_stage;
21407 	savelevel[current_set].which_set = current_set;
21408 	strncpy(savelevel[current_set].dName, set_names[current_set], MAX_NAME_LEN);
21409 }
21410 
21411 
21412 
playlevel(char * filename)21413 int playlevel(char *filename)
21414 {
21415 	int i;
21416 	Script* ptempscript = pcurrentscript;
21417 
21418 	kill_all();
21419 
21420 	if(!new_game)
21421 	{
21422 		savelevelinfo();
21423 		saveGameFile();
21424 		saveHighScoreFile();
21425 		saveScriptFile();
21426 	}
21427 	new_game = 0;
21428 
21429 	load_level(filename);
21430 	time = 0;
21431 	nextplan = 0;
21432 	stalker = NULL;
21433 	firstplayer = NULL;
21434 
21435 	// Fixes the start level executing last button bug
21436 	for(i=0; i<maxplayers[current_set]; i++)
21437 	{
21438 		if(player[i].lives > 0)
21439 		{
21440 			player[i].newkeys = player[i].playkeys = 0;
21441 			player[i].weapnum = level->setweap;
21442 			spawnplayer(i);
21443 			player[i].ent->rush[1] = 0;
21444 		}
21445 	}
21446 
21447 
21448 	//execute a script when level started
21449 	if(Script_IsInitialized(&level_script)) Script_Execute(&level_script);
21450 	if(Script_IsInitialized(&(level->level_script))) Script_Execute(&(level->level_script));
21451 
21452 	while(!endgame)
21453 	{
21454 		update(1,0);
21455 		if(level_completed) endgame |= (!findent(TYPE_ENEMY) || level->type || findent(TYPE_ENDLEVEL));    // Ends when all enemies die or a bonus level
21456 	}
21457 	//execute a script when level finished
21458 	if(Script_IsInitialized(&endlevel_script)) Script_Execute(&endlevel_script);
21459 	if(Script_IsInitialized(&(level->endlevel_script))) Script_Execute(&(level->endlevel_script));
21460 	fade_out(0, 0);
21461 
21462 	for(i=0; i<maxplayers[current_set]; i++)
21463 	{
21464 		if(player[i].ent)
21465 		{
21466 			nomaxrushreset[i] = player[i].ent->rush[1];
21467 			player[i].spawnhealth = player[i].ent->health;
21468 			player[i].spawnmp = player[i].ent->mp;
21469 		}
21470 	}
21471 
21472 	if(!musicoverlap) sound_close_music();
21473 
21474 	kill_all();
21475 	unload_level();
21476 
21477 	pcurrentscript = ptempscript;
21478 
21479 	return (player[0].lives > 0 || player[1].lives > 0 || player[2].lives > 0|| player[3].lives > 0); //4player
21480 }
21481 
21482 
selectplayer(int * players,char * filename)21483 int selectplayer(int *players, char* filename)
21484 {
21485 	s_model* tempmodel;
21486 	entity *example[4] = {NULL,NULL,NULL,NULL};
21487 	int i,x;
21488 	int cmap[MAX_PLAYERS] = {0,1,2,3};
21489 	int tperror = 0;
21490 	int exit = 0;
21491 	int ready[MAX_PLAYERS] = {0,0,0,0};
21492 	int escape = 0;
21493 	int players_busy = 0;
21494 	int players_ready = 0;
21495 	int immediate[MAX_PLAYERS]= {0,0,0,0};
21496 	char string[128] = {""};
21497 	char* buf, *command;
21498 	size_t size = 0;
21499 	ptrdiff_t pos = 0;
21500 	ArgList arglist;
21501 	char argbuf[MAX_ARG_LEN+1] = "";
21502 
21503 	selectScreen = 1;
21504 	kill_all();
21505 	reset_playable_list(1);
21506 
21507 	if(loadGameFile())
21508 	{
21509 		bonus = 0;
21510 		for(i=0; i<MAX_DIFFICULTIES; i++) if(savelevel[i].times_completed > 0) bonus += savelevel[i].times_completed;
21511 	}
21512 
21513 	if(filename && filename[0])
21514 	{
21515 		if(buffer_pakfile(filename, &buf, &size)!=1) shutdown(1, "Failed to load player select file '%s'", filename);
21516 		while(pos < size)
21517 		{
21518 			ParseArgs(&arglist,buf+pos,argbuf);
21519 			command = GET_ARG(0);
21520 			if(command && command[0])
21521 			{
21522 				if(stricmp(command, "music")==0)
21523 				{
21524 					music(GET_ARG(1), GET_INT_ARG(2), atol(GET_ARG(3)));
21525 				}
21526 				else if(stricmp(command, "allowselect")==0)
21527 				{
21528 					load_playable_list(buf+pos);
21529 				}
21530 				else if(stricmp(command, "background")==0)
21531 				{
21532 					load_background(GET_ARG(1), 1);
21533 				}
21534 				else if(stricmp(command, "load")==0){
21535 					tempmodel = findmodel(GET_ARG(1));
21536 					if (!tempmodel)
21537 						load_cached_model(GET_ARG(1), filename, GET_INT_ARG(2));
21538 					else
21539 						update_model_loadflag(tempmodel, GET_INT_ARG(2));
21540 				}
21541 				else
21542 					if(command && command[0])
21543 						printf("Command '%s' is not understood in file '%s'", command, filename);
21544 			}
21545 
21546 			pos += getNewLineStart(buf + pos);
21547 		}
21548 		if(buf != NULL)
21549 		{
21550 			free(buf);
21551 			buf = NULL;
21552 		}
21553 		for(i=0; i<maxplayers[current_set]; i++)
21554 		{
21555 			if(players[i])
21556 			{
21557 				if(!psmenu[i][0] && !psmenu[i][1])
21558 				{
21559 					if(maxplayers[current_set] > 2) example[i] = spawn((float)((111-(maxplayers[current_set]*14))+((i*(320-(166/maxplayers[current_set]))/maxplayers[current_set])+videomodes.hShift)),(float)(230+videomodes.vShift),0 ,spdirection[i] , NULL, -1, nextplayermodel(NULL));
21560 					else example[i] = spawn((float)(83+(videomodes.hShift/2)+(i*(155+videomodes.hShift))),(float)(230+videomodes.vShift),0 ,spdirection[i] , NULL, -1, nextplayermodel(NULL));
21561 				}
21562 				else example[i] = spawn((float)psmenu[i][0], (float)psmenu[i][1], 0, spdirection[i], NULL, -1, nextplayermodel(NULL));
21563 			}
21564 		}
21565 	}
21566 	else // without select.txt
21567 	{
21568 		if(skipselect&&(*skipselect)[current_set][0])
21569 		{
21570 			for(i=0; i<MAX_PLAYERS; i++)
21571 			{
21572 				memset(&player[i], 0, sizeof(s_player));
21573 				if(!players[i]) continue;
21574 
21575 				if((*skipselect)[current_set][i]) // just in case or it will be an array overflow issue
21576 				strncpy(player[i].name, (*skipselect)[current_set][i], MAX_NAME_LEN);
21577 				//else continue;
21578 				if(!noshare) credits = CONTINUES;
21579 				else
21580 				{
21581 					player[i].credits = CONTINUES;
21582 					player[i].hasplayed = 1;
21583 				}
21584 				if(!creditscheat)
21585 				{
21586 					if(noshare) --player[i].credits;
21587 					else --credits;
21588 				}
21589 				player[i].lives = PLAYER_LIVES;
21590 			}
21591 			selectScreen = 0;
21592 			return 1;
21593 		}
21594 
21595 		if(unlockbg && bonus)
21596 		{
21597 			// New alternative background path for PSP
21598 			if(custBkgrds != NULL)
21599 			{
21600 				strcpy(string, custBkgrds);
21601 				strncat(string, "unlockbg", 8);
21602 				load_background(string, 1);
21603 			}
21604 			else load_cached_background("data/bgs/unlockbg", 1);
21605 		}
21606 		else
21607 		{
21608 			// New alternative background path for PSP
21609 			if(custBkgrds != NULL)
21610 			{
21611 				strncpy(string, custBkgrds, 128);
21612 				strncat(string, "select", 6);
21613 				load_background(string, 1);
21614 			}
21615 			else load_cached_background("data/bgs/select", 1);
21616 		}
21617 		if(!music("data/music/menu", 1, 0))
21618 			music("data/music/remix",1,0);
21619 		if(!noshare) credits = CONTINUES;
21620 		for(i=0; i<MAX_PLAYERS; i++)
21621 		{
21622 			memset(&player[i], 0, sizeof(s_player));
21623 			immediate[i] = players[i];
21624 		}
21625 	}
21626 
21627 
21628 	while(!(exit || escape))
21629 	{
21630 		players_busy = 0;
21631 		players_ready = 0;
21632 		for(i=0; i<maxplayers[current_set]; i++)
21633 		{
21634 			// you can't have that character!
21635 			if((tperror == i+1) && !ready[i]) font_printf(75+videomodes.hShift,123+videomodes.vShift,0, 0,"Player %d Choose a Different Character!", i+1);
21636 			if(!ready[i])
21637 			{
21638 				if(player[i].lives <= 0 && (noshare || credits>0) && ((player[i].newkeys & FLAG_ANYBUTTON) || immediate[i]))
21639 				{
21640 					if(noshare)
21641 					{
21642 						player[i].credits = CONTINUES;
21643 						player[i].hasplayed = 1;
21644 					}
21645 
21646 					if(!creditscheat)
21647 					{
21648 						if(noshare) --player[i].credits;
21649 						else --credits;
21650 					}
21651 
21652 					player[i].lives = PLAYER_LIVES;
21653 
21654 					if(!psmenu[i][0] && !psmenu[i][1])
21655 					{
21656 						if(maxplayers[current_set] > 2) example[i] = spawn((float)((111-(maxplayers[current_set]*14))+((i*(320-(166/maxplayers[current_set]))/maxplayers[current_set])+videomodes.hShift)),(float)(230+videomodes.vShift),0 ,spdirection[i] , NULL, -1, nextplayermodel(NULL));
21657 						else example[i] = spawn((float)(83+(videomodes.hShift/2)+(i*(155+videomodes.hShift))),(float)(230+videomodes.vShift),0 ,spdirection[i] , NULL, -1, nextplayermodel(NULL));
21658 					}
21659 					else example[i] = spawn((float)psmenu[i][0], (float)psmenu[i][1], 0, spdirection[i], NULL, -1, nextplayermodel(NULL));
21660 
21661 					if(example[i]==NULL) shutdown(1, "Failed to create player selection object!");
21662 
21663 					// Select Player Direction for select player screen
21664 					// example[i]->direction = spdirection[i]; // moved to spawn method
21665 
21666 					// Make player 2 different colour automatically
21667 					player[i].colourmap = i;
21668 
21669 					while((example[i]->modeldata.maps.hide_start) && (example[i]->modeldata.maps.hide_end) &&
21670 					cmap[i] >= example[i]->modeldata.maps.hide_start &&
21671 					cmap[i] <= example[i]->modeldata.maps.hide_end )
21672 					{
21673 						cmap[i]++;
21674 						if(cmap[i] > example[i]->modeldata.maps_loaded) cmap[i] = 0;
21675 					}
21676 
21677 					player[i].playkeys = 0;
21678 					ent_set_colourmap(example[i], cmap[i]);
21679 
21680 					if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
21681 				}
21682 				else if(player[i].newkeys & FLAG_MOVELEFT && example[i])
21683 				{
21684 					if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
21685 					ent_set_model(example[i], prevplayermodel(example[i]->model)->name);
21686 					cmap[i] = i;
21687 
21688 					while((example[i]->modeldata.maps.hide_start) && (example[i]->modeldata.maps.hide_end) &&
21689 					cmap[i] >= example[i]->modeldata.maps.hide_start &&
21690 					cmap[i] <= example[i]->modeldata.maps.hide_end )
21691 					{
21692 						cmap[i]++;
21693 						if(cmap[i] > example[i]->modeldata.maps_loaded) cmap[i] = 0;
21694 					}
21695 
21696 					ent_set_colourmap(example[i], cmap[i]);
21697 					tperror = 0;
21698 				}
21699 				else if(player[i].newkeys & FLAG_MOVERIGHT && example[i])
21700 				{
21701 					if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
21702 					ent_set_model(example[i], nextplayermodel(example[i]->model)->name);
21703 					cmap[i] = i;
21704 
21705 					while((example[i]->modeldata.maps.hide_start) && (example[i]->modeldata.maps.hide_end) &&
21706 					cmap[i] >= example[i]->modeldata.maps.hide_start && cmap[i] <= example[i]->modeldata.maps.hide_end )
21707 					{
21708 						cmap[i]++;
21709 						if(cmap[i] > example[i]->modeldata.maps_loaded) cmap[i] = 0;
21710 					}
21711 
21712 					ent_set_colourmap(example[i], cmap[i]);
21713 					tperror = 0;
21714 				}
21715 				// oooh pretty colors! - selectable color scheme for player characters
21716 				else if(player[i].newkeys & FLAG_MOVEUP && colourselect && example[i])
21717 				{
21718 					do
21719 					{
21720 						cmap[i]++;
21721 						if(cmap[i] > example[i]->modeldata.maps_loaded) cmap[i] = 0;
21722 					}
21723 					while(
21724 					(example[i]->modeldata.maps.frozen &&
21725 					cmap[i] - 1 == example[i]->modeldata.maps.frozen - 1) ||
21726 					((example[i]->modeldata.maps.hide_start) && (example[i]->modeldata.maps.hide_end) &&
21727 					cmap[i] - 1 >= example[i]->modeldata.maps.hide_start - 1 &&
21728 					cmap[i] - 1 <= example[i]->modeldata.maps.hide_end - 1)
21729 					);
21730 
21731 					ent_set_colourmap(example[i], cmap[i]);
21732 				}
21733 				else if(player[i].newkeys & FLAG_MOVEDOWN && colourselect && example[i])
21734 				{
21735 					do
21736 					{
21737 						cmap[i]--;
21738 						if(cmap[i] < 0) cmap[i] = example[i]->modeldata.maps_loaded;
21739 					}
21740 					while(
21741 					(example[i]->modeldata.maps.frozen &&
21742 					cmap[i] - 1 == example[i]->modeldata.maps.frozen - 1) ||
21743 					((example[i]->modeldata.maps.hide_start) && (example[i]->modeldata.maps.hide_end) &&
21744 					cmap[i] - 1 >= example[i]->modeldata.maps.hide_start - 1 &&
21745 					cmap[i] - 1 <= example[i]->modeldata.maps.hide_end - 1)
21746 					);
21747 
21748 					ent_set_colourmap(example[i], cmap[i]);
21749 				}
21750 				else if((player[i].newkeys & FLAG_ANYBUTTON) && example[i])
21751 				{
21752 
21753 					if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
21754 					strcpy(player[i].name, example[i]->modeldata.name);
21755 					player[i].colourmap = cmap[i];
21756 
21757 					// reports error if players try to use the same character and sameplay mode is off
21758 					if(sameplayer)
21759 					{
21760 						for(x=0; x<maxplayers[current_set]; x++)
21761 						{
21762 							if((strncmp(player[i].name,player[x].name,strlen(player[i].name)) == 0) && (i != x))
21763 							{
21764 								tperror = i+1;
21765 								break;
21766 							}
21767 						}
21768 					}
21769 
21770 					if(!tperror)
21771 					{
21772 						time=0;
21773 						// yay you picked me!
21774 						if(validanim(example[i],ANI_PICK)) ent_set_anim(example[i], ANI_PICK, 0);
21775 						while(!ready[i] && example[i] != NULL)
21776 						{
21777 							update(0,0);
21778 							if((!validanim(example[i],ANI_PICK) || example[i]->modeldata.animation[ANI_PICK]->loop.mode) && time>GAME_SPEED*2) ready[i] = 1;
21779 							else if(!example[i]->animating) ready[i] = 1;
21780 							if(ready[i]) time=0;
21781 						}
21782 					}
21783 				}
21784 			}
21785 			else
21786 			{
21787 				if(!psmenu[i][2] && !psmenu[i][3])
21788 				{
21789 					if(maxplayers[current_set] > 2) font_printf((95-(maxplayers[current_set]*14))+((i*(320-(166/maxplayers[current_set]))/maxplayers[current_set])+videomodes.hShift), 225+videomodes.vShift, 0, 0, "Ready!");
21790 					else font_printf(67+(videomodes.hShift/2)+(i*(155+videomodes.hShift)), 225+videomodes.vShift, 0, 0, "Ready!");
21791 				}
21792 				else font_printf(psmenu[i][2], psmenu[i][3], 0, 0, "Ready!");
21793 			}
21794 
21795 			if(example[i] != NULL) players_busy++;
21796 			if(ready[i]) players_ready++;
21797 		}
21798 
21799 		if(players_busy && players_busy==players_ready && time>GAME_SPEED) exit = 1;
21800 		update(0,0);
21801 
21802 		if(bothnewkeys & FLAG_ESC) escape = 1;
21803 	}
21804 
21805 	// No longer at the select screen
21806 	kill_all();
21807 	sound_close_music();
21808 	selectScreen = 0;
21809 
21810 	return (!escape);
21811 }
21812 
playgame(int * players,unsigned which_set,int useSavedGame)21813 void playgame(int *players,  unsigned which_set, int useSavedGame)
21814 {
21815 	int i;
21816 	current_level = 0;
21817 	current_stage = 1;
21818 	current_set = which_set;
21819 
21820 	if(which_set>=num_difficulties) return;
21821 	// shutdown(1, "Illegal set chosen: index %i (there are only %i sets)!", which_set, num_difficulties);
21822 
21823 	allow_secret_chars = ifcomplete[which_set];
21824 	PLAYER_LIVES = difflives[which_set];
21825 	musicoverlap=diffoverlap[which_set];
21826 	fade=custfade[which_set];
21827 	CONTINUES = diffcreds[which_set];
21828 	magic_type = typemp[which_set];
21829 	if(PLAYER_LIVES == 0) PLAYER_LIVES = 3;
21830 	if(CONTINUES == 0) CONTINUES = 5;
21831 	if(fade == 0) fade = 24;
21832 	sameplayer = same[which_set];
21833 
21834 	memset(player, 0, sizeof(s_player)*4);
21835 
21836 	if(useSavedGame)
21837 	{
21838 		loadScriptFile();
21839 		current_level = savelevel[current_set].level;
21840 		current_stage = savelevel[current_set].stage;
21841 		if(savelevel[current_set].flag == 2) // don't check 1 or 0 becuase if we use saved game the flag must be >0
21842 		{
21843 			for(i=0; i<maxplayers[current_set]; i++)
21844 			{
21845 				player[i].lives = savelevel[current_set].pLives[i];
21846 				player[i].score = savelevel[current_set].pScores[i];
21847 				player[i].colourmap = savelevel[current_set].pColourmap[i];
21848 				player[i].weapnum = savelevel[current_set].pWeapnum[i];
21849 				player[i].spawnhealth = savelevel[current_set].pSpawnhealth[i];
21850 				player[i].spawnmp = savelevel[current_set].pSpawnmp[i];
21851 				strncpy(player[i].name, savelevel[current_set].pName[i], MAX_NAME_LEN);
21852 			}
21853 			credits = savelevel[current_set].credits;
21854 		}
21855 	}
21856 	else
21857 	{
21858 		//max_global_var_index = 0;
21859 		new_game = 1;
21860 	}
21861 
21862 	if((useSavedGame && savelevel[current_set].flag == 2) || selectplayer(players, NULL)) // if save flag is 2 don't select player
21863 	{
21864 		while(current_level < num_levels[which_set])
21865 		{
21866 			if(branch_name[0])  // branch checking
21867 			{
21868 				//current_stage = 1; //jump, jump... perhaps we don't need to reset it, modders should take care of it.
21869 				for(i=0; i<num_levels[which_set]; i++)
21870 				{
21871 					if(stricmp(levelorder[which_set][i]->branchname, branch_name)==0)
21872 					{
21873 						current_level = i;
21874 						break;
21875 					}
21876 					//if(levelorder[which_set][i]->gonext==1) ++current_stage; OX. Commented this line out. Seems to be cause of inacurate stage # complete message.
21877 				}
21878 				branch_name[0] = 0;// clear up so we won't stuck here
21879 			}
21880 			PLAYER_MIN_Z = levelorder[which_set][current_level]->z_coords[0];
21881 			PLAYER_MAX_Z = levelorder[which_set][current_level]->z_coords[1];
21882 			BGHEIGHT = levelorder[which_set][current_level]->z_coords[2];
21883 
21884 			if(levelorder[which_set][current_level]->type==cut_scene)
21885 				playscene(levelorder[which_set][current_level]->filename);
21886 			else if(levelorder[which_set][current_level]->type==select_screen)
21887 			{
21888 				for(i=0; i<MAX_PLAYERS ; i++) players[i] = (player[i].lives>0);
21889 				if(selectplayer(players, levelorder[which_set][current_level]->filename)==0)
21890 				{
21891 					break;
21892 				}
21893 			}
21894 			else if(!playlevel(levelorder[which_set][current_level]->filename))
21895 			{
21896 				if(player[0].lives <= 0 && player[1].lives <= 0 && player[2].lives <= 0 && player[3].lives <= 0){
21897 					gameover();
21898 					if(!noshowhof[which_set]) hallfame(1);
21899 					for(i=0; i<maxplayers[current_set]; i++)
21900 					{
21901 						player[i].hasplayed = 0;
21902 						player[i].weapnum = 0;
21903 					}
21904 				}
21905 				break;
21906 			}
21907 			if(levelorder[which_set][current_level]->gonext==1)
21908 			{
21909 				showcomplete(current_stage);
21910 				for(i=0; i<maxplayers[current_set]; i++)
21911 				{
21912 					player[i].spawnhealth = 0;
21913 					player[i].spawnmp = 0;
21914 				}
21915 				++current_stage;
21916 				savelevel[current_set].stage = current_stage;
21917 			}
21918 			current_level++;
21919 			savelevel[current_set].level = current_level;
21920 			//2007-2-24, gonext = 2, end game
21921 			if(levelorder[which_set][current_level-1]->gonext == 2)
21922 			{
21923 				current_level = num_levels[which_set];
21924 			}
21925 		}
21926 
21927 		if(current_level >= num_levels[which_set])
21928 		{
21929 			bonus += savelevel[current_set].times_completed++;
21930 			saveGameFile();
21931 			saveHighScoreFile();
21932 			fade_out(0, 0);
21933 			hallfame(1);
21934 		}
21935 	}
21936 	// clear global script variant list
21937 	branch_name[0] = 0;
21938 	//max_global_var_index = -1;
21939 	//for(i=0; i<max_indexed_vars; i++) ScriptVariant_Clear(indexed_var_list+i);
21940 	sound_close_music();
21941 }
21942 
choose_difficulty()21943 int choose_difficulty()
21944 {
21945 	int quit = 0;
21946 	int selector = 0;
21947 	int maxdisplay = 5;
21948 	int i, j;
21949 	//float slider = 0;
21950 	int barx, bary, barw, barh;
21951 
21952 	barx = videomodes.hRes/5; bary = _liney(0,2)-2; barw = videomodes.hRes*3/5; barh = 5*(font_heights[0]+1)+4;
21953 	bothnewkeys = 0;
21954 
21955 	if(loadGameFile())
21956 	{
21957 		bonus = 0;
21958 		for(i=0; i<MAX_DIFFICULTIES; i++) if(savelevel[i].times_completed > 0) bonus += savelevel[i].times_completed;
21959 	}
21960 
21961 	while(!quit)
21962 	{
21963 		if(num_difficulties > 1)
21964 		{
21965 			_menutextm(2, 0, 0, "Game Mode");
21966 			for(j=0,i=num_difficulties <= maxdisplay?0:(selector>=maxdisplay?maxdisplay:0); i<num_difficulties; j++,i++)
21967 			{
21968 				if(j < maxdisplay)
21969 				{
21970 					if(bonus >= ifcomplete[i]) _menutextm((selector==i), 2+j, 0, "%s", set_names[i]);
21971 					else
21972 					{
21973 						if(ifcomplete[i]>1) _menutextm((selector==i), 2+j, 0, "%s - Finish Game %i Times To UnLock", set_names[i], ifcomplete[i]);
21974 						else _menutextm((selector==i), 2+j, 0, "%s - Finish Game To UnLock", set_names[i]);
21975 					}
21976 				}
21977 				else break;
21978 			}
21979 			_menutextm((selector==i), 8, 0, "Back");
21980 
21981 			//draw the scroll bar
21982 			if(num_difficulties>maxdisplay)
21983 			{
21984 				spriteq_add_box(barx,  bary,        barw,     barh,   0, color_black, 0); //outerbox
21985 				spriteq_add_line(barx, bary,  barx+8, bary, 1, color_white, 0);
21986 				spriteq_add_line(barx, bary, barx, bary + barh, 1, color_white, 0);
21987 				spriteq_add_line(barx + 8, bary, barx+8, bary+barh,  1, color_white, 0);
21988 				spriteq_add_line(barx, bary+barh, barx+8, bary+barh,  1, color_white, 0);
21989 				spriteq_add_box(barx+1,  bary + selector*(barh-3)/num_difficulties, 7,             3,            2, color_white, 0); //slider
21990 			}
21991 		}
21992 
21993 		update(0,0);
21994 
21995 		if(num_difficulties==1){ // OX. Mods with only one set will auto load that difficulty.
21996 			if(selector==num_difficulties) quit = 1;
21997 			else if(bonus >= ifcomplete[selector]){
21998 				saveslot = selector;
21999 				strncpy(savelevel[saveslot].dName, set_names[saveslot], MAX_NAME_LEN+1);
22000 				return saveslot;
22001 		}
22002 		}
22003 
22004 		if(bothnewkeys & FLAG_ESC) quit = 1;
22005 		if(bothnewkeys & FLAG_MOVEUP)
22006 		{
22007 			--selector;
22008 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22009 		}
22010 		if(bothnewkeys & FLAG_MOVEDOWN)
22011 		{
22012 			++selector;
22013 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22014 		}
22015 		if(selector<0) selector = num_difficulties;
22016 		if(selector>num_difficulties) selector = 0;
22017 		//if(selector<num_difficulties) slider = selector * 4.5;
22018 
22019 		if(bothnewkeys & FLAG_ANYBUTTON){
22020 
22021 			if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
22022 
22023 			if(selector==num_difficulties) quit = 1;
22024 			else if(bonus >= ifcomplete[selector]){
22025 				saveslot = selector;
22026 				strncpy(savelevel[saveslot].dName, set_names[saveslot], MAX_NAME_LEN+1);
22027 				return saveslot;
22028 			}
22029 		}
22030 	}
22031 	bothnewkeys = 0;
22032 	return -1;
22033 }
22034 
load_saved_game()22035 int load_saved_game()
22036 {
22037 	int quit = 0;
22038 	int selector = 0;
22039 	int savedStatus = 0;
22040 	char name[256] = {""};
22041 	int col1 = -8, col2=6;
22042 
22043 	bothnewkeys = 0;
22044 
22045 	if((savedStatus = loadGameFile())) getPakName(name,0);
22046 	for(saveslot=0; saveslot<MAX_DIFFICULTIES; saveslot++) if(savelevel[saveslot].flag && savelevel[saveslot].level) break;
22047 
22048 	while(!quit)
22049 	{
22050 		if(saveslot>=MAX_DIFFICULTIES) // not found
22051 		{
22052 			_menutextm(2, 0, 0, "Load Game");
22053 			_menutext(0, col1, 2, "Saved File:");
22054 			_menutext(0, col2, 2, "Not Found!");
22055 			_menutextm(1, 4, 0, "Back");
22056 
22057 			selector = 2;
22058 		}
22059 		else
22060 		{
22061 			_menutextm(2, -5, 0, "Load Game");
22062 			_menutext(0, col1, -3, "Saved File:");
22063 			if(savedStatus) _menutext(0, col2, -3, "%s", name);
22064 			else _menutext(0, col2, -3, "Not Found!");
22065 
22066 			if(savedStatus){
22067 				_menutext((selector==0), col1, -2, "Mode:");
22068 				_menutext((selector==0), col2, -2, "%s", savelevel[saveslot].dName);
22069 				_menutext(0, col1, -1, "Stage:");
22070 				_menutext(0, col2, -1, "%d", savelevel[saveslot].stage);
22071 				_menutext(0, col1, 0, "Level:");
22072 				_menutext(0, col2, 0, "%d", savelevel[saveslot].level);
22073 				_menutext(0, col1, 1, "Credits:");
22074 				_menutext(0, col2, 1, "%d", savelevel[saveslot].credits);
22075 				_menutext(0, col1, 2, "Player 1 Lives:");
22076 				_menutext(0, col2, 2, "%d", savelevel[saveslot].pLives[0]);
22077 				_menutext(0, col1, 3, "Player 2 Lives:");
22078 				_menutext(0, col2, 3, "%d", savelevel[saveslot].pLives[1]);
22079 				_menutext(0, col1, 4, "Player 3 Lives:");
22080 				_menutext(0, col2, 4, "%d", savelevel[saveslot].pLives[2]);
22081 				_menutext(0, col1, 5, "Player 4 Lives:");
22082 				_menutext(0, col2, 5, "%d", savelevel[saveslot].pLives[3]);
22083 				_menutextm((selector==1), 7, 0, "Start Game");
22084 			}
22085 			_menutextm((selector==2), 8, 0, "Back");
22086 		}
22087 		update(0,0);
22088 
22089 		if(bothnewkeys & FLAG_ESC) quit = 1;
22090 		if(selector == 0 && (bothnewkeys & FLAG_MOVELEFT)){
22091 			while(1){
22092 				--saveslot;
22093 				if(saveslot<0) saveslot = MAX_DIFFICULTIES - 1;
22094 				if(savelevel[saveslot].flag && savelevel[saveslot].level) break;
22095 			}
22096 			sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22097 		}
22098 		if(selector == 0 && (bothnewkeys & FLAG_MOVERIGHT)){
22099 			while(1){
22100 				++saveslot;
22101 				if(saveslot>MAX_DIFFICULTIES - 1) saveslot = 0;
22102 				if(savelevel[saveslot].flag && savelevel[saveslot].level) break;
22103 			}
22104 			sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22105 		}
22106 		if(bothnewkeys & FLAG_MOVEUP){
22107 			--selector;
22108 			sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22109 		}
22110 		if(bothnewkeys & FLAG_MOVEDOWN){
22111 			++selector;
22112 			sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22113 		}
22114 		if(savedStatus){
22115 			if(selector<0) selector = 2;
22116 			if(selector>2) selector = 0;
22117 		}
22118 		else selector = 2;
22119 
22120 		if(selector > 0 && (bothnewkeys & FLAG_ANYBUTTON)){
22121 			sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
22122 			switch(selector){
22123 				case 1:
22124 					return saveslot;
22125 					break;
22126 				case 2:
22127 					quit = 1;
22128 					break;
22129 			}
22130 		}
22131 	}
22132 	bothnewkeys = 0;
22133 	return -1;
22134 }
22135 
choose_mode(int * players)22136 int choose_mode(int *players)
22137 {
22138 	int quit = 0;
22139 	int relback = 0;
22140 	int selector = 0;
22141 	int status = 0;
22142 
22143 	bothnewkeys = 0;
22144 
22145 	while(!quit)
22146 	{
22147 		_menutextm(2, 0, 0, "Choose Mode");
22148 		_menutextm((selector==0), 2, 0, "New Game");
22149 		_menutextm((selector==1), 3, 0, "Load Game");
22150 		_menutextm((selector==2), 5, 0, "Back");
22151 
22152 		update(0,0);
22153 
22154 		if(bothnewkeys & FLAG_ESC) quit = 1;
22155 		if(bothnewkeys & FLAG_MOVEUP)
22156 		{
22157 			--selector;
22158 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22159 		}
22160 		if(bothnewkeys & FLAG_MOVEDOWN)
22161 		{
22162 			++selector;
22163 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22164 		}
22165 		if(selector<0) selector = 2;
22166 		if(selector>2) selector = 0;
22167 
22168 		if(bothnewkeys & FLAG_ANYBUTTON)
22169 		{
22170 			if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
22171 			switch(selector)
22172 			{
22173 				case 0:
22174 					status = choose_difficulty();
22175 					if(status != -1)
22176 					{
22177 						playgame(players, status, 0);
22178 						relback = 1;
22179 						quit = 1;
22180 					}
22181 					break;
22182 				case 1:
22183 					status = load_saved_game();
22184 					if(status != -1)
22185 					{
22186 						playgame(players, status, 1);
22187 						relback = 1;
22188 						quit = 1;
22189 					}
22190 					break;
22191 				default:
22192 					quit = 1;
22193 					break;
22194 			}
22195 		}
22196 	}
22197 	bothnewkeys = 0;
22198 	return relback;
22199 }
22200 
term_videomodes()22201 void term_videomodes()
22202 {
22203 	videomodes.hRes = 0;
22204 	videomodes.vRes = 0;
22205 	video_set_mode(videomodes);
22206 	if(custScenes != NULL) free(custScenes); custScenes = NULL;
22207 	if(custBkgrds != NULL) free(custBkgrds); custBkgrds = NULL;
22208 	if(custLevels != NULL) free(custLevels); custLevels = NULL;
22209 	if(custModels != NULL) free(custModels); custModels = NULL;
22210 }
22211 
22212 // Load Video Mode from file
init_videomodes(int log)22213 void init_videomodes(int log)
22214 {
22215 	char *filename = "data/video.txt";
22216 	int bits = 8, tmp;
22217 	ptrdiff_t pos, len;
22218 	size_t size;
22219 	char *buf = NULL;
22220 	char *command = NULL;
22221 	char *value = NULL;
22222 	ArgList arglist;
22223 	char argbuf[MAX_ARG_LEN+1] = "";
22224 
22225 	if(log) printf("Initializing video............\n");
22226 
22227 	// 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.
22228 #define tryfile(X) if((tmp=openpackfile(X,packfile))!=-1) { closepackfile(tmp); filename=X; goto readfile; }
22229 #if WIN || LINUX
22230 	tryfile("data/videopc.txt");
22231 #elif WII
22232 	tryfile("data/videowii.txt");
22233 	if(CONF_GetAspectRatio() == CONF_ASPECT_16_9) { tryfile("data/video169.txt") }
22234 	else tryfile("data/video43.txt");
22235 #elif PSP
22236 	tryfile("data/videopsp.txt");
22237 	tryfile("data/video169.txt");
22238 #elif DC
22239 	tryfile("data/videodc.txt");
22240 	tryfile("data/video43.txt");
22241 #elif WIZ
22242 	tryfile("data/videowiz.txt");
22243 	tryfile("data/video169.txt");
22244 #elif GP2X
22245 	tryfile("data/videogp2x.txt");
22246 	tryfile("data/video43.txt");
22247 #elif DINGOO
22248 	tryfile("data/videodingoo.txt");
22249 	tryfile("data/video43.txt");
22250 #elif SYMBIAN
22251 	tryfile("data/videosymbian.txt");
22252 #endif
22253 #undef tryfile
22254 
22255 readfile:
22256 	// Read file
22257 	if(buffer_pakfile(filename, &buf, &size)!=1)
22258 	{
22259 		videoMode = 0;
22260 		printf("'%s' not found.\n", filename);
22261 		goto VIDEOMODES;
22262 	}
22263 
22264 	printf("Reading video settings from '%s'.\n", filename);
22265 
22266 	// Now interpret the contents of buf line by line
22267 	pos = 0;
22268 	while(pos<size){
22269 		ParseArgs(&arglist,buf+pos,argbuf);
22270 		command = GET_ARG(0);
22271 
22272 		if(command && command[0]){
22273 			if(stricmp(command, "video")==0){
22274 				videoMode = GET_INT_ARG(1);
22275 			}
22276 			else if(stricmp(command, "scenes")==0){
22277 				len = strlen(GET_ARG(1));
22278 				custScenes = malloc(len + 1);
22279 				strcpy(custScenes, GET_ARG(1));
22280 				custScenes[len] = 0;
22281 			}
22282 			else if(stricmp(command, "backgrounds")==0){
22283 				len = strlen(GET_ARG(1));
22284 				custBkgrds = malloc(len + 1);
22285 				strcpy(custBkgrds, GET_ARG(1));
22286 				custBkgrds[len] = 0;
22287 			}
22288 			else if(stricmp(command, "levels")==0){
22289 				len = strlen(GET_ARG(1));
22290 				custLevels = malloc(len + 1);
22291 				strcpy(custLevels, GET_ARG(1));
22292 				custLevels[len] = 0;
22293 			}
22294 			else if(stricmp(command, "models")==0){
22295 				len = strlen(GET_ARG(1));
22296 				custModels = malloc(len + 1);
22297 				strcpy(custModels, GET_ARG(1));
22298 				custModels[len] = 0;
22299 			}
22300 			else if(stricmp(command, "colourdepth")==0){
22301 				pixelformat=PIXEL_x8;
22302 				value = GET_ARG(1);
22303 				if(stricmp(value, "8bit")==0)
22304 				{
22305 					screenformat=PIXEL_8;
22306 					pixelformat=PIXEL_8;
22307 				}
22308 				else if(stricmp(value, "16bit")==0) { screenformat=PIXEL_16; bits=16; }
22309 				else if(stricmp(value, "32bit")==0) { screenformat=PIXEL_32; bits=32; }
22310 				else if(value[0]==0) screenformat=PIXEL_32;
22311 				else shutdown(1, "Screen colour depth can only be either 8bit, 16bit or 32bit.");
22312 			}
22313 			else
22314 				if(stricmp(command, "forcemode")==0) {}
22315 			else
22316 				if(command && command[0])
22317 					printf("Command '%s' not understood in file '%s'!", command, filename);
22318 		}
22319 		// Go to next line
22320 	pos += getNewLineStart(buf + pos);
22321 	}
22322 
22323 	if(buf != NULL){
22324 		free(buf);
22325 		buf = NULL;
22326 	}
22327 
22328 #if DINGOO || GP2X
22329 	videoMode = 0;
22330 #endif
22331 
22332 #if SYMBIAN
22333 	if(videoMode != 0 && videoMode != 2)
22334 	{
22335 		videoMode = 0;
22336 	}
22337 #endif
22338 
22339 VIDEOMODES:
22340 	switch (videoMode)
22341 	{
22342 		// 320x240 - All Platforms
22343 		case 0:
22344 			videomodes.mode    = savedata.screen[videoMode][0];
22345 			videomodes.filter  = savedata.screen[videoMode][1];
22346 			videomodes.hRes    = 320;
22347 			videomodes.vRes    = 240;
22348 			videomodes.hScale  = 1;
22349 			videomodes.vScale  = 1;
22350 			videomodes.hShift  = 0;
22351 			videomodes.vShift  = 0;
22352 			videomodes.dOffset = 231;
22353 			PLAYER_MIN_Z       = 160;
22354 			PLAYER_MAX_Z       = 232;
22355 			BGHEIGHT           = 160;
22356 	        break;
22357 
22358 		// 480x272 - All Platforms
22359 		case 1:
22360 			videomodes.mode    = savedata.screen[videoMode][0];
22361 			videomodes.filter  = savedata.screen[videoMode][1];
22362 	        videomodes.hRes    = 480;
22363 			videomodes.vRes    = 272;
22364 			videomodes.hScale  = (float)1.5;
22365 			videomodes.vScale  = (float)1.13;
22366 			videomodes.hShift  = 80;
22367 			videomodes.vShift  = 20;
22368 			videomodes.dOffset = 263;
22369 			PLAYER_MIN_Z       = 182;
22370 			PLAYER_MAX_Z       = 264;
22371 			BGHEIGHT           = 182;
22372 			break;
22373 
22374 		// 640x480 - PC, Dreamcast, Wii
22375 		case 2:
22376 			videomodes.mode    = savedata.screen[videoMode][0];
22377 			videomodes.filter  = savedata.screen[videoMode][1];
22378 	        videomodes.hRes    = 640;
22379 			videomodes.vRes    = 480;
22380 			videomodes.hScale  = 2;
22381 			videomodes.vScale  = 2;
22382 			videomodes.hShift  = 160;
22383 			videomodes.vShift  = 35;
22384 			videomodes.dOffset = 464;
22385 			PLAYER_MIN_Z       = 321;
22386 			PLAYER_MAX_Z       = 465;
22387 			BGHEIGHT           = 321;
22388 			break;
22389 
22390 		// 720x480 - PC, Wii
22391 		case 3:
22392 			videomodes.mode    = savedata.screen[videoMode][0];
22393 			videomodes.filter  = savedata.screen[videoMode][1];
22394 	        videomodes.hRes    = 720;
22395 			videomodes.vRes    = 480;
22396 			videomodes.hScale  = 2.25;
22397 			videomodes.vScale  = 2;
22398 			videomodes.hShift  = 200;
22399 			videomodes.vShift  = 35;
22400 			videomodes.dOffset = 464;
22401 			PLAYER_MIN_Z       = 321;
22402 			PLAYER_MAX_Z       = 465;
22403 			BGHEIGHT           = 321;
22404 			break;
22405 
22406 		// 800x480 - PC, Wii, Pandora
22407 		case 4:
22408 			videomodes.mode    = savedata.screen[videoMode][0];
22409 			videomodes.filter  = savedata.screen[videoMode][1];
22410 			videomodes.hRes    = 800;
22411 			videomodes.vRes    = 480;
22412 			videomodes.hScale  = 2.5;
22413 			videomodes.vScale  = 2;
22414 			videomodes.hShift  = 240;
22415 			videomodes.vShift  = 35;
22416 			videomodes.dOffset = 464;
22417 			PLAYER_MIN_Z       = 321;
22418 			PLAYER_MAX_Z       = 465;
22419 			BGHEIGHT           = 321;
22420 			break;
22421 
22422 		// 800x600 - PC, Dreamcast, Wii
22423 		case 5:
22424 			videomodes.mode    = savedata.screen[videoMode][0];
22425 			videomodes.filter  = savedata.screen[videoMode][1];
22426 			videomodes.hRes    = 800;
22427 			videomodes.vRes    = 600;
22428 			videomodes.hScale  = 2.5;
22429 			videomodes.vScale  = 2.5;
22430 			videomodes.hShift  = 240;
22431 			videomodes.vShift  = 44;
22432 			videomodes.dOffset = 580;
22433 			PLAYER_MIN_Z       = 401;
22434 			PLAYER_MAX_Z       = 582;
22435 			BGHEIGHT           = 401;
22436 			break;
22437 
22438 		// 960x540 - PC, Wii
22439 		case 6:
22440 			videomodes.mode    = savedata.screen[videoMode][0];
22441 			videomodes.filter  = savedata.screen[videoMode][1];
22442 	        videomodes.hRes    = 960;
22443 			videomodes.vRes    = 540;
22444 			videomodes.hScale  = 3;
22445 			videomodes.vScale  = 2.25;
22446 			videomodes.hShift  = 320;
22447 			videomodes.vShift  = 40;
22448 			videomodes.dOffset = 522;
22449 			PLAYER_MIN_Z       = 362;
22450 			PLAYER_MAX_Z       = 524;
22451 			BGHEIGHT           = 362;
22452 			break;
22453 
22454 		default:
22455 			shutdown(1, "Invalid video mode: %d in 'data/video.txt', supported modes:\n"
22456 				        "0 - 320x240\n"
22457 						"1 - 480x272\n"
22458 						"2 - 640x480\n"
22459 						"3 - 720x480\n"
22460 						"4 - 800x480\n"
22461 						"5 - 800x600\n"
22462 						"6 - 960x540\n\n", videoMode);
22463 			break;
22464 	}
22465 
22466 #if SDL || WII
22467 	video_stretch(savedata.stretch);
22468 #endif
22469 
22470 	if((vscreen = allocscreen(videomodes.hRes, videomodes.vRes, screenformat)) == NULL) shutdown(1, "Not enough memory!\n");
22471 	videomodes.pixel = pixelbytes[(int)vscreen->pixelformat];
22472 	video_set_mode(videomodes);
22473 	clearscreen(vscreen);
22474 
22475 	if(log) printf("Initialized video.............\t%dx%d (Mode: %d, Depth: %d Bit)\n\n",videomodes.hRes, videomodes.vRes, videoMode, bits);
22476 }
22477 
22478 
22479 
22480 // ----------------------------------------------------------------------------
22481 
22482 
22483 // Set key or button safely (with switching)
safe_set(int * arr,int index,int newkey,int oldkey)22484 void safe_set(int *arr, int index, int newkey, int oldkey){
22485 	int i;
22486 	for(i=0; i<12; i++){
22487 		if(arr[i]==newkey) arr[i] = oldkey;
22488 	}
22489 	arr[index] = newkey;
22490 }
22491 
22492 
keyboard_setup(int player)22493 void keyboard_setup(int player){
22494 	int quit = 0,
22495 		selector = 0,
22496 		setting = -1,
22497 		i, k, ok = 0,
22498 		disabledkey[12] = {0,0,0,0,0,0,0,0,0,0,0,0},
22499 		col1 =-8, col2 = 6;
22500 	ptrdiff_t pos, voffset;
22501 	size_t size;
22502 	ArgList arglist;
22503 	char argbuf[MAX_ARG_LEN+1] = "";
22504 	char *buf, *command, *filename = "data/menu.txt",
22505 	     buttonnames[12][16];
22506 
22507 	printf("Loading control settings.......\t");
22508 
22509 	strncpy(buttonnames[0], "Move Up", 16);
22510 	strncpy(buttonnames[1], "Move Down", 16);
22511 	strncpy(buttonnames[2], "Move Left", 16);
22512 	strncpy(buttonnames[3], "Move Right", 16);
22513 	strncpy(buttonnames[4], "Attack 1", 16);
22514 	strncpy(buttonnames[5], "Attack 2", 16);
22515 	strncpy(buttonnames[6], "Attack 3", 16);
22516 	strncpy(buttonnames[7], "Attack 4", 16);
22517 	strncpy(buttonnames[8], "Jump", 16);
22518 	strncpy(buttonnames[9], "Special", 16);
22519 	strncpy(buttonnames[10], "Start", 16);
22520 	strncpy(buttonnames[11], "Screenshot", 16);
22521 
22522 	savesettings();
22523 	bothnewkeys = 0;
22524 
22525 	// Read file
22526 	if(buffer_pakfile(filename, &buf, &size)){
22527 		// Now interpret the contents of buf line by line
22528 		pos = 0;
22529 		while(pos<size){
22530 			ParseArgs(&arglist,buf+pos,argbuf);
22531 			command = GET_ARG(0);
22532 			if(command[0]){
22533 				if(stricmp(command, "disablekey")==0){
22534 
22535 					if(stricmp(GET_ARG(1), "moveup")==0)
22536 						disabledkey[0] = 1;
22537 					else if(stricmp(GET_ARG(1), "movedown")==0)
22538 						disabledkey[1] = 1;
22539 					else if(stricmp(GET_ARG(1), "moveleft")==0)
22540 						disabledkey[2] = 1;
22541 					else if(stricmp(GET_ARG(1), "moveright")==0)
22542 						disabledkey[3] = 1;
22543 					else if(stricmp(GET_ARG(1), "attack")==0)
22544 						disabledkey[4] = 1;
22545 					else if(stricmp(GET_ARG(1), "attack2") == 0)
22546 						disabledkey[5] = 1;
22547 					else if(stricmp(GET_ARG(1), "attack3") == 0)
22548 						disabledkey[6] = 1;
22549 					else if(stricmp(GET_ARG(1), "attack4") == 0)
22550 						disabledkey[7] = 1;
22551 					else if(stricmp(GET_ARG(1), "jump") == 0)
22552 						disabledkey[8] = 1;
22553 					else if(stricmp(GET_ARG(1), "special") == 0)
22554 						disabledkey[9] = 1;
22555 					else if(stricmp(GET_ARG(1), "start") == 0)
22556 						disabledkey[10] = 1;
22557 					else if(stricmp(GET_ARG(1), "screenshot") == 0)
22558 						disabledkey[11] = 1;
22559 				}
22560 				else if(stricmp(command, "renamekey")==0){
22561 					if(stricmp(GET_ARG(1), "moveup") == 0)
22562 						strncpy(buttonnames[0], GET_ARG(2), 16);
22563 					else if(stricmp(GET_ARG(1), "movedown") == 0)
22564 						strncpy(buttonnames[1], GET_ARG(2), 16);
22565 					else if(stricmp(GET_ARG(1), "moveleft") == 0)
22566 						strncpy(buttonnames[2], GET_ARG(2), 16);
22567 					else if(stricmp(GET_ARG(1), "moveright") == 0)
22568 						strncpy(buttonnames[3], GET_ARG(2), 16);
22569 					else if(stricmp(GET_ARG(1), "attack") == 0)
22570 						strncpy(buttonnames[4], GET_ARG(2), 16);
22571 					else if(stricmp(GET_ARG(1), "attack2") == 0)
22572 						strncpy(buttonnames[5], GET_ARG(2), 16);
22573 					else if(stricmp(GET_ARG(1), "attack3") == 0)
22574 						strncpy(buttonnames[6], GET_ARG(2), 16);
22575 					else if(stricmp(GET_ARG(1), "attack4") == 0)
22576 						strncpy(buttonnames[7], GET_ARG(2), 16);
22577 					else if(stricmp(GET_ARG(1), "jump") == 0)
22578 						strncpy(buttonnames[8], GET_ARG(2), 16);
22579 					else if(stricmp(GET_ARG(1), "special") == 0)
22580 						strncpy(buttonnames[9], GET_ARG(2), 16);
22581 					else if(stricmp(GET_ARG(1), "start") == 0)
22582 						strncpy(buttonnames[10], GET_ARG(2), 16);
22583 					else if(stricmp(GET_ARG(1), "screenshot") == 0)
22584 						strncpy(buttonnames[11], GET_ARG(2), 16);
22585 				}
22586 				else if(stricmp(command, "fontmonospace")==0){
22587 					 // here to keep from crashing
22588 				}
22589 				else
22590 					if(command && command[0])
22591 						printf("Command '%s' not understood in file '%s'!", command, filename);
22592 
22593 			}
22594 			// Go to next line
22595 			pos += getNewLineStart(buf + pos);
22596 		}
22597 		if(buf != NULL){
22598 			free(buf);
22599 			buf = NULL;
22600 		}
22601 	}
22602 
22603 	while(disabledkey[selector]) if(++selector>11) break;
22604 
22605 	while(!quit){
22606 		voffset = -6;
22607 		_menutextm(2, -8, 0, "Player %i", player+1);
22608 		for(i = 0; i < 12; i++){
22609 			  if(!disabledkey[i]){
22610 					_menutext((selector==i), col1, voffset, "%s", buttonnames[i]);
22611 					_menutext((selector==i), col2, voffset, "%s", control_getkeyname(savedata.keys[player][i]));
22612 					voffset++;
22613 			  }
22614 		}
22615 		_menutextm((selector==12), 7, 0, "OK");
22616 		_menutextm((selector==13), 8, 0, "Cancel");
22617 		update((level!=NULL),0);
22618 
22619 		if(setting > -1){
22620 			if(bothnewkeys & FLAG_ESC){
22621 				savedata.keys[player][setting] = ok;
22622 				sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 50);
22623 				setting = -1;
22624 			}
22625 			if(setting > -1){
22626 				k = control_scankey();
22627 				if(k){
22628 					safe_set(savedata.keys[player], setting, k, ok);
22629 					sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
22630 					setting = -1;
22631 					// Prevent accidental screenshot
22632 					bothnewkeys = 0;
22633 				}
22634 			}
22635 		}
22636 		else{
22637 			if(bothnewkeys & FLAG_ESC) quit = 1;
22638 			if(bothnewkeys & FLAG_MOVEUP){
22639 				do{ if(--selector<0) break; }while(disabledkey[selector]);
22640 				sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22641 			}
22642 			if(bothnewkeys & FLAG_MOVEDOWN){
22643 				do{ if(++selector>11) break; }while(disabledkey[selector]);
22644 				sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22645 			}
22646 			if(selector<0) selector = 13;
22647 			if(selector>13){
22648 				 selector = 0;
22649 				 while(disabledkey[selector]) if(++selector>11) break;
22650 			}
22651 			if(bothnewkeys & FLAG_ANYBUTTON){
22652 				sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
22653 				if(selector==12) quit = 2;
22654 				else if(selector==13) quit = 1;
22655 				else{
22656 					setting = selector;
22657 					ok = savedata.keys[player][setting];
22658 					savedata.keys[player][setting] = 0;
22659 #if DOS || SDL || PSP || WII
22660 					keyboard_getlastkey();
22661 #endif
22662 				}
22663 			}
22664 		}
22665 	}
22666 
22667 	if(quit==2){
22668 		apply_controls();
22669 		savesettings();
22670 	}
22671 	else loadsettings();
22672 
22673 
22674 	update(0,0);
22675 	bothnewkeys = 0;
22676 	printf("Done!\n");
22677 }
22678 
22679 
22680 #ifndef DISABLE_MOVIE
movie_options()22681 void movie_options(){
22682 	int quit = 0;
22683 	int selector = 1; // 0
22684 
22685 	bothnewkeys = 0;
22686 
22687 	while(!quit){
22688 		_menutextm(2, 1, 0, "Movie Mode");
22689 		_menutextm((selector==0), 2, 0, "Save Movie");
22690 		_menutextm((selector==1), 3, 0, "Load Movie");
22691 		_menutextm((selector==2), 5, 0, "Back");
22692 		update((level!=NULL),0);
22693 
22694 		if(bothnewkeys & FLAG_ESC) quit = 1;
22695 		if(bothnewkeys & FLAG_MOVEUP){
22696 			--selector;
22697 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22698 		}
22699 		if(bothnewkeys & FLAG_MOVEDOWN){
22700 			++selector;
22701 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22702 		}
22703 		if(selector<0) selector = 2;
22704 		if(selector>2) selector = 0;
22705 		if(bothnewkeys & FLAG_ANYBUTTON){
22706 
22707 			if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
22708 
22709 			switch(selector){
22710 				case 0:
22711 					movie_closefile(); //close first
22712 					movie_openfile(1); // save movie
22713 					quit = 1;
22714 					break;
22715 				case 1:
22716 					selector = 0;
22717 					movie_closefile(); //close first
22718 					movie_openfile(0); // play movie
22719 					quit = 1;
22720 					break;
22721 				default:
22722 					quit = (bothnewkeys & FLAG_ANYBUTTON);
22723 			}
22724 		}
22725 	}
22726 	savesettings();
22727 	bothnewkeys = 0;
22728 }
22729 #endif
22730 
22731 
22732 
input_options()22733 void input_options(){
22734 	int quit = 0;
22735 	int selector = 1; // 0
22736 
22737 	bothnewkeys = 0;
22738 
22739 	while(!quit){
22740 		_menutextm(2, -5, 0, "Control Options");
22741 
22742 #if PSP
22743 		if(savedata.usejoy) _menutext((selector==0), -4, -2, "Analog Pad Enabled");
22744 		else _menutext((selector==0), -4, -2, "Analog Pad Disabled");
22745 #elif WII
22746 		if(savedata.usejoy) _menutext((selector==0), -4, -2, "Nunchuk Analog Enabled");
22747 		else _menutext((selector==0), -4, -2, "Nunchuk Analog Disabled");
22748 #else
22749 		if(savedata.usejoy){
22750 			_menutext((selector==0),  -4, -2, "GamePads Enabled");
22751 			if(!control_getjoyenabled()){
22752 				_menutext((selector==0), 7, -2, " - Device Not Ready");
22753 			}
22754 		}
22755 		else _menutext((selector==0),  -4, -2, "GamePads Disabled");
22756 #endif
22757 
22758 		_menutext((selector==1), -4, -1, "Setup Player 1...");
22759 		_menutext((selector==2), -4, 0, "Setup Player 2...");
22760 		_menutext((selector==3), -4, 1, "Setup Player 3...");
22761 		_menutext((selector==4), -4, 2, "Setup Player 4...");
22762 		_menutextm((selector==5), 7, 0, "Back");
22763 		update((level!=NULL),0);
22764 
22765 		if(bothnewkeys & FLAG_ESC) quit = 1;
22766 		if(bothnewkeys & FLAG_MOVEUP){
22767 			--selector;
22768 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22769 		}
22770 		if(bothnewkeys & FLAG_MOVEDOWN){
22771 			++selector;
22772 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22773 		}
22774 		if(selector<0) selector = 5;
22775 		if(selector>5) selector = 0;
22776 		if(bothnewkeys & (FLAG_MOVELEFT|FLAG_MOVERIGHT|FLAG_ANYBUTTON)){
22777 
22778 			if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
22779 
22780 			switch(selector){
22781 				case 0:
22782 					control_usejoy((savedata.usejoy ^= 1));
22783 					break;
22784 				case 1:
22785 					keyboard_setup(0);
22786 					break;
22787 				case 2:
22788 					keyboard_setup(1);
22789 					break;
22790 				case 3:
22791 					keyboard_setup(2);
22792 					break;
22793 				case 4:
22794 					keyboard_setup(3);
22795 					break;
22796 				default:
22797 					quit = (bothnewkeys & FLAG_ANYBUTTON);
22798 			}
22799 		}
22800 	}
22801 	savesettings();
22802 	bothnewkeys = 0;
22803 }
22804 
22805 
22806 
sound_options()22807 void sound_options(){
22808 
22809 	int quit = 0;
22810 	int selector = 0;
22811 	int dir;
22812 	int col1 = -8;
22813 	int col2 = 6;
22814 
22815 	bothnewkeys = 0;
22816 
22817 	while(!quit){
22818 		_menutextm(2, -5, 0, "Sound Options");
22819 		_menutext((selector==0), col1, -2, "Sound Volume:");
22820 		_menutext((selector==0), col2, -2, "%i", savedata.soundvol);
22821 		_menutext((selector==1), col1, -1, "SFX Volume:");
22822 		_menutext((selector==1), col2, -1, "%i", savedata.effectvol);
22823 		_menutext((selector==2), col1, 0, "Music Volume:");
22824 		_menutext((selector==2), col2, 0, "%i", savedata.musicvol);
22825 		_menutext((selector==3), col1, 1, "BGM:");
22826 		_menutext((selector==3), col2, 1, "%s", (savedata.usemusic ? "Enabled" : "Disabled"));
22827 		_menutext((selector==4), col1, 2, "Show Titles:");
22828 		_menutext((selector==4), col2, 2, "%s", (savedata.showtitles ? "Yes" : "No"));
22829 		_menutext((selector==5), col1, 3, "Advanced Options...");
22830 		_menutextm((selector==6), 7, 0, "Back");
22831 
22832 		update((level!=NULL),0);
22833 
22834 		if(bothnewkeys & FLAG_ESC) quit = 1;
22835 		if(bothnewkeys & FLAG_MOVEUP){
22836 			--selector;
22837 
22838 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22839 		}
22840 		if(bothnewkeys & FLAG_MOVEDOWN){
22841 			++selector;
22842 
22843 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22844 		}
22845 		if(selector<0) selector = 6;
22846 		if(selector>6) selector = 0;
22847 
22848 		if(bothnewkeys & (FLAG_MOVELEFT|FLAG_MOVERIGHT|FLAG_ANYBUTTON)){
22849 			dir = 0;
22850 
22851 			if(bothnewkeys & FLAG_MOVELEFT) dir = -1;
22852 			else if(bothnewkeys & FLAG_MOVERIGHT) dir = 1;
22853 
22854 			if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
22855 
22856 			switch(selector){
22857 				case 0:
22858 					savedata.soundvol += dir;
22859 					if(savedata.soundvol < 0) savedata.soundvol = 0;
22860 					if(savedata.soundvol > 15) savedata.soundvol = 15;
22861 					SB_setvolume(SB_VOICEVOL, savedata.soundvol);
22862 					break;
22863 				case 1:
22864 					savedata.effectvol += 4*dir;
22865 					if(savedata.effectvol < 0) savedata.effectvol = 0;
22866 					if(savedata.effectvol > 512) savedata.effectvol = 512;
22867 					break;
22868 				case 3:
22869 					if(!dir) break;
22870 					if(!savedata.usemusic){
22871 						savedata.usemusic = 1;
22872 						music("data/music/remix", 1, 0);
22873 					}
22874 					else{
22875 						savedata.usemusic = 0;
22876 						sound_close_music();
22877 					}
22878 					break;
22879 				case 2:
22880 					savedata.musicvol += 4*dir;
22881 					if(savedata.musicvol < 0) savedata.musicvol = 0;
22882 					if(savedata.musicvol > 512) savedata.musicvol = 512;
22883 					sound_volume_music(savedata.musicvol, savedata.musicvol);
22884 					break;
22885 				case 4:
22886 					savedata.showtitles = !savedata.showtitles;
22887 					break;
22888 				case 5:
22889 					soundcard_options();
22890 					break;
22891 				default:
22892 					quit = 1;
22893 			}
22894 		}
22895 	}
22896 	savesettings();
22897 	bothnewkeys = 0;
22898 }
22899 
config_settings()22900 void config_settings(){    //  OX. Load from / save to default.cfg. Restore OpenBoR "factory" settings.
22901 	int quit = 0;
22902 	int selector = 0;
22903 	int dir = 0;
22904 	int saved = 0;
22905 	int loaded = 0;
22906 	int restored = 0;
22907 
22908 	bothnewkeys = 0;
22909 
22910 	while(!quit){
22911 		_menutextm(2, -5, 0, "Configuration Settings");
22912 
22913 		if(saved == 1) _menutextm((selector==0), -2, 0, "Save Settings To Default.cfg%s", "  Done!");
22914 		else _menutextm((selector==0), -2, 0, "Save Settings To Default.cfg%s","");
22915 
22916 		if(loaded == 1) _menutextm((selector==1), -1, 0, "Load Settings From Default.cfg%s", "  Done!");
22917 		else  _menutextm((selector==1), -1, 0, "Load Settings From Default.cfg%s", "");
22918 
22919 		if(restored == 1) _menutextm((selector==2), 0, 0, "Restore OpenBoR Defaults%s", "  Done!");
22920 		else _menutextm((selector==2), 0, 0, "Restore OpenBoR Defaults%s", "");
22921 
22922 		_menutextm((selector==3), 1, 0, "Back");
22923 
22924 		update((level!=NULL),0);
22925 
22926 		if(bothnewkeys & FLAG_ESC) quit = 1;
22927 		if(bothnewkeys & FLAG_MOVEUP){
22928 			--selector;
22929 
22930 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22931 		}
22932 		if(bothnewkeys & FLAG_MOVEDOWN){
22933 			++selector;
22934 
22935 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
22936 		}
22937 
22938 		if(selector<0) selector = 3;
22939 		if(selector>3) selector = 0;
22940 
22941 		if(bothnewkeys & (FLAG_MOVELEFT|FLAG_MOVERIGHT|FLAG_ANYBUTTON)){
22942 			dir = 0;
22943 
22944 			if(bothnewkeys & FLAG_MOVELEFT) dir = -1;
22945 			else if(bothnewkeys & FLAG_MOVERIGHT) dir = 1;
22946 
22947 			if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
22948 
22949 			switch(selector){
22950 				case 0:
22951 					saveasdefault();
22952 					saved = 1;
22953 					break;
22954 
22955 				case 1:
22956 					loadfromdefault();
22957 					//shutdown(2, "\nSettings Loaded From Default.cfg. Restart Required.\n\n");
22958 					init_videomodes(0);
22959 					SB_setvolume(SB_VOICEVOL, savedata.soundvol);
22960 					sound_volume_music(savedata.musicvol, savedata.musicvol);
22961 					loaded = 1;
22962 					break;
22963 				case 2:
22964 					clearsettings();
22965 					//shutdown(2, "\nSettings Loaded From Default.cfg. Restart Required.\n\n");
22966 					init_videomodes(0);
22967 					SB_setvolume(SB_VOICEVOL, savedata.soundvol);
22968 					sound_volume_music(savedata.musicvol, savedata.musicvol);
22969 					restored = 1;
22970 					break;
22971 				default:
22972 					quit = 1;
22973 			}
22974 		}
22975 	}
22976 	savesettings();
22977 	bothnewkeys = 0;
22978 }
22979 
22980 
cheatoptions()22981 void cheatoptions(){    //  LTB 1-13-05 took out sameplayer option
22982 	int quit = 0;
22983 	int selector = 0;
22984 	int dir;
22985 	int col1 = -8;
22986 	int col2 = 6;
22987 
22988 	bothnewkeys = 0;
22989 
22990 	while(!quit){
22991 		_menutextm(2, -5, 0, "Cheat Options");
22992 		_menutext((selector==0), col1, -3, "Brightness:");
22993 		_menutext((selector==0), col2, -3, "%i", savedata.brightness);
22994 		_menutext((selector==1), col1, -2, "Gamma:");
22995 		_menutext((selector==1), col2, -2, "%i", savedata.gamma);
22996 		_menutext((selector==2), col1, -1, "Control Options...");
22997 		_menutext((selector==3), col1, 0, "Sound Options...");
22998 		_menutext((selector==4), col1, 1, "System Options...");
22999 
23000 		if(livescheat)         _menutext((selector==5), col1, 2, "Infinite Lives On");
23001 		else if(!livescheat)   _menutext((selector==5), col1, 2, "Infinite Lives Off");
23002 		if(creditscheat)       _menutext((selector==6), col1, 3, "Infinite Credits On"); // Enemies fall down when you respawn
23003 		else if(!creditscheat) _menutext((selector==6), col1, 3, "Infinite Credits Off");//Enemies don't fall down when you respawn
23004 		if(healthcheat)        _menutext((selector==7), col1, 4, "Infinite Health On"); // Enemies fall down when you respawn
23005 		else if(!healthcheat)  _menutext((selector==7), col1, 4, "Infinite Health Off");//Enemies don't fall down when you respawn
23006 
23007 		_menutextm((selector==8), 7, 0, "Back");
23008 
23009 		update((level!=NULL),0);
23010 
23011 		if(bothnewkeys & FLAG_ESC) quit = 1;
23012 		if(bothnewkeys & FLAG_MOVEUP){
23013 			--selector;
23014 
23015 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23016 		}
23017 		if(bothnewkeys & FLAG_MOVEDOWN){
23018 			++selector;
23019 
23020 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23021 		}
23022 
23023 		if(selector<0) selector = 8;  // 7-1-2005 //13-1-2005 changed to 11
23024 		if(selector>8) selector = 0;//    7-1-2005 6 changed to 10 //13-1-2005 changed to 11
23025 
23026 		if(bothnewkeys & (FLAG_MOVELEFT|FLAG_MOVERIGHT|FLAG_ANYBUTTON)){
23027 			dir = 0;
23028 
23029 			if(bothnewkeys & FLAG_MOVELEFT) dir = -1;
23030 			else if(bothnewkeys & FLAG_MOVERIGHT) dir = 1;
23031 
23032 			if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
23033 
23034 			switch(selector){
23035 				case 0:
23036 					savedata.brightness += 8*dir;
23037 					if(savedata.brightness < -256) savedata.brightness = -256;
23038 					if(savedata.brightness > 256) savedata.brightness = 256;
23039 					vga_vwait();
23040 					palette_set_corrected(pal, savedata.gamma,savedata.gamma,savedata.gamma, savedata.brightness,savedata.brightness,savedata.brightness);
23041 					break;
23042 				case 1:
23043 					savedata.gamma += 8*dir;
23044 					if(savedata.gamma < -256) savedata.gamma = -256;
23045 					if(savedata.gamma > 256) savedata.gamma = 256;
23046 					vga_vwait();
23047 					palette_set_corrected(pal, savedata.gamma,savedata.gamma,savedata.gamma, savedata.brightness,savedata.brightness,savedata.brightness);
23048 					break;
23049 				case 2:
23050 					input_options();
23051 					break;
23052 				case 3:
23053 					sound_options();
23054 					break;
23055 				case 4:
23056 					system_options();
23057 					break;
23058 				case 5:
23059 					if(!livescheat) livescheat = 1;
23060 					else if(livescheat) livescheat = 0;
23061 					break;
23062 				case 6:
23063 					if(!creditscheat) creditscheat = 1;
23064 					else if(creditscheat) creditscheat = 0;
23065 					break;
23066 				case 7:
23067 					if(!healthcheat) healthcheat = 1;
23068 					else if(healthcheat) healthcheat = 0;
23069 					break;
23070 
23071 				default:
23072 					quit = 1;
23073 			}
23074 		}
23075 	}
23076 	savesettings();
23077 	bothnewkeys = 0;
23078 }
23079 
23080 
system_options()23081 void system_options(){
23082 
23083 	int quit = 0;
23084 	int selector = 0;
23085 	int dir = 0;
23086 	int ret = 6;
23087 	int col1 = -8;
23088 	int col2 = 5;
23089 
23090 #if PSP
23091 	int batteryPercentage = 0;
23092 	int batteryLifeTime = 0;
23093 	int externalPower = 0;
23094 #endif
23095 
23096 	bothnewkeys = 0;
23097 
23098 	while(!quit){
23099 		_menutextm(2, -5, 0, "System Options");
23100 
23101 		_menutext(0, col1, -2, "Total RAM:");
23102 		_menutext(0, col2, -2, "%s KBytes", commaprint(getSystemRam(KBYTES)));
23103 
23104 		_menutext(0, col1, -1, "Used RAM:");
23105 		_menutext(0, col2, -1, "%s KBytes", commaprint(getUsedRam(KBYTES)));
23106 
23107 		_menutext((selector==0), col1, 0, "Debug Info:");
23108 		_menutext((selector==0), col2, 0, (savedata.debuginfo ? "Enabled" : "Disabled"));
23109 
23110 		_menutext((selector==1), col1, 1, "File Logging:");
23111 		_menutext((selector==1), col2, 1, (savedata.uselog ? "Enabled" : "Disabled"));
23112 
23113 		_menutext((selector==2), col1, 2, "Players: ");
23114 		if(!ctrlmaxplayers[current_set]) _menutext((selector==2), col2, 2, "%i", maxplayers[current_set]);
23115 		else _menutext((selector==2), col2, 2, "%i by Mod", maxplayers[current_set]);
23116 
23117 		_menutext((selector==3), col1, 3, "Versus Damage:", 0);
23118 		if(versusdamage == 0) _menutext((selector==3), col2, 3, "Disabled by Mod");
23119 		else if(versusdamage == 1) _menutext((selector==3), col2, 3, "Enabled by Mod");
23120 		else
23121 		{
23122 			if(savedata.mode) _menutext((selector==3), col2, 3, "Disabled");//Mode 1 - Players CAN'T attack each other
23123 			else _menutext((selector==3), col2, 3, "Enabled");//Mode 2 - Players CAN attack each other
23124 		}
23125 
23126 		_menutext((selector==4), col1, 4, "Cheats:");
23127 		_menutext((selector==4), col2, 4, forcecheatsoff?"Disabled by Mod":(cheats?"On":"Off"));
23128 
23129 #ifndef DC
23130 
23131 		_menutext((selector==5), col1, 5, "Config Settings");
23132 
23133 #endif
23134 
23135 #if PSP
23136 		externalPower = scePowerIsPowerOnline();
23137 		_menutext((selector==6), col1, 6, "CPU Speed:");
23138 		_menutext((selector==6), col2, 6, "%d MHz", scePowerGetCpuClockFrequency());
23139 		if(!externalPower){
23140 			batteryPercentage = scePowerGetBatteryLifePercent();
23141 			batteryLifeTime = scePowerGetBatteryLifeTime();
23142 			_menutext(0, col1, 7, "Battery:");
23143 			if(batteryPercentage < 0 || batteryLifeTime < 0) _menutext(0, col2, 8, "Calculating...");
23144 			else _menutext(0, col2, 7, "%d%% - %02d:%02d", batteryPercentage, batteryLifeTime/60,batteryLifeTime-(batteryLifeTime/60*60));
23145 		}
23146 		else{
23147 			_menutext(0, col1, 7, "Charging:");
23148 			_menutext(0, col2, 7, "%d%% AC Power", scePowerGetBatteryLifePercent());
23149 		}
23150 		ret = 7;
23151 #endif
23152 
23153 		_menutextm((selector==ret), 8, 0, "Back");
23154 
23155 		update((level!=NULL),0);
23156 
23157 		if(bothnewkeys & FLAG_ESC) quit = 1;
23158 		if(bothnewkeys & FLAG_MOVEUP){
23159 			--selector;
23160 			sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23161 		}
23162 		if(bothnewkeys & FLAG_MOVEDOWN){
23163 			++selector;
23164 			sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23165 		}
23166 
23167 		if(selector < 0) selector = ret;
23168 		if(selector > ret) selector = 0;
23169 
23170 		if(bothnewkeys & (FLAG_MOVELEFT|FLAG_MOVERIGHT|FLAG_ANYBUTTON)){
23171 			dir = 0;
23172 			if(bothnewkeys & FLAG_MOVELEFT) dir = -1;
23173 			else if(bothnewkeys & FLAG_MOVERIGHT) dir = 1;
23174 			sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
23175 
23176 			switch(selector){
23177 				case 0:
23178 					savedata.debuginfo = !savedata.debuginfo;
23179 					break;
23180 
23181 				case 1:
23182 					savedata.uselog =  !savedata.uselog;
23183 					break;
23184 
23185 				case 2:
23186 					if(!ctrlmaxplayers[current_set]){
23187 						if(maxplayers[current_set] == 2) maxplayers[current_set] = 4;
23188 						else maxplayers[current_set] = 2;
23189 					}
23190 					break;
23191 
23192 				case 3:
23193 					if(versusdamage > 1)
23194 					{
23195 						if(savedata.mode) savedata.mode = 0;
23196 						else              savedata.mode = 1;
23197 					}
23198 					break;
23199 
23200 				case 4:
23201 					cheats = !cheats;
23202 					break;
23203 
23204 #ifndef DC
23205 
23206 				case 5:
23207 					config_settings();
23208 					break;
23209 
23210 #endif
23211 
23212 #ifdef PSP
23213 				case 6:
23214 					savedata.pspcpuspeed += dir;
23215 					if(savedata.pspcpuspeed<0) savedata.pspcpuspeed = 2;
23216 					if(savedata.pspcpuspeed>2) savedata.pspcpuspeed = 0;
23217 					switch(savedata.pspcpuspeed){
23218 				case 0:
23219 					scePowerSetClockFrequency(222, 222, 111);
23220 					break;
23221 				case 1:
23222 					scePowerSetClockFrequency(266, 266, 133);
23223 					break;
23224 				case 2:
23225 					scePowerSetClockFrequency(333, 333, 166);
23226 					break;
23227 					}
23228 					break;
23229 #endif
23230 
23231 				default:
23232 					quit = 1;
23233 					break;
23234 			}
23235 		}
23236 	}
23237 	savesettings();
23238 	bothnewkeys = 0;
23239 }
23240 
23241 
video_options()23242 void video_options(){
23243 	int quit = 0;
23244 	int selector = 0;
23245 	int dir;
23246 	int col1 = -8, col2 = 6;
23247 
23248 	bothnewkeys = 0;
23249 
23250 	while(!quit){
23251 		_menutextm(2, -5, 0, "Video Options");
23252 		_menutext((selector==0), col1, -3, "Brightness:");
23253 		_menutext((selector==0), col2, -3, "%i", savedata.brightness);
23254 		_menutext((selector==1), col1, -2, "Gamma:");
23255 		_menutext((selector==1), col2, -2, "%i", savedata.gamma);
23256 		_menutext((selector==2), col1, -1, "Window Offset:");
23257 		_menutext((selector==2), col2, -1, "%i", savedata.windowpos);
23258 
23259 #if DOS || DC || GP2X || DINGOO
23260 		_menutextm((selector==3), 7, 0, "Back");
23261 		if(selector<0) selector = 3;
23262 		if(selector>3) selector = 0;
23263 #endif
23264 
23265 #if XBOX
23266 		_menutext((selector==3), col1, 0, "Screen Size:");
23267 		_menutext((selector==3), col2, 0, "Guide R/L Thumbsticks");
23268 		_menutext((selector==3), col1, 1, "GFX Filters:");
23269 		_menutext((selector==3), col2, 1, "Press R/L Thumbsticks");
23270 		_menutextm((selector==4), 7, 0, "Back");
23271 		if(selector<0) selector = 4;
23272 		if(selector>4) selector = 0;
23273 #endif
23274 
23275 #if WII
23276 		_menutext((selector==3), col1, 0, "Display Mode:");
23277 		_menutext((selector==3), col2, 0, savedata.fullscreen ? "Stretch to Screen" : "Preserve Aspect Ratio");
23278 		_menutextm((selector==4), 7, 0, "Back");
23279 		if(selector<0) selector = 4;
23280 		if(selector>4) selector = 0;
23281 #endif
23282 
23283 #if SDL
23284 #ifndef GP2X
23285 		_menutext((selector==3), col1, 0, "Display Mode:");
23286 		_menutext((selector==3), col2, 0, "%s", savedata.fullscreen ? "Full" : "Window");
23287 
23288 		_menutext((selector==4), col1, 1, "Video Backend:");
23289 		_menutext((selector==4), col2, 1, "%s", opengl ? "OpenGL" : "SDL");
23290 
23291 		if(opengl)
23292 		{
23293 			_menutext((selector==5), col1, 2, "Screen:");
23294 			if(savedata.fullscreen) _menutext((selector==5), col2, 2, "Automatic");
23295 			else _menutext((selector==5), col2, 2, "%4.2fx - %ix%i", savedata.glscale, (int)(videomodes.hRes*savedata.glscale), (int)(videomodes.vRes*savedata.glscale));
23296 
23297 			_menutext((selector==6), col1, 3, "Filters:");
23298 			_menutext((selector==6), col2, 3, "%s", savedata.glscale!=1.0 ? (savedata.glfilter[savedata.fullscreen] ? "Simple" : "Bilinear") : "Disabled");
23299 		}
23300 		else
23301 		{
23302 			_menutext((selector==5), col1, 2, "Screen:");
23303 			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]);
23304 			else _menutext((selector==5), col2, 2, "Disabled");
23305 
23306 			_menutext((selector==6), col1, 3, "Filters:");
23307 			_menutext((selector==6), col2, 3, "%s", savedata.screen[videoMode][0]==2 ? GfxBlitterNames[(int)savedata.screen[videoMode][1]] : "Disabled");
23308 		}
23309 
23310 		if(savedata.fullscreen)
23311 		{
23312 			_menutext((selector==7), col1, 4, "Fullscreen Type:");
23313 			_menutext((selector==7), col2, 4, "%s", savedata.stretch ? "Stretch to Screen" : "Preserve Aspect Ratio");
23314 		} else if(selector==7) selector = (bothnewkeys & FLAG_MOVEUP) ? 6 : 8;
23315 
23316 		_menutextm((selector==8), 7, 0, "Back");
23317 		if(selector<0) selector = 8;
23318 		if(selector>8) selector = 0;
23319 #endif
23320 #endif
23321 
23322 #if PSP
23323 		_menutext((selector==3), col1, 0, "Screen:");
23324 		_menutext((selector==3), col2, 0, "%s", displayFormat[(int)videomodes.mode].name);
23325 		_menutext((selector==4), col1, 1, "Filters:");
23326 		_menutext((selector==4), col2, 1, "%s", filterName[(int)videomodes.filter]);
23327 		_menutext((selector==5), col1, 2, "Display:");
23328 		_menutext((selector==5), col2, 2, "%s", displayName[displayMode]);
23329 		_menutext((selector>=6 && selector<=9), col1, 3, "Overscan:");
23330 		_menutext((selector>=6 && selector<=9), col2+1.5, 3, ".");
23331 		_menutext((selector>=6 && selector<=9), col2+3.5, 3, ".");
23332 		_menutext((selector>=6 && selector<=9), col2+5.5, 3, ".");
23333 		_menutext((selector==6), col2, 3, "%02d", savedata.overscan[0]);
23334 		_menutext((selector==7), col2+2, 3, "%02d", savedata.overscan[1]);
23335 		_menutext((selector==8), col2+4, 3, "%02d", savedata.overscan[2]);
23336 		_menutext((selector==9), col2+6, 3, "%02d", savedata.overscan[3]);
23337 		_menutextm((selector==10), 7, 0, "Back");
23338 		if(selector<0) selector = 10;
23339 		if(selector>10) selector = 0;
23340 #endif
23341 
23342 		update((level!=NULL),0);
23343 
23344 		if(bothnewkeys & FLAG_ESC) quit = 1;
23345 		if(bothnewkeys & FLAG_MOVEUP){
23346 			--selector;
23347 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23348 		}
23349 		if(bothnewkeys & FLAG_MOVEDOWN){
23350 			++selector;
23351 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23352 		}
23353 		if(bothnewkeys & (FLAG_MOVELEFT|FLAG_MOVERIGHT|FLAG_ANYBUTTON)){
23354 			dir = 0;
23355 
23356 			if(bothnewkeys & FLAG_MOVELEFT) dir = -1;
23357 			else if(bothnewkeys & FLAG_MOVERIGHT) dir = 1;
23358 
23359 			if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
23360 
23361 			switch(selector){
23362 				case 0:
23363 					savedata.brightness += 8*dir;
23364 					if(savedata.brightness < -256) savedata.brightness = -256;
23365 					if(savedata.brightness > 256) savedata.brightness = 256;
23366 					vga_vwait();
23367 					set_color_correction(savedata.gamma, savedata.brightness);
23368 					break;
23369 				case 1:
23370 					savedata.gamma += 8*dir;
23371 					if(savedata.gamma < -256) savedata.gamma = -256;
23372 					if(savedata.gamma > 256) savedata.gamma = 256;
23373 					vga_vwait();
23374 					set_color_correction(savedata.gamma, savedata.brightness);
23375 					break;
23376 				case 2:
23377 					savedata.windowpos += dir;
23378 					if(savedata.windowpos < -2) savedata.windowpos = -2;
23379 					if(savedata.windowpos > 20) savedata.windowpos = 20;
23380 					break;
23381 #if SDL || PSP || XBOX || WII
23382 				case 3:
23383 #if XBOX
23384 					update((level!=NULL),0);
23385 					xbox_resize();
23386 #endif
23387 
23388 #if WII
23389 					//video_fullscreen_flip();
23390 					video_stretch((savedata.stretch ^= 1));
23391 					break;
23392 #endif
23393 
23394 #if PSP
23395 					if(videoMode == 0)
23396 					{   // 320x240
23397 						videomodes.mode += dir;
23398 						if(videomodes.mode > PSP_DISPLAY_FORMATS - 1) videomodes.mode = 0;
23399 						if(videomodes.mode < 0) videomodes.mode = PSP_DISPLAY_FORMATS - 1;
23400 						savedata.screen[videoMode][0] = videomodes.mode;
23401 						video_set_mode(videomodes);
23402 					}
23403 					break;
23404 
23405 				case 4:
23406 					if(videoMode == 0)
23407 					{   // 320x240
23408 						videomodes.filter += dir;
23409 						if(videomodes.filter > PSP_DISPLAY_FILTERS - 1) videomodes.filter = 0;
23410 						if(videomodes.filter < 0) videomodes.filter = PSP_DISPLAY_FILTERS - 1;
23411 						savedata.screen[videoMode][1] = videomodes.filter;
23412 						video_set_mode(videomodes);
23413 					}
23414 					break;
23415 
23416 				case 5:
23417 					displayMode += dir;
23418 					if(displayMode > PSP_DISPLAY_MODES - 1) displayMode = 0;
23419 					if(displayMode < 0) displayMode = PSP_DISPLAY_MODES - 1;
23420 					if(displayMode)
23421 						setGraphicsTVOverScan(savedata.overscan[0], savedata.overscan[1], savedata.overscan[2], savedata.overscan[3]);
23422 					else
23423 						setGraphicsTVOverScan(0, 0, 0, 0);
23424 					savedata.usetv = displayMode;
23425 					disableGraphics();
23426 					initGraphics(savedata.usetv, videomodes.pixel);
23427 					video_set_mode(videomodes);
23428 					break;
23429 				case 6:
23430 				case 7:
23431 				case 8:
23432 				case 9:
23433 					savedata.overscan[selector-8] += dir;
23434 					if(savedata.overscan[selector-8] > 99) savedata.overscan[selector-8] = 0;
23435 					if(savedata.overscan[selector-8] < 0) savedata.overscan[selector-8] = 99;
23436 					if(displayMode)
23437 					{
23438 						setGraphicsTVOverScan(savedata.overscan[0], savedata.overscan[1], savedata.overscan[2], savedata.overscan[3]);
23439 						video_set_mode(videomodes);
23440 					}
23441 					break;
23442 #endif
23443 #endif
23444 
23445 
23446 #if SDL
23447 #ifndef GP2X
23448 					video_fullscreen_flip();
23449 					break;
23450 				case 4:
23451 					savedata.usegl[savedata.fullscreen] ^= 1;
23452 					video_set_mode(videomodes);
23453 					set_color_correction(savedata.gamma, savedata.brightness);
23454 					break;
23455 				case 5:
23456 					if(opengl)
23457 					{
23458 						if(savedata.fullscreen) break;
23459 						savedata.glscale += dir * 0.25;
23460 						if(savedata.glscale < 0.25) savedata.glscale = 0.25;
23461 						if(savedata.glscale > 4.00) savedata.glscale = 4.00;
23462 						video_set_mode(videomodes);
23463 					}
23464 					else
23465 					{
23466 	    				videomodes.mode += dir * 2;
23467 #ifdef WII
23468 					    // Wii with SDL is limited to 640x480
23469 						if(videomodes.mode > 2) videomodes.mode = 0;
23470 					    if(videomodes.mode < 0) videomodes.mode = 2;
23471 #else
23472 						if(videomodes.mode > 4) videomodes.mode = 0;
23473 					    if(videomodes.mode < 0) videomodes.mode = 4;
23474 #endif
23475 					    savedata.screen[videoMode][0] = videomodes.mode;
23476 						video_set_mode(videomodes);
23477 						change_system_palette(current_palette);
23478 					}
23479 					break;
23480 				case 6:
23481 					if(opengl)
23482 					{
23483 						if(savedata.glscale == 1.0) break;
23484 						savedata.glfilter[savedata.fullscreen] += dir;
23485 						if(savedata.glfilter[savedata.fullscreen] < 0) savedata.glfilter[savedata.fullscreen] = 1;
23486 						if(savedata.glfilter[savedata.fullscreen] > 1) savedata.glfilter[savedata.fullscreen] = 0;
23487 					}
23488 					else
23489 					{
23490 						if(videomodes.mode!=2) break;
23491 						videomodes.filter += dir;
23492 						if(videomodes.filter > BLITTER_MAX - 1) videomodes.filter = 0;
23493 					    if(videomodes.filter < 0) videomodes.filter = BLITTER_MAX - 1;
23494 						savedata.screen[videoMode][1] = videomodes.filter;
23495 					}
23496 					break;
23497 				case 7:
23498 					video_stretch((savedata.stretch ^= 1));
23499 					break;
23500 #endif
23501 #endif
23502 				default:
23503 					quit = 1;
23504 			}
23505 		}
23506 	}
23507 	savesettings();
23508 	bothnewkeys = 0;
23509 }
23510 
23511 
options()23512 void options(){
23513 	int quit = 0;
23514 	int selector = 0;
23515 	int dir;
23516 
23517 	bothnewkeys = 0;
23518 
23519 	while(!quit){
23520 		_menutextm(2, 0, 0, "Options");
23521 		_menutextm((selector==0), 2, 0, "Video Options...");
23522 		_menutextm((selector==1), 3, 0, "Sound Options...");
23523 		_menutextm((selector==2), 4, 0, "Control Options...");
23524 		_menutextm((selector==3), 5, 0, "System Options...");
23525 		_menutextm((selector==4), 7, 0, "Back");
23526 
23527 		if(selector<0) selector = 4;
23528 		if(selector>4) selector = 0;
23529 
23530 		update((level!=NULL),0);
23531 
23532 		if(bothnewkeys & FLAG_ESC) quit = 1;
23533 		if(bothnewkeys & FLAG_MOVEUP){
23534 			--selector;
23535 
23536 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23537 		}
23538 		if(bothnewkeys & FLAG_MOVEDOWN){
23539 			++selector;
23540 
23541 			if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23542 		}
23543 		if(bothnewkeys & (FLAG_MOVELEFT|FLAG_MOVERIGHT|FLAG_ANYBUTTON)){
23544 			dir = 0;
23545 
23546 			if(bothnewkeys & FLAG_MOVELEFT) dir = -1;
23547 			else if(bothnewkeys & FLAG_MOVERIGHT) dir = 1;
23548 
23549 			if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
23550 
23551 			switch(selector){
23552 				case 0:
23553 					video_options();
23554 					break;
23555 				case 1:
23556 					sound_options();
23557 					break;
23558 				case 2:
23559 					input_options();
23560 					break;
23561 				case 3:
23562 					system_options();
23563 					break;
23564 				default:
23565 					quit = 1;
23566 			}
23567 		}
23568 	}
23569 	savesettings();
23570 	if(pause==1) pause=2;
23571 	bothnewkeys = 0;
23572 }
23573 
soundcard_options()23574 void soundcard_options(){
23575 	int quit = 0;
23576 	int selector = 0;
23577 	int col1=-8, col2=6;
23578 
23579 	savesettings();
23580 
23581 	bothnewkeys = 0;
23582 
23583 	while(!quit){
23584 		_menutextm(2, -5, 0, "Advanced Sound Options");
23585 		_menutext((selector==0), col1, -2, "Frequency:");
23586 		_menutext((selector==0), col2, -2, "%i", savedata.soundrate);
23587 		_menutext((selector==1), col1, -1, "Bits:");
23588 		_menutext((selector==1), col2, -1, "%i", savedata.soundbits);
23589 		_menutextm((selector==2), 1, 0, "Apply");
23590 		_menutextm((selector==3), 2, 0, "Discard");
23591 		_menutextm((selector==4), 7, 0, "Back");
23592 		update((level!=NULL),0);
23593 
23594 		if(bothnewkeys & FLAG_ESC) quit = 1;
23595 		if(bothnewkeys & FLAG_MOVEUP){
23596 			--selector;
23597 			sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23598 		}
23599 		if(bothnewkeys & FLAG_MOVEDOWN){
23600 			++selector;
23601 			sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23602 		}
23603 		if(selector<0) selector = 4;
23604 		selector %= 5;
23605 		if(bothnewkeys & (FLAG_MOVELEFT|FLAG_MOVERIGHT|FLAG_ANYBUTTON)){
23606 			sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
23607 			switch(selector){
23608 				case 0:
23609 					if(bothnewkeys & FLAG_MOVELEFT) savedata.soundrate >>= 1;
23610 					if(bothnewkeys & FLAG_MOVERIGHT) savedata.soundrate <<= 1;
23611 					if(savedata.soundrate < 11025) savedata.soundrate = 44100;
23612 					if(savedata.soundrate > 44100) savedata.soundrate = 11025;
23613 					break;
23614 				case 1:
23615 					savedata.soundbits = (savedata.soundbits ^ (8+16));
23616 					if(savedata.soundbits!=8 && savedata.soundbits!=16) savedata.soundbits = 8;
23617 					break;
23618 				case 2:
23619 					if(!(bothnewkeys & FLAG_ANYBUTTON)) break;
23620 					// Apply new hardware settings
23621 					sound_stop_playback();
23622 					if(!sound_start_playback(savedata.soundbits, savedata.soundrate)){
23623 						savedata.soundbits = 8;
23624 						savedata.soundrate = 11025;
23625 						sound_start_playback(savedata.soundbits, savedata.soundrate);
23626 					}
23627 					music("data/music/remix", 1, 0);
23628 					savesettings();
23629 					break;
23630 				case 3:
23631 					if(bothnewkeys & FLAG_ANYBUTTON) loadsettings();
23632 					break;
23633 				default:
23634 					quit = (bothnewkeys & FLAG_ANYBUTTON);
23635 			}
23636 		}
23637 	}
23638 	loadsettings();
23639 	bothnewkeys = 0;
23640 }
23641 
23642 #ifdef XBOX
display_logfile()23643 void display_logfile()
23644 {
23645 	int i, j, k;
23646 	stringptr *logfile = NULL;
23647 	char textpad[128] = {""};
23648 	int currentline = 0;
23649 	int filesize = 0;
23650 	int done = 0;
23651 
23652 	logfile = readFromLogFile(OPENBOR_LOG);
23653 	if(logfile != NULL)
23654 	{
23655 		unload_background();
23656 		load_background("menu/logview", 0);
23657 		while(!done)
23658 		{
23659 			font_printf(5,3, 1, 0, "Log Viewer");
23660 			font_printf(259,3, 1, 0, "Quit : Escape");
23661 			filesize = logfile->size;
23662 			if(bothkeys & FLAG_MOVEUP)
23663 			{
23664 				currentline -= 5;
23665 				if(currentline < 0) currentline = 0;
23666 			}
23667 			if(bothkeys & FLAG_MOVEDOWN)
23668 			{
23669 				currentline += 5;
23670 				if(currentline > filesize) currentline = filesize;
23671 			}
23672 			k = 0;
23673 			j = 2;
23674 			for(i=currentline; i<filesize; i++)
23675 			{
23676 				if(logfile->ptr[i] >= 0x20 && logfile->ptr[i] <= 0x7e)
23677 				{
23678 					textpad[k] = logfile->ptr[i];
23679 					k++;
23680 				}
23681 				else if(logfile->ptr[i] == 0x09)
23682 				{
23683 					textpad[k+0] = ' '; textpad[k+1] = ' ';
23684 					textpad[k+2] = ' '; textpad[k+3] = ' ';
23685 					k+=4;
23686 				}
23687 				else
23688 				{
23689 					font_printf(5, j*10, 0, 0, "%s", textpad);
23690 					j++;
23691 					k=0;
23692 					strncpy(textpad, "", 128);
23693 				}
23694 			}
23695 			if(bothkeys & FLAG_ESC) done = 1;
23696 			update((level!=NULL),0);
23697 		}
23698 		free_string(logfile);
23699 		logfile = NULL;
23700 		unload_background();
23701 		load_background("menu/logo", 0);
23702 	}
23703 }
23704 #endif
23705 
23706 // ----------------------------------------------------------------------------
23707 
23708 
openborMain(int argc,char ** argv)23709 void openborMain(int argc, char** argv)
23710 {
23711 	sprite_map = NULL;
23712 	int quit = 0;
23713 	int relback = 1;
23714 	int selector = 0;
23715 	u32 introtime = 0;
23716 	int started = 0;
23717 	char tmpBuff[128] = {""};
23718 	int players[MAX_PLAYERS];
23719 	int i;
23720 	int argl;
23721 
23722 #if XBOX
23723 	int done = 0;
23724 	char pakname[128] = {""};
23725 	char listing[32] = {""};
23726 	int paks = 0;
23727 	int list = 0;
23728 	int lOffset=0;
23729 	u32 menutime = 0;
23730 #endif
23731 
23732 	printf("OpenBoR %s, Compile Date: " __DATE__ "\n\n", VERSION);
23733 
23734 	if(argc > 1) {
23735 		argl = strlen(argv[1]);
23736 		if(argl > 14 && !memcmp(argv[1], "offscreenkill=", 14))
23737 			DEFAULT_OFFSCREEN_KILL = getValidInt((char*)argv[1] + 14,"","");
23738 		if(argl > 14 && !memcmp(argv[1], "showfilesused=", 14))
23739 			printFileUsageStatistics = getValidInt((char*)argv[1] + 14,"","");
23740 	}
23741 
23742 	modelcmdlist = createModelCommandList();
23743 	modelstxtcmdlist = createModelstxtCommandList();
23744 	levelcmdlist = createLevelCommandList();
23745 	levelordercmdlist = createLevelOrderCommandList();
23746 	createModelList();
23747 
23748 
23749 #ifdef XBOX
23750 	loadsettings();
23751 	paks = findmods();
23752 	if(paks==1) getBasePath(packfile, paklist[0].filename, 1);
23753 	else
23754 	{
23755 		strcpy(packfile, "d:\\Paks\\menu.pak");
23756 		guistartup();
23757 		load_background("menu/logo", 0);
23758 		while(!done)
23759 		{
23760 			if(paks < 1) font_printf(10,24, 1, 0, "No Mods In Paks Folder!");
23761 			if(bothnewkeys & FLAG_ESC)
23762 			{
23763 				disablelog = 1;
23764 				shutdown(1, "");
23765 			}
23766 
23767 			for(list=0; list<paks; list++)
23768 			{
23769 				strncpy(pakname, paklist[list+lOffset].filename,128-strlen(paklist[list+lOffset].filename));
23770 				if(list<18)
23771 				{
23772 					strncpy(listing, "", 32);
23773 					strncpy(listing, pakname, 31);
23774 					font_printf(10,24+(11*list), selector==list, 0, "%s", listing);
23775 				}
23776 			}
23777 			if(bothkeys & FLAG_MOVEUP && time >= menutime)
23778 			{
23779 				--selector;
23780 
23781 				menutime = time + GAME_SPEED/8;
23782 			}
23783 			if(bothkeys & FLAG_MOVEDOWN && time >= menutime)
23784 			{
23785 				++selector;
23786 				menutime = time + GAME_SPEED/8;
23787 			}
23788 #ifndef DC
23789 			if(bothkeys & FLAG_SPECIAL) display_logfile();
23790 #endif
23791 			if(selector>paks-1) selector=paks-1;
23792 			if(selector>17)
23793 			{
23794 				if((selector+lOffset)<paks) lOffset++;
23795 				selector=17;
23796 			}
23797 			if(selector<0)
23798 			{
23799 				selector=0;
23800 				if(lOffset>0) lOffset--;
23801 			}
23802 			if((bothnewkeys&(FLAG_START)) && paks > 1)
23803 			{
23804 				strncpy(pakname, paklist[selector+lOffset].filename,128-strlen(paklist[selector+lOffset].filename));
23805 				getBasePath(packfile, pakname, 1);
23806 				done = 1;
23807 			}
23808 
23809 			font_printf(5,3, 2, 0, "OpenBoR %s", VERSION);
23810 			font_printf(265,3, 2, 0, __DATE__);
23811 			font_printf(197,155, 2, 0, "www.LavaLit.com");
23812 			font_printf(190,165, 2, 0, "www.SenileTeam.com");
23813 			font_printf(5,229, 2, 0, "Start : Load");
23814 			font_printf(259,229, 2, 0, "Quit : Escape");
23815 
23816 			if(done) font_printf(215,175, 2, 0, "Loading...");
23817 			update(0,0);
23818 		}
23819 
23820 		if(paks != 1)
23821 		{
23822 			// unload whats been allocated.
23823 			selector = 0;
23824 			unload_background();
23825 			freescreen(vscreen);
23826 			unload_all_fonts();
23827 			borTimerExit();
23828 			control_exit();
23829 		}
23830 	}
23831 #endif
23832 
23833 	// Load necessary components.
23834 	printf("Game Selected: %s\n\n", packfile);
23835 	loadsettings();
23836 	startup();
23837 
23838 	// New alternative background path for PSP
23839 	if(custBkgrds != NULL)
23840 	{
23841 		strcpy(tmpBuff,custBkgrds);
23842 		strncat(tmpBuff,"logo", 4);
23843 		load_background(tmpBuff, 0);
23844 	}
23845 	else {
23846 		printf("use cached bg\n");
23847 		load_cached_background("data/bgs/logo", 0);
23848 	}
23849 
23850 	while(time<GAME_SPEED*6 && !(bothnewkeys&(FLAG_ANYBUTTON|FLAG_ESC))) update(0,0);
23851 
23852 	music("data/music/remix", 1, 0);
23853 
23854 	// New alternative scene path for PSP
23855 	if(custScenes != NULL)
23856 	{
23857 		strncpy(tmpBuff,custScenes, 128);
23858 		strncat(tmpBuff,"logo.txt", 8);
23859 		playscene(tmpBuff);
23860 	}
23861 	else playscene("data/scenes/logo.txt");
23862 	clearscreen(background);
23863 
23864 	while(!quit)
23865 	{
23866 		if(time >= introtime)
23867 		{
23868 			// New alternative scene path for PSP
23869 			if(custScenes != NULL)
23870 			{
23871 				strncpy(tmpBuff,custScenes, 128);
23872 				strncat(tmpBuff,"intro.txt", 9);
23873 				playscene(tmpBuff);
23874 			}
23875 			else playscene("data/scenes/intro.txt");
23876 			update(0,0);
23877 			introtime = time + GAME_SPEED * 20;
23878 			relback = 1;
23879 			started = 0;
23880 		}
23881 
23882 		if(bothnewkeys & FLAG_ESC) quit = 1;
23883 
23884 		if(!started)
23885 		{
23886 			if((time%GAME_SPEED) < (GAME_SPEED/2)) _menutextm(0, 0, 0, "PRESS START");
23887 			if(bothnewkeys&(FLAG_ANYBUTTON))
23888 			{
23889 				started = 1;
23890 				relback = 1;
23891 			}
23892 		}
23893 		else
23894 		{
23895 			_menutextm((selector==0), 2, 0, "Start Game");
23896 			_menutextm((selector==1), 3, 0, "Options");
23897 			_menutextm((selector==2), 4, 0, "How To Play");
23898 			_menutextm((selector==3), 5, 0, "Hall Of Fame");
23899 			_menutextm((selector==4), 6, 0, "Quit");
23900 			if(selector<0) selector = 5;
23901 			if(selector>5) selector = 0;
23902 
23903 			if(bothnewkeys) introtime = time + GAME_SPEED * 20;
23904 
23905 			if(bothnewkeys & FLAG_MOVEUP)
23906 			{
23907 				--selector;
23908 				if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23909 			}
23910 			if(bothnewkeys & FLAG_MOVEDOWN)
23911 			{
23912 				++selector;
23913 				if(SAMPLE_BEEP >= 0) sound_play_sample(SAMPLE_BEEP, 0, savedata.effectvol,savedata.effectvol, 100);
23914 			}
23915 			if(bothnewkeys&(FLAG_ANYBUTTON))
23916 			{
23917 				if(SAMPLE_BEEP2 >= 0) sound_play_sample(SAMPLE_BEEP2, 0, savedata.effectvol,savedata.effectvol, 100);
23918 				switch(selector)
23919 				{
23920 				case 0:
23921 					for(i=0; i<MAX_PLAYERS; i++) players[i] = player[i].newkeys & (FLAG_ANYBUTTON);
23922 					relback = choose_mode(players);
23923 					if(relback) started = 0;
23924 					break;
23925 				case 1:
23926 					if(!cheats) options();
23927 					else
23928 					{
23929 						if(!forcecheatsoff) cheatoptions();
23930 						else options();
23931 					}
23932 					break;
23933 				case 2:
23934 					if(custScenes != NULL)
23935 					{
23936 						strncpy(tmpBuff,custScenes, 128);
23937 						strncat(tmpBuff,"howto.txt", 9);
23938 						playscene(tmpBuff);
23939 					}
23940 					else playscene("data/scenes/howto.txt");
23941 					relback = 1;
23942 					break;
23943 				case 3:
23944 					hallfame(0);
23945 					relback = 1;
23946 					break;
23947 				default:
23948 					quit = 1;
23949 					break;
23950 				}
23951 				introtime = time + GAME_SPEED * 20;
23952 			}
23953 		}
23954 		if(relback)
23955 		{
23956 			if(started)
23957 			{
23958 				menuScreen  = 1;
23959 				titleScreen = 0;
23960 				if(custBkgrds != NULL)
23961 				{
23962 					strncpy(tmpBuff,custBkgrds, 128);
23963 					strncat(tmpBuff,"titleb", 6);
23964 					load_background(tmpBuff, 0);
23965 				}
23966 				else load_cached_background("data/bgs/titleb", 0);
23967 			}
23968 			else
23969 			{
23970 				menuScreen  = 0;
23971 				titleScreen = 1;
23972 				if(custBkgrds != NULL)
23973 				{
23974 					strncpy(tmpBuff,custBkgrds, 128);
23975 					strncat(tmpBuff,"title", 5);
23976 					load_background(tmpBuff, 0);
23977 				}
23978 				else load_cached_background("data/bgs/title", 0);
23979 			}
23980 
23981 			if(!sound_query_music(NULL,NULL)) music("data/music/remix", 1, 0);
23982 			relback = 0;
23983 		}
23984 		update(0,0);
23985 	}
23986 	shutdown(0, DEFAULT_SHUTDOWN_MESSAGE);
23987 }
23988 
23989 #undef GET_ARG
23990 #undef GET_ARG_LEN
23991 #undef GET_ARGP
23992 #undef GET_ARGP_LEN
23993 #undef GET_INT_ARG
23994 #undef GET_FLOAT_ARG
23995 #undef GET_INT_ARGP
23996 #undef GET_FLOAT_ARGP
23997