1 /* ResidualVM - A 3D game interpreter
2  *
3  * ResidualVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the AUTHORS
5  * file distributed with this source distribution.
6  *
7  * Additional copyright for this file:
8  * Copyright (C) 1999-2000 Revolution Software Ltd.
9  * This code is based on source code created by Revolution Software,
10  * used with permission.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25  *
26  */
27 
28 #include "engines/icb/p4.h" //for machine version
29 #include "engines/icb/common/px_common.h"
30 #include "engines/icb/common/px_linkeddatafile.h"
31 #include "engines/icb/mission.h"
32 #include "engines/icb/session.h"
33 #include "engines/icb/object_structs.h"
34 #include "engines/icb/debug.h"
35 #include "engines/icb/player.h"
36 #include "engines/icb/direct_input.h"
37 #include "engines/icb/barriers.h"
38 #include "engines/icb/common/px_route_barriers.h"
39 #include "engines/icb/global_objects.h"
40 #include "engines/icb/animation_mega_set.h"
41 #include "engines/icb/mission.h"
42 #include "engines/icb/common/px_scriptengine.h"
43 #include "engines/icb/icb.h"
44 #include "engines/icb/global_switches.h"
45 #include "engines/icb/res_man.h"
46 #include "engines/icb/sound.h"
47 #include "engines/icb/floors.h"
48 #include "engines/icb/remora.h"
49 
50 #include "common/textconsole.h"
51 
52 namespace ICB {
53 
fn_player(int32 & result,int32 * params)54 mcodeFunctionReturnCodes fn_player(int32 &result, int32 *params) { return (MS->fn_player(result, params)); }
fn_prime_player_history(int32 & result,int32 * params)55 mcodeFunctionReturnCodes fn_prime_player_history(int32 &result, int32 *params) { return (MS->fn_prime_player_history(result, params)); }
fn_is_id_the_player(int32 & result,int32 * params)56 mcodeFunctionReturnCodes fn_is_id_the_player(int32 &result, int32 *params) { return (MS->fn_is_id_the_player(result, params)); }
fn_push_player_status(int32 & result,int32 * params)57 mcodeFunctionReturnCodes fn_push_player_status(int32 &result, int32 *params) { return (MS->fn_push_player_status(result, params)); }
fn_pop_player_status(int32 & result,int32 * params)58 mcodeFunctionReturnCodes fn_pop_player_status(int32 &result, int32 *params) { return (MS->fn_pop_player_status(result, params)); }
fn_post_third_party_speech(int32 & result,int32 * params)59 mcodeFunctionReturnCodes fn_post_third_party_speech(int32 &result, int32 *params) { return (MS->fn_post_third_party_speech(result, params)); }
fn_set_player_has_weapon(int32 & result,int32 * params)60 mcodeFunctionReturnCodes fn_set_player_has_weapon(int32 &result, int32 *params) { return (MS->fn_set_player_has_weapon(result, params)); }
fn_can_hear_players_feet(int32 & result,int32 * params)61 mcodeFunctionReturnCodes fn_can_hear_players_feet(int32 &result, int32 *params) { return (MS->fn_can_hear_players_feet(result, params)); }
fn_is_player_striking(int32 & result,int32 * params)62 mcodeFunctionReturnCodes fn_is_player_striking(int32 &result, int32 *params) { return (MS->fn_is_player_striking(result, params)); }
63 
64 // pc device switch
65 extern __pc_input device;
66 
67 int32 armedChangesMode = 0;
68 int32 animToggles = 0;
69 int32 CAMERA_SMOOTH_CYCLES = 12;
70 
71 #define CORRECT_PAN                                                                                                                                                                \
72 	if (log->pan >= HALF_TURN)                                                                                                                                                 \
73 		log->pan -= FULL_TURN;                                                                                                                                             \
74 	else if (log->pan <= -HALF_TURN)                                                                                                                                           \
75 		log->pan += FULL_TURN;
76 
___init()77 void _player::___init() {
78 	Zdebug("constructing _player");
79 
80 	player_exists = FALSE8;
81 	haveCamera = 0;
82 	armedChangesMode = 0;
83 	hunting = 0;
84 	lastCameraPan = 3 * FULL_TURN; // a placeholder to say never set
85 	deltaCameraPan = ZERO_TURN;
86 	;
87 	interact_selected = FALSE8;
88 	cur_interact_id = (uint)-1;
89 
90 	look_at_selected = 0;
91 
92 	aim_turn_amount = (FULL_TURN * 2) / 100;        // 2% of a turn per game cycle
93 	crouch_turn_amount = (FULL_TURN * 1) / 100;     // 1% of a turn per game cycle
94 	stood_turn_amount = (FULL_TURN * 1) / 100;      // 1% of a turn per game cycle
95 	stood_fast_turn_amount = (FULL_TURN * 7) / 100; // 7% of a turn per game cycle
96 	walk_turn_amount = (FULL_TURN * 2 / 100);       // 2% of a turn per game cycle
97 	run_turn_amount = (FULL_TURN * 4 / 100);        // 2% of a turn per game cycle
98 
99 	// push it twice to fill up the stack : just in case someone does a pop before a push
100 	// Push_control_mode( ACTOR_RELATIVE );
101 	// Push_control_mode( ACTOR_RELATIVE );
102 
103 	being_shot = (int8)0;
104 
105 	look_at_id = 0;
106 	MS->init_asyncs = FALSE8; // not inited the 4 async vox image structs
107 }
108 
Player_press_inv_button()109 __mode_return _player::Player_press_inv_button() {
110 	// check if the player has pressed the INVENTORY button
111 
112 	// return
113 	//				__FINISHED_THIS_CYCLE, or
114 	//				__MORE_THIS_CYCLE
115 
116 	if ((cur_state.IsButtonSet(__INVENTORY)) && (!inv_lock)) {
117 
118 		// Don't bring up the inventory if there is nothing in it.
119 		{
120 			// This brings up the inventory.
121 			if ((player_status == NEW_AIM) || (player_status == CROUCH_AIM)) {
122 			} else {
123 				g_oIconListManager->ActivateIconMenu(ICON_LIST_INVENTORY, TRUE8, TRUE8);
124 			}
125 
126 			g_oIconListManager->CycleInventoryLogic(cur_state);
127 
128 			inv_lock = TRUE8;
129 
130 			Push_control_mode(ACTOR_RELATIVE);
131 			Push_player_stat();
132 			Set_player_status(INVENTORY);
133 		}
134 
135 		return (__FINISHED_THIS_CYCLE);
136 	} else {
137 		// Stopped inventory dropping in repeatedly when you hold down the key.
138 		if (!(cur_state.IsButtonSet(__INVENTORY))) {
139 			inv_lock = FALSE8; // released
140 		}
141 	}
142 
143 	return (__MORE_THIS_CYCLE);
144 }
145 
Player_press_remora_button()146 __mode_return _player::Player_press_remora_button() {
147 	// check if the player has pressed the FIRE button
148 	// if so see if there's a current interact object and if so setup the interaction
149 
150 	// return
151 	//				__FINISHED_THIS_CYCLE, or
152 	//				__MORE_THIS_CYCLE
153 
154 	if ((cur_state.IsButtonSet(__REMORA)) && (!remora_lock)) {
155 		Push_player_stat();
156 		Set_player_status(REMORA);
157 		remora_lock = TRUE8;
158 		interact_lock = TRUE8; // avoid problems coming out
159 		Push_control_mode(ACTOR_RELATIVE);
160 		MS->Awaken_doors(); // sleeping doors come alive while in remora display!
161 
162 		// This sets a flag which the Remora will pick up next cycle.
163 		g_oRemora->ActivateRemora(_remora::MOTION_SCAN);
164 		g_oRemora->CycleRemoraLogic(cur_state);
165 		return (__FINISHED_THIS_CYCLE);
166 	} else if (!(cur_state.IsButtonSet(__REMORA)))
167 		remora_lock = FALSE8;
168 
169 	return (__MORE_THIS_CYCLE);
170 }
171 
Player_press_fire_button()172 __mode_return _player::Player_press_fire_button() {
173 	// check if the player has pressed the FIRE button
174 	// if so see if there's a current interact object and if so setup the interaction
175 
176 	// return
177 	//				__FINISHED_THIS_CYCLE, or
178 	//				__MORE_THIS_CYCLE
179 
180 	bool8 res;
181 	int32 retval;
182 
183 	// check for interact button
184 	if ((being_shot == 0) && (cur_state.IsButtonSet(__ATTACK)) && (!fire_lock) && (GetNoBullets())) {
185 		// cant shoot at non evils
186 		if ((interact_selected) && (!MS->logic_structs[cur_interact_id]->mega->is_evil)) {
187 			if (!MS->Engine_start_interaction("non_evil_interact", cur_interact_id))
188 				return __MORE_THIS_CYCLE;
189 
190 			fire_lock = TRUE8; // switch the lock on
191 
192 			// do this as exit conversation will pop the player status
193 			if (MS->logic_structs[Fetch_player_id()]->mega->Fetch_armed_status())
194 				Set_player_status(NEW_AIM);
195 			else
196 				Set_player_status(STOOD);
197 			Push_player_stat();
198 
199 			return (__FINISHED_THIS_CYCLE);
200 		}
201 
202 		fire_lock = TRUE8; // switch the lock on
203 
204 		// check for special script content overide
205 		if ((interact_selected) && (MS->logic_structs[cur_interact_id]->mega))
206 			if (MS->logic_structs[cur_interact_id]->mega->use_fire_script) {
207 				res = MS->Call_socket(cur_interact_id, "shoot", &retval);
208 				if (!res)
209 					Fatal_error("shoot script missing");
210 
211 				// do this as exit conversation will pop the player status
212 				if (MS->logic_structs[Fetch_player_id()]->mega->Fetch_armed_status())
213 					Set_player_status(NEW_AIM);
214 				else
215 					Set_player_status(STOOD);
216 				Push_player_stat();
217 
218 				return (__FINISHED_THIS_CYCLE);
219 			}
220 
221 		// play gun sound
222 		if (MS->logic_structs[player_id]->sfxVars[GUNSHOT_SFX_VAR] != 0)
223 			RegisterSound(player_id, NULL, MS->logic_structs[player_id]->sfxVars[GUNSHOT_SFX_VAR], gunDesc,
224 			              (int8)127); // have to use full version so we can give hash instead of string
225 		else
226 			RegisterSound(player_id, defaultGunSfx, gunDesc); // use small version as we have string not hash
227 
228 		// dynamic light
229 		log->mega->SetDynamicLight(1, 255, 255, 255, 0, 150, 100, 200); // 2m rgb=WHITE
230 
231 		// Hey we are shooting
232 		log->mega->is_shooting = TRUE8;
233 
234 		UseBullets(1); // used another bullet
235 
236 		// if target and target alive then stick a bullet in them
237 		if ((interact_selected) && (MS->Call_socket(cur_interact_id, "give_state", &retval))) {
238 			if (!retval) {
239 				//      try to fetch the object
240 				MS->socket_object = (c_game_object *)MS->objects->Fetch_item_by_number(cur_interact_id);
241 
242 				res = MS->Call_socket(cur_interact_id, "gun_shot", &retval);
243 
244 				MS->Set_chi_permission(); // if chi's around she gets permission to start shooting
245 
246 				if (!res)
247 					Tdebug("gun_shot_errors.txt", "no [%s] for object [%s]", "gun_shot", MS->socket_object->GetName());
248 			}
249 		} else {
250 			// no hit play ricochet sound
251 			if (MS->logic_structs[player_id]->sfxVars[RICOCHET_SFX_VAR] != 0)
252 				RegisterSound(player_id, NULL, MS->logic_structs[player_id]->sfxVars[RICOCHET_SFX_VAR], ricochetDesc,
253 				              (int8)127); // have to use full version so we can give hash instead of string
254 			else
255 				RegisterSound(player_id, defaultRicochetSfx, ricochetDesc); // use small version as we have string not hash
256 
257 			// now, we hit nothing, but if chi cant see us then set her permission
258 			if (!g_oLineOfSight->LineOfSight(MS->chi_id, Fetch_player_id()))
259 				MS->Set_chi_permission(); // if chi's around she gets permission to start shooting
260 		}
261 
262 		// back to stand aim or crouch aim
263 		if (player_status == NEW_AIM)
264 			Hard_start_new_mode(NEW_AIM, __STAND_AND_SHOOT);
265 		else
266 			Hard_start_new_mode(CROUCH_AIM, __STAND_AND_SHOOT);
267 
268 		return (__FINISHED_THIS_CYCLE);
269 	} else if ((cur_state.IsButtonSet(__ATTACK)) && (!fire_lock) && (!GetNoBullets())) {
270 		// would have fired but we have no bullets
271 		// if we have clips then reload
272 
273 		if (GetNoAmmoClips()) {
274 			// reload
275 			UseAmmoClips(1); // use a clip
276 
277 			int32 bull_per_clip = GetBulletsPerClip();
278 
279 			SetBullets(bull_per_clip); // reload
280 
281 			if (player_status == NEW_AIM)
282 				Hard_start_new_mode(NEW_AIM, __LOAD_GUN);
283 			else
284 				Hard_start_new_mode(CROUCH_AIM, __LOAD_GUN);
285 
286 			return (__FINISHED_THIS_CYCLE);
287 		}
288 	}
289 
290 	if (!cur_state.IsButtonSet(__ATTACK)) // release the lock
291 		fire_lock = FALSE8; // let go
292 
293 	return (__MORE_THIS_CYCLE);
294 }
295 
Player_press_strike_button()296 __mode_return _player::Player_press_strike_button() {
297 	// check if the player has pressed the FIRE button when stood unarmed - to punch
298 
299 	// return
300 	//				__FINISHED_THIS_CYCLE, or
301 	//				__MORE_THIS_CYCLE
302 
303 	bool8 ret;
304 	int32 retval;
305 
306 	// check for interact button
307 	if ((cur_state.IsButtonSet(__ATTACK)) && (!fire_lock)) {
308 
309 		fire_lock = TRUE8; // switch the lock on
310 
311 		// physically cant punch chi or no evils
312 		if ((interact_selected) && (MS->logic_structs[cur_interact_id]->image_type == VOXEL) && (!MS->logic_structs[cur_interact_id]->mega->is_evil)) {
313 			PXreal sub1, sub2, dist;
314 
315 			sub1 = MS->logic_structs[cur_interact_id]->mega->actor_xyz.x - log->mega->actor_xyz.x;
316 			sub2 = MS->logic_structs[cur_interact_id]->mega->actor_xyz.z - log->mega->actor_xyz.z;
317 
318 			dist = ((sub1 * sub1) + (sub2 * sub2));
319 
320 			if (dist < (PXreal(200 * 200)))
321 				return (__FINISHED_THIS_CYCLE);
322 		}
323 
324 		// check for special script content overide
325 		if ((interact_selected) && (MS->logic_structs[cur_interact_id]->mega))
326 			if (MS->logic_structs[cur_interact_id]->mega->use_strike_script) {
327 				if (MS->logic_structs[cur_interact_id]->mega->Is_crouched())
328 					return __MORE_THIS_CYCLE;
329 
330 				ret = MS->Call_socket(cur_interact_id, "strike", &retval);
331 				if (!ret)
332 					Fatal_error("strike script missing");
333 
334 				return (__FINISHED_THIS_CYCLE);
335 			}
336 
337 		// can be stood or crouched, unarmed
338 		if (player_status == CROUCHING) {
339 			Hard_start_new_mode(CROUCH_TO_PUNCH, __STAND_CROUCHED_TO_STAND);
340 		} else {
341 			//      link anim has been requested - the link exists
342 			log->anim_pc = 0; // start at hard 0
343 
344 			//      set to linking mode
345 			player_status = STRIKING;
346 
347 			//      set anim type to link
348 			log->cur_anim_type = __STRIKE;
349 
350 			//			dales tweeky low strike thing
351 			if ((interact_selected) && (MS->logic_structs[cur_interact_id]->image_type == VOXEL)) {
352 				if (!(g_icb->getRandomSource()->getRandomNumber(10 - 1)))
353 					log->cur_anim_type = __LOW_STRIKE;
354 			}
355 		}
356 		return (__FINISHED_THIS_CYCLE);
357 	}
358 
359 	if (!cur_state.IsButtonSet(__ATTACK)) // release the lock
360 		fire_lock = FALSE8; // let go
361 
362 	return (__MORE_THIS_CYCLE);
363 }
364 
fn_prime_player_history(int32 &,int32 *)365 mcodeFunctionReturnCodes _game_session::fn_prime_player_history(int32 &, int32 *) {
366 	// put the first entry in the history list
367 
368 	_floor *floor;
369 
370 	history[cur_history].interaction = FALSE8;
371 	history[cur_history].id =
372 	    floor_def->Locate_floor_rect(logic_structs[cur_id]->mega->actor_xyz.x, logic_structs[cur_id]->mega->actor_xyz.z, logic_structs[cur_id]->mega->actor_xyz.y, &floor);
373 
374 	logic_structs[cur_id]->owner_floor_rect = history[cur_history].id; // gotta set this for first fn_player
375 	pre_interact_floor = history[cur_history].id;
376 
377 	if (history[cur_history].id == PXNULL)
378 		Message_box("fn_prime_player_history hasnt got a legal coordinate from player?");
379 
380 	Tdebug("history.txt", ">> %d", history[cur_history].id);
381 
382 	// prime local position stuff
383 	hist_pin_x = logic_structs[cur_id]->mega->actor_xyz.x;
384 	hist_pin_z = logic_structs[cur_id]->mega->actor_xyz.z;
385 
386 	local_history_count = 0; // total points recorded in this room
387 	next_local = 0; // place in array for next
388 	local_count_down = TIME_to_next_local_history;
389 
390 	return IR_CONT;
391 }
392 
fn_is_id_the_player(int32 & result,int32 * params)393 mcodeFunctionReturnCodes _game_session::fn_is_id_the_player(int32 &result, int32 *params) {
394 	// returns true or false if the passed id is the player
395 
396 	// params        0   id of object
397 
398 	if (params[0] == (int32)player.Fetch_player_id()) {
399 		result = TRUE8;
400 		return IR_CONT;
401 	}
402 
403 	result = FALSE8;
404 	return IR_CONT;
405 }
406 
fn_push_player_status(int32 &,int32 *)407 mcodeFunctionReturnCodes _game_session::fn_push_player_status(int32 &, int32 *) {
408 	// reset player to either stood or stood armed
409 	if (logic_structs[player.Fetch_player_id()]->mega->Is_crouched())
410 		player.Set_player_status(CROUCHING);
411 	else if (logic_structs[player.Fetch_player_id()]->mega->Fetch_armed_status())
412 		player.Set_player_status(NEW_AIM);
413 	else
414 		player.Set_player_status(STOOD);
415 
416 	player.Push_player_stat();
417 
418 	return IR_CONT;
419 }
420 
fn_pop_player_status(int32 &,int32 *)421 mcodeFunctionReturnCodes _game_session::fn_pop_player_status(int32 &, int32 *) {
422 	player.Pop_player_stat();
423 
424 	return IR_CONT;
425 }
426 
fn_post_third_party_speech(int32 &,int32 *)427 mcodeFunctionReturnCodes _game_session::fn_post_third_party_speech(int32 &, int32 *) {
428 	// called after player has been grabbed by a non player started conversation
429 
430 	player.Pop_player_stat();
431 
432 	return IR_CONT;
433 }
434 
fn_set_player_has_weapon(int32 &,int32 * params)435 mcodeFunctionReturnCodes _game_session::fn_set_player_has_weapon(int32 &, int32 *params) {
436 	// set the has gun flag
437 
438 	// params    0   yes/no
439 
440 	player.has_weapon = (bool8)(params[0]);
441 
442 	return IR_CONT;
443 }
444 
fn_player(int32 &,int32 *)445 mcodeFunctionReturnCodes _game_session::fn_player(int32 &, int32 *) {
446 	mcodeFunctionReturnCodes ret;
447 	PXreal sub1, sub2, len;
448 
449 	// if there is a set watch to someone other than player do no player processing
450 	if ((g_mission->camera_follow_id_overide) && (player.Fetch_player_id() != g_mission->camera_follow_id_overide))
451 		return IR_REPEAT;
452 
453 	if (!L->looping) {
454 		L->anim_pc = 0; // reset for when we are coming straight back in after a context re-run has changed the logic unexpectedly
455 		L->looping = TRUE8;
456 		M->cur_parent = 0; // force a reset - if players routes first cycle then the player barriers are never brought in
457 	}
458 
459 	// run player user, control and animation logic
460 	ret = player.Gateway();
461 
462 	// find current intereact object
463 	player.Find_current_player_interact_object();
464 
465 	//	set floor rect value - used by stage draw to find indexed camera name
466 	floor_def->Set_floor_rect_flag(L);
467 
468 	// build the players movement list
469 	// add new entry if cur entry is an interaction, or, floor has changed
470 	if ((L->owner_floor_rect != pre_interact_floor) && (floor_def->On_a_floor(M)) && (prev_save_state)) {
471 
472 		//		changed floor
473 		cur_history++;
474 		if (cur_history == MAX_player_history)
475 			cur_history = 0; // wrap
476 
477 		history[cur_history].interaction = FALSE8;
478 		history[cur_history].id = L->owner_floor_rect; // record new floor id
479 		history[cur_history].first_x = M->actor_xyz.x;
480 		history[cur_history].first_z = M->actor_xyz.z;
481 
482 		// spectre history
483 		spectre_hist[pre_interact_floor].x = hist_pin_x;
484 		spectre_hist[pre_interact_floor].z = hist_pin_z;
485 
486 		hist_pin_x = M->actor_xyz.x;
487 		hist_pin_y = M->actor_xyz.y;
488 		hist_pin_z = M->actor_xyz.z;
489 
490 		pre_interact_floor = L->owner_floor_rect; // last floor
491 		local_history_count = 0; // set to 0 points in this room - but, record the coordinate for pin purposes
492 		next_local = 0; // place in array for next
493 		local_count_down = TIME_to_next_local_history;
494 
495 		Tdebug("history.txt", "> %d", L->owner_floor_rect);
496 	}
497 
498 	if ((!local_count_down) && (prev_save_state)) {
499 		//		ok, we're pinned to last spot
500 		//		unless we've moved significantly then we dont record another position
501 
502 		sub1 = (PXreal)M->actor_xyz.x - hist_pin_x;
503 		sub2 = (PXreal)M->actor_xyz.z - hist_pin_z;
504 
505 		//		dist
506 		len = (PXreal)((sub1 * sub1) + (sub2 * sub2));
507 
508 		if ((floor_def->On_a_floor(M)) && (len > (PXreal)(HISTORY_RUBBER * HISTORY_RUBBER))) {
509 
510 			//			Message_box("writing %3.1f, %3.1f, next_local=%d, local_history_count %d", M->actor_xyz.x, M->actor_xyz.z, next_local,
511 			//local_history_count);
512 			//			record coordinate
513 			local_history[next_local].x = M->actor_xyz.x;
514 			local_history[next_local].z = M->actor_xyz.z;
515 
516 			hist_pin_x = M->actor_xyz.x;
517 			hist_pin_y = M->actor_xyz.y;
518 			hist_pin_z = M->actor_xyz.z;
519 
520 			//			loop forever overwriting earlier entries as we move around
521 			next_local++;
522 			if (next_local == MAX_local_history)
523 				next_local = 0;
524 
525 			if (local_history_count < MAX_local_history)
526 				local_history_count++;
527 		}
528 
529 		local_count_down = TIME_to_next_local_history;
530 	} else {
531 
532 		if (player.player_status == WALKING)
533 			local_count_down--;
534 
535 		if ((player.player_status == RUNNING) && (local_count_down))
536 			local_count_down--;
537 	}
538 
539 	// reset for a cycle
540 	player.stood_on_lift = 0; // clear stood on lift platform flag
541 
542 	return (ret);
543 }
544 
Gateway()545 mcodeFunctionReturnCodes _player::Gateway() {
546 	// top level call for player interface
547 
548 	// basically,
549 
550 	// fetch player object
551 
552 	// check for events that affect the player object
553 
554 	// see what we're doing
555 	//	see what player is doing
556 
557 	// Jake 15/2/98 : set the default
558 	__mode_return ret = __FINISHED_THIS_CYCLE;
559 	int32 bull_per_clip;
560 	c_game_object *ob;
561 
562 	// Set the player control mode correctly
563 	switch (g_px->display_mode) {
564 	case NETHACK:
565 	case TEMP_NETHACK: {
566 		// Set the player into ACTOR_RELATIVE mode for nethack modes
567 		Set_control_mode(ACTOR_RELATIVE);
568 	}
569 	case THREED: {}
570 	}
571 
572 	// when not in menu put into user selected control mode
573 	// the idea is that this is a lot more secure than the previous push/pop scheme
574 	if ((player_status != INVENTORY) && (player_status != REMORA))
575 		focus_mode = master_mode;
576 
577 	// check keys/pads/etc. to see what the user is trying to do
578 	Update_input_state();
579 
580 	do {
581 		switch (player_status) {
582 		//      not all of these will be user controllable - like being blown up, etc.
583 
584 		case STOOD:
585 			ret = Player_interact();
586 			if (ret == __FINISHED_THIS_CYCLE)
587 				return (IR_TERMINATE); // set to go around again and do a cycle of the interact script
588 
589 			ret = Player_press_strike_button();
590 			if (ret == __FINISHED_THIS_CYCLE)
591 				return (IR_TERMINATE); // set to go around again and do a cycle of the interact script
592 
593 			// no interact so keep going as normal
594 			ret = Player_stood();
595 			break;
596 
597 		case WALKING:
598 			ret = Player_interact();
599 			// check if interact has set up a new script to run on level 2
600 			if (ret == __FINISHED_THIS_CYCLE)
601 				return (IR_TERMINATE); // set to go around again and do a cycle of the interact script
602 			// no interact so keep going as normal
603 
604 			ret = Player_press_strike_button();
605 			if (ret == __FINISHED_THIS_CYCLE)
606 				return (IR_TERMINATE); // set to go around again and do a cycle of the interact script
607 
608 			ret = Player_walking();
609 
610 			break;
611 
612 		case CROUCH_WALK:
613 			ret = Player_crouch_walk();
614 			break;
615 
616 		case NEW_AIM:
617 			ret = Player_interact(); // check if interact has set up a new script to run on level 2
618 			if (ret == __FINISHED_THIS_CYCLE)
619 				return (IR_TERMINATE); // set to go around again and do a cycle of the interact script
620 
621 			ret = Player_press_fire_button();
622 			if (ret == __FINISHED_THIS_CYCLE)
623 				return (IR_REPEAT); //
624 
625 			ret = Player_new_aim();
626 			break;
627 
628 		case CROUCH_AIM:
629 			ret = Player_press_fire_button();
630 			if (ret == __FINISHED_THIS_CYCLE)
631 				return (IR_REPEAT); //
632 
633 			ret = Player_crouch_aim();
634 			break;
635 
636 		case PUTTING_AWAY_GUN: // going from armed with gun to unarmed
637 			MS->Set_pose(__NOT_ARMED);
638 			MS->Change_pose_in_current_anim_set();
639 			if (armedChangesMode == 1)
640 				Pop_control_mode();
641 			Hard_start_new_mode(STOOD, __STAND);
642 			return (IR_STOP);
643 
644 		case PUTTING_AWAY_CROUCH_GUN: // going from armed with gun to unarmed
645 			MS->Set_pose(__CROUCH_NOT_ARMED);
646 			MS->Change_pose_in_current_anim_set();
647 			if (armedChangesMode == 1)
648 				Push_control_mode(ACTOR_RELATIVE);
649 			Hard_start_new_mode(CROUCHING, __STAND);
650 			return (IR_REPEAT);
651 
652 		case RUNNING:
653 			ret = Player_press_strike_button();
654 			if (ret == __FINISHED_THIS_CYCLE)
655 				return (IR_TERMINATE); // set to go around again and do a cycle of the interact script
656 
657 			ret = Player_running();
658 			break;
659 
660 		case CROUCH_TO_STAND_UNARMED: // crouch to stood unarmed
661 			MS->Set_pose(__NOT_ARMED);
662 			MS->Change_pose_in_current_anim_set();
663 			Hard_start_new_mode(STOOD, __STAND);
664 			return (IR_STOP);
665 
666 		case CROUCH_TO_PUNCH:
667 			MS->Set_pose(__NOT_ARMED);
668 			MS->Change_pose_in_current_anim_set();
669 			//      link anim has been requested - the link exists
670 			log->anim_pc = 0; // start at hard 0
671 
672 			//      set to linking mode
673 			player_status = STRIKING;
674 
675 			//      set anim type to link
676 			log->cur_anim_type = __STRIKE;
677 
678 			return (IR_STOP);
679 
680 		case CROUCH_TO_STAND_ARMED: // crouch to stood armed
681 			MS->Set_pose(__GUN);
682 			MS->Change_pose_in_current_anim_set();
683 			Hard_start_new_mode(NEW_AIM, __STAND);
684 
685 			return (IR_REPEAT);
686 
687 		case CROUCHING:
688 			ret = Player_interact(); // check if interact has set up a new script to run on level 2
689 			if (ret == __FINISHED_THIS_CYCLE)
690 				return (IR_TERMINATE); // set to go around again and do a cycle of the interact script
691 
692 			ret = Player_press_strike_button();
693 			if (ret == __FINISHED_THIS_CYCLE)
694 				return (IR_TERMINATE); // set to go around again and do a cycle of the interact script
695 
696 			ret = Player_crouching();
697 			if (ret == __FINISHED_THIS_CYCLE)
698 				return (IR_REPEAT); //
699 
700 			break;
701 
702 		case INVENTORY:
703 
704 			// Cycle the inventory's logic.
705 			g_oIconListManager->CycleInventoryLogic(cur_state);
706 
707 			// If the Remora is now shut down, we need to return to player-standing mode.
708 			if (!g_oIconListManager->IsActive()) {
709 
710 				if (g_oIconListManager->IsHolding()) {
711 
712 					// reload gun
713 					if ((g_oIconListManager->Holding(ARMS_AMMO_NAME)) && (player_status == STOOD)) {
714 						interact_lock = TRUE8;
715 						g_oIconListManager->Drop();
716 
717 						// Make sure number of clips is > 0
718 						bull_per_clip = GetBulletsPerClip();
719 
720 						if ((has_weapon) && GetNoAmmoClips() && (GetNoBullets() < bull_per_clip)) {
721 							if (previous_stat == CROUCHING) {
722 								MS->Set_pose(__CROUCH_GUN);
723 								MS->Change_pose_in_current_anim_set();
724 								Hard_start_new_mode(FIN_NORMAL_CROUCH_RELOAD, __LOAD_GUN_CROUCH_2);
725 							} else {
726 								MS->Set_pose(__GUN);
727 								MS->Change_pose_in_current_anim_set();
728 								Hard_start_new_mode(FIN_NORMAL_RELOAD, __LOAD_GUN_2);
729 							}
730 							return IR_REPEAT;
731 						}
732 					}
733 
734 					// use a medi kit
735 					if (g_oIconListManager->Holding(ARMS_HEALTH_NAME)) {
736 						int32 hit_var;
737 						uint32 hits;
738 						uint32 new_energy;
739 
740 						interact_lock = TRUE8;
741 
742 						ob = (c_game_object *)MS->objects->Fetch_item_by_number(player_id);
743 
744 						// Make sure number of medi-packs is > 0
745 						if (GetNoMediPacks() > 0) {
746 							hit_var = ob->GetVariable((const char *)"hits");
747 							hits = ob->GetIntegerVariable(hit_var);
748 							if (hits != MAX_HITS) {
749 								new_energy = hits + MAX_HITS / 2;
750 								if (new_energy > MAX_HITS)
751 									new_energy = MAX_HITS;
752 
753 								ob->SetIntegerVariable(hit_var, new_energy); // full health again
754 								UseMediPacks(1); // use the pack
755 								// Play the medi-pack sound !
756 								RegisterSoundSpecial(defaultUsingMediSfx, addingMediDesc, 127, 0);
757 								MS->health_time = 12;
758 							}
759 						}
760 						g_oIconListManager->Drop();
761 
762 						Pop_control_mode();
763 						Pop_player_stat();
764 						return IR_REPEAT;
765 					}
766 
767 					// gun
768 					if (g_oIconListManager->Holding(ARMS_GUN_NAME)) {
769 						interact_lock = TRUE8;
770 						g_oIconListManager->Drop();
771 						Pop_control_mode();
772 						Pop_player_stat();
773 						return IR_REPEAT;
774 					}
775 
776 					ret = Player_interact(); // check if interact has set up a new script to run on level 2
777 					if (ret == __FINISHED_THIS_CYCLE)
778 						return (IR_TERMINATE); // set to go around again and do a cycle of the interact script
779 				}
780 
781 				Pop_control_mode();
782 				Pop_player_stat();
783 			}
784 
785 			break;
786 
787 		case FIN_NORMAL_RELOAD:
788 			UseAmmoClips(1); // use a a clip
789 			bull_per_clip = GetBulletsPerClip();
790 			SetBullets(bull_per_clip); // reload
791 			MS->Set_pose(__NOT_ARMED);
792 			MS->Change_pose_in_current_anim_set();
793 			Hard_start_new_mode(STOOD, __STAND);
794 			return (IR_STOP);
795 			break;
796 		case FIN_NORMAL_CROUCH_RELOAD:
797 			UseAmmoClips(1); // use a a clip
798 			bull_per_clip = GetBulletsPerClip();
799 			SetBullets(bull_per_clip); // reload
800 			MS->Set_pose(__CROUCH_NOT_ARMED);
801 			MS->Change_pose_in_current_anim_set();
802 			Hard_start_new_mode(CROUCHING, __STAND);
803 			return (IR_STOP);
804 			break;
805 
806 		case FINISHED_RELOADING:
807 
808 			UseAmmoClips(1); // use a a clip
809 
810 			bull_per_clip = GetBulletsPerClip();
811 
812 			SetBullets(bull_per_clip); // reload
813 
814 			Pop_control_mode();
815 			Pop_player_stat();
816 			break;
817 
818 		case REMORA:
819 			// The Remora is currently up over the game screen.  Most important check is to see if player
820 			// wants to quit it.
821 			if (cur_state.IsButtonSet(__REMORA)) {
822 				if (!remora_lock) {
823 					g_oRemora->DeactivateRemora(FALSE8);
824 					remora_lock = TRUE8;
825 				}
826 			} else {
827 				remora_lock = FALSE8;
828 			}
829 
830 			// Now just run its logic.  It will process the 'deactivate' message if one was posted in previous line.
831 			g_oRemora->CycleRemoraLogic(cur_state);
832 
833 			// Cycle the inventory logic if it is active.  Note though that the fact that the Remora is active does
834 			// not mean the inventory is, because there could be a gap between menus being displayed.
835 			if (g_oIconListManager->IsActive())
836 				g_oIconListManager->CycleInventoryLogic(cur_state);
837 
838 			// If the Remora is now shut down, we need to return to player-standing mode.
839 			if (!g_oRemora->IsActive()) {
840 				Pop_control_mode();
841 
842 				Pop_player_stat();
843 
844 				MS->Setup_prop_sleep_states(); // recompute prop sleep states once we leave remora
845 			}
846 
847 			return (IR_REPEAT);
848 
849 		case LINKING:
850 			ret = Process_link();
851 			break;
852 		case EASY_LINKING:
853 			ret = Process_easy_link();
854 			break;
855 		case STILL_LINKING:
856 			ret = Process_still_link();
857 			break;
858 		case STILL_REVERSE_LINKING:
859 			ret = Process_reverse_still_link();
860 			break;
861 
862 		case FAST_LINKING:
863 			ret = Process_fast_link();
864 			break;
865 		case REVERSE_LINKING:
866 			ret = Process_reverse_link();
867 			break;
868 		case GUN_LINKING:
869 			ret = Player_press_fire_button();
870 			if (ret == __FINISHED_THIS_CYCLE)
871 				return (IR_REPEAT); //
872 
873 			ret = Process_link();
874 			break;
875 
876 		case STRIKING:
877 			ret = Process_strike();
878 			break;
879 
880 		// stair
881 		case ON_STAIRS:
882 			ret = Player_stairs();
883 			break;
884 		case RUNNING_ON_STAIRS:
885 			ret = Player_running_on_stairs();
886 			break;
887 		case STOOD_ON_STAIRS:
888 			ret = Player_stood_on_stairs();
889 			break;
890 
891 		case REVERSE_ON_STAIRS:
892 			if (stair_dir != MS->stairs[stair_num].up)
893 				log->pan = MS->stairs[stair_num].pan + HALF_TURN; // if we are not traveling in the stairs original direction then we reverse the pan by 180deg
894 
895 			else
896 				log->pan = MS->stairs[stair_num].pan; // otherwise we are turning to the stairs true pan and simple use that value
897 
898 			player_status = ON_STAIRS;
899 			ret = __MORE_THIS_CYCLE;
900 			break;
901 
902 		// ladder
903 		case ON_LADDER:
904 			ret = Player_ladder();
905 			break;
906 		case SLIP_SLIDIN_AWAY:
907 			ret = Player_slide_on_ladder();
908 			break;
909 		case LEAVE_LADDER: // top
910 			log->mega->actor_xyz.y += (REAL_ONE * (24 * 4));
911 			Leave_stair(); // history and stuff
912 			MS->camera_lock = FALSE8; // stop rough room cut through effect
913 			log->mega->drawShadow = TRUE8; // shadows back on
914 			Start_new_mode(STOOD);
915 			ret = __MORE_THIS_CYCLE;
916 			break;
917 		case LEAVE_LADDER_BOTTOM:
918 			log->pan += HALF_TURN;
919 			MS->floor_def->Allign_with_floor(log->mega);
920 			Start_new_mode(STOOD);
921 			ret = __MORE_THIS_CYCLE;
922 			break;
923 
924 		case BEGIN_DOWN_LADDER:
925 			log->mega->actor_xyz.y -= (REAL_ONE * (24 * 4));
926 			// log->pan = MS->stairs[stair_num].pan + HALF_TURN; //if we are not traveling in the stairs original direction then we reverse the pan by 180deg
927 			stair_unit += 5;
928 			Set_player_status(ON_LADDER);
929 			ret = __MORE_THIS_CYCLE;
930 			break;
931 
932 		default:
933 			Fatal_error("_player::Gateway player in illegal mode %d", player_status);
934 			break;
935 		}
936 	} while (ret == __MORE_THIS_CYCLE);
937 
938 	return (IR_REPEAT);
939 }
940 
Set_player_status(_player_stat new_mode)941 void _player::Set_player_status(_player_stat new_mode) {
942 	// simply force the mode
943 	// for example, called after an interaction to put us back standing
944 
945 	player_status = new_mode;
946 }
947 
Start_new_mode(_player_stat new_mode)948 void _player::Start_new_mode(_player_stat new_mode) {
949 	// start new mode - no linking anim
950 
951 	log->anim_pc = 0;
952 	player_status = new_mode;
953 }
954 
Push_player_stat()955 void _player::Push_player_stat() {
956 	previous_stat = player_status;
957 }
958 
Pop_player_stat()959 void _player::Pop_player_stat() {
960 	player_status = previous_stat;
961 }
962 
Soft_start_new_mode_no_link(_player_stat new_mode,__mega_set_names type)963 void _player::Soft_start_new_mode_no_link(_player_stat new_mode, __mega_set_names type) {
964 	// change anim mode
965 	// where type is the anim that will be played in the target mode
966 
967 	// eg walk to run (which has no link)
968 
969 	int32 diff = 1000000; // a big number
970 	uint32 old_leg_pos;
971 	int32 j;
972 
973 	// link anim not in CAPS
974 	if ((!log->voxel_info->IsAnimTable(type)))
975 		Fatal_error("Soft_start_new_mode_no_link missing anim caps %s", master_anim_name_table[type].name);
976 
977 	// JAKE : just in case defrag has moved something about
978 	PXanim *pCurAnim = (PXanim *)rs_anims->Res_open(log->voxel_info->get_info_name(log->cur_anim_type), log->voxel_info->info_name_hash[log->cur_anim_type],
979 	                                                log->voxel_info->base_path, log->voxel_info->base_path_hash); //
980 
981 	// find out leg position for current frame
982 	old_leg_pos = PXFrameEnOfAnim(log->anim_pc, pCurAnim)->left_foot_distance;
983 
984 	// JAKE : just in case defrag has moved something about
985 	PXanim *pLnkAnim = (PXanim *)rs_anims->Res_open(log->voxel_info->get_info_name(type), log->voxel_info->info_name_hash[type], log->voxel_info->base_path,
986 	                                                log->voxel_info->base_path_hash); //
987 	// see which has the closest leg position
988 	for (j = 0; j < (pLnkAnim->frame_qty - 1); j++) {
989 		int32 foot = PXFrameEnOfAnim(j, pLnkAnim)->left_foot_distance;
990 		int32 d = twabs(foot - old_leg_pos);
991 		if (d < diff) {
992 			diff = d;
993 			log->anim_pc = j; // this frame is best so far
994 		}
995 	}
996 
997 	// set to linking mode
998 	player_status = new_mode;
999 
1000 	// set anim type to link
1001 	log->cur_anim_type = type;
1002 }
1003 
Soft_start_new_mode(_player_stat new_mode,__mega_set_names opt_link)1004 void _player::Soft_start_new_mode(_player_stat new_mode, __mega_set_names opt_link) {
1005 	// change anim mode via an optional link anim
1006 	// it is ok for the link anim to not exist despite being specified
1007 
1008 	// NOTE this sets the first frame of the link anim so the caller should return to Gate_way() with a __FINISHED_THIS_CYCLE
1009 
1010 	int32 diff = 1000000; // a big number
1011 	uint32 old_leg_pos;
1012 	int32 j;
1013 
1014 	// link anim not in CAPS
1015 	if ((!log->voxel_info->IsAnimTable(opt_link))) {
1016 		Zdebug(1, "start_new_mode missing anim caps %s", master_anim_name_table[opt_link].name);
1017 
1018 		log->anim_pc = 0;
1019 		player_status = new_mode;
1020 
1021 		return;
1022 	}
1023 
1024 	//	Zdebug("\ncalc start link frame");
1025 
1026 	// JAKE : just in case defrag has moved something about
1027 	PXanim *pCurAnim = (PXanim *)rs_anims->Res_open(log->voxel_info->get_info_name(log->cur_anim_type), log->voxel_info->info_name_hash[log->cur_anim_type],
1028 	                                                log->voxel_info->base_path, log->voxel_info->base_path_hash); //
1029 
1030 	// find out leg position for current frame
1031 	old_leg_pos = PXFrameEnOfAnim(log->anim_pc, pCurAnim)->left_foot_distance;
1032 
1033 	// JAKE : just in case defrag has moved something about
1034 	PXanim *pLnkAnim = (PXanim *)rs_anims->Res_open(log->voxel_info->get_info_name(opt_link), log->voxel_info->info_name_hash[opt_link], log->voxel_info->base_path,
1035 	                                                log->voxel_info->base_path_hash); //
1036 
1037 	// see which has the closest leg position
1038 	for (j = 0; j < (pLnkAnim->frame_qty - 1); j++) {
1039 		int32 foot = PXFrameEnOfAnim(j, pLnkAnim)->left_foot_distance;
1040 		int32 d = twabs(foot - old_leg_pos);
1041 		if (d < diff) {
1042 			diff = d;
1043 			log->anim_pc = j; // this frame is best so far
1044 		}
1045 	}
1046 
1047 	// set to linking mode
1048 	player_status = FAST_LINKING;
1049 
1050 	// remember new mode to switch in after link anim
1051 	stat_after_link = new_mode;
1052 
1053 	// set anim type to link
1054 	log->cur_anim_type = opt_link;
1055 }
1056 
Fast_hard_start_new_mode(_player_stat new_mode,__mega_set_names opt_link)1057 void _player::Fast_hard_start_new_mode(_player_stat new_mode, __mega_set_names opt_link) {
1058 	Hard_start_new_mode(new_mode, opt_link);
1059 	player_status = FAST_LINKING;
1060 }
1061 
Hard_start_new_mode(_player_stat new_mode,__mega_set_names opt_link)1062 void _player::Hard_start_new_mode(_player_stat new_mode, __mega_set_names opt_link) {
1063 	// change anim mode via an optional link anim
1064 	// it is ok for the link anim to not exist despite being specified
1065 
1066 	// NOTE this sets the first frame of the link anim so the caller should return to Gate_way() with a __FINISHED_THIS_CYCLE
1067 
1068 	// link anim not in CAPS
1069 	if ((!log->voxel_info->IsAnimTable(opt_link))) {
1070 		warning("start_new_mode missing anim caps %s", master_anim_name_table[opt_link].name);
1071 
1072 		log->anim_pc = 0;
1073 		player_status = new_mode;
1074 
1075 		return;
1076 	}
1077 
1078 	// link anim has been requested - the link exists
1079 
1080 	log->anim_pc = 0; // start at hard 0
1081 
1082 	// set to linking mode
1083 	player_status = LINKING;
1084 
1085 	// remember new mode to switch in after link anim
1086 	stat_after_link = new_mode;
1087 
1088 	// set anim type to link
1089 	log->cur_anim_type = opt_link;
1090 }
1091 
Easy_start_new_mode(_player_stat new_mode,__mega_set_names opt_link)1092 void _player::Easy_start_new_mode(_player_stat new_mode, __mega_set_names opt_link) {
1093 	// change anim mode via an optional link anim
1094 	// the link anim is hard started but played easy - i.e. without barrier chacking
1095 
1096 	// NOTE this sets the first frame of the link anim so the caller should return to Gate_way() with a __FINISHED_THIS_CYCLE
1097 
1098 	// link anim not in CAPS
1099 	if ((!log->voxel_info->IsAnimTable(opt_link))) {
1100 		Zdebug(1, "start_new_mode missing anim caps %s", master_anim_name_table[opt_link].name);
1101 
1102 		log->anim_pc = 0;
1103 		player_status = new_mode;
1104 
1105 		return;
1106 	}
1107 
1108 	// set anim type to link
1109 	log->cur_anim_type = opt_link;
1110 
1111 	// get animation
1112 	PXanim *anim = (PXanim *)rs_anims->Res_open(log->voxel_info->get_info_name(log->cur_anim_type), log->voxel_info->info_name_hash[log->cur_anim_type],
1113 	                                            log->voxel_info->base_path, log->voxel_info->base_path_hash); //
1114 
1115 	log->anim_pc = anim->frame_qty - 2;
1116 	MS->Easy_frame_and_motion(log->cur_anim_type, TRUE8, 1); // push to frame 0
1117 	log->anim_pc = 0;
1118 
1119 	// set to linking mode
1120 	player_status = EASY_LINKING;
1121 
1122 	// remember new mode to switch in after link anim
1123 	stat_after_link = new_mode;
1124 }
1125 
Set_to_first_frame(__mega_set_names opt_link)1126 void _player::Set_to_first_frame(__mega_set_names opt_link) {
1127 	// link anim not in CAPS
1128 	if ((!log->voxel_info->IsAnimTable(opt_link)))
1129 		Fatal_error("Set_to_first_frame missing anim caps %s", master_anim_name_table[opt_link].name);
1130 
1131 	// set anim type to link
1132 	log->cur_anim_type = opt_link;
1133 	log->anim_pc = 0;
1134 }
1135 
Set_to_last_frame(__mega_set_names opt_link)1136 void _player::Set_to_last_frame(__mega_set_names opt_link) {
1137 	// link anim not in CAPS
1138 	if ((!log->voxel_info->IsAnimTable(opt_link)))
1139 		Fatal_error("Set_to_last_frame missing anim caps %s", master_anim_name_table[opt_link].name);
1140 
1141 	// set anim type to link
1142 	log->cur_anim_type = opt_link;
1143 
1144 	// get animation
1145 	PXanim *anim = (PXanim *)rs_anims->Res_open(log->voxel_info->get_info_name(log->cur_anim_type), log->voxel_info->info_name_hash[log->cur_anim_type],
1146 	                                            log->voxel_info->base_path, log->voxel_info->base_path_hash); //
1147 
1148 	log->anim_pc = anim->frame_qty - 2;
1149 }
1150 
Still_start_new_mode(_player_stat new_mode,__mega_set_names link)1151 void _player::Still_start_new_mode(_player_stat new_mode, __mega_set_names link) {
1152 	// change anim mode via a STILL link anim
1153 
1154 	// link anim not in CAPS
1155 	if ((!log->voxel_info->IsAnimTable(link))) {
1156 		log->anim_pc = 0;
1157 		player_status = new_mode;
1158 
1159 		return;
1160 	}
1161 
1162 	// link anim has been requested - the link exists
1163 
1164 	// start at first frame
1165 	log->anim_pc = 0;
1166 
1167 	// set to linking mode
1168 	player_status = STILL_LINKING;
1169 
1170 	// remember new mode to switch in after link anim
1171 	stat_after_link = new_mode;
1172 
1173 	// set anim type to link
1174 	log->cur_anim_type = link;
1175 }
1176 
Still_reverse_start_new_mode(_player_stat new_mode,__mega_set_names link)1177 void _player::Still_reverse_start_new_mode(_player_stat new_mode, __mega_set_names link) {
1178 	// change anim mode via a STILL link anim
1179 
1180 	Set_to_last_frame(link);
1181 
1182 	// set to linking mode
1183 	player_status = STILL_REVERSE_LINKING;
1184 
1185 	// remember new mode to switch in after link anim
1186 	stat_after_link = new_mode;
1187 
1188 	// set anim type to link
1189 	log->cur_anim_type = link;
1190 }
1191 
Hard_start_reverse_new_mode(_player_stat new_mode,__mega_set_names opt_link)1192 void _player::Hard_start_reverse_new_mode(_player_stat new_mode, __mega_set_names opt_link) {
1193 	// change anim mode via an optional link anim
1194 	// it is ok for the link anim to not exist despite being specified
1195 	// the link anim is played end to beginning
1196 
1197 	// NOTE this sets the first frame of the link anim so the caller should return to Gate_way() with a __FINISHED_THIS_CYCLE
1198 
1199 	// link anim not in CAPS
1200 	if ((!log->voxel_info->IsAnimTable(opt_link))) {
1201 		Zdebug(1, "Hard_start_reverse_new_mode missing anim caps %s", master_anim_name_table[opt_link].name);
1202 
1203 		log->anim_pc = 0;
1204 		player_status = new_mode;
1205 
1206 		return;
1207 	}
1208 
1209 	// link anim has been requested - the link exists
1210 
1211 	PXanim *anim = (PXanim *)rs_anims->Res_open(log->voxel_info->get_info_name(opt_link), log->voxel_info->info_name_hash[opt_link], log->voxel_info->base_path,
1212 	                                            log->voxel_info->base_path_hash); //
1213 	log->anim_pc = anim->frame_qty - 2;
1214 
1215 	// set to linking mode
1216 	player_status = REVERSE_LINKING;
1217 
1218 	// remember new mode to switch in after link anim
1219 	stat_after_link = new_mode;
1220 
1221 	// set anim type to link
1222 	log->cur_anim_type = opt_link;
1223 }
1224 
Soft_start_new_mode(_player_stat new_mode,__mega_set_names opt_link,__mega_set_names opt_link2)1225 void _player::Soft_start_new_mode(_player_stat new_mode, __mega_set_names opt_link, __mega_set_names opt_link2) {
1226 	// this is the 2 link anim version of Start_new_mode
1227 	// we pick the best frame match from the two link anims specified
1228 
1229 	// change anim mode via an optional link anim
1230 	// it is ok for the link anim to not exist despite being specified
1231 
1232 	// NOTE this sets the first frame of the link anim so the caller should return to Gate_way() with a __FINISHED_THIS_CYCLE
1233 
1234 	int32 diff = 1000000; // a big number
1235 
1236 	uint32 old_leg_pos;
1237 	int32 j;
1238 
1239 	// no link anim specified OR
1240 	// either link anim not in CAPS then just forget all about it - hey, too bad, ok?
1241 	if ((!log->voxel_info->IsAnimTable(opt_link)) || (!log->voxel_info->IsAnimTable(opt_link2))) {
1242 		Zdebug(1, "start_new_mode missing anim caps %s %s", master_anim_name_table[opt_link].name, master_anim_name_table[opt_link2].name);
1243 
1244 		log->anim_pc = 0;
1245 		player_status = new_mode;
1246 
1247 		return;
1248 	}
1249 
1250 	// link anim has been requested - the link exists
1251 
1252 	// find frame to skip to
1253 
1254 	// Load the current anim
1255 	PXanim *pCurAnim = (PXanim *)rs_anims->Res_open(log->voxel_info->get_info_name(log->cur_anim_type), log->voxel_info->info_name_hash[log->cur_anim_type],
1256 	                                                log->voxel_info->base_path, log->voxel_info->base_path_hash); //
1257 
1258 	// find out leg position for current frame
1259 	old_leg_pos = PXFrameEnOfAnim(log->anim_pc, pCurAnim)->left_foot_distance;
1260 
1261 	// Load the first link candidate anim
1262 	PXanim *pLnkAnim = (PXanim *)rs_anims->Res_open(log->voxel_info->get_info_name(opt_link), log->voxel_info->info_name_hash[opt_link], log->voxel_info->base_path,
1263 	                                                log->voxel_info->base_path_hash); //
1264 
1265 	// see which has the closest leg position
1266 	for (j = 0; j < (pLnkAnim->frame_qty - 1); j++) {
1267 		int32 foot = PXFrameEnOfAnim(j, pLnkAnim)->left_foot_distance;
1268 		int32 d = twabs(foot - old_leg_pos);
1269 		if (d < diff) {
1270 			diff = d;
1271 			log->anim_pc = j; // this frame is best so far
1272 			log->cur_anim_type = opt_link;
1273 		}
1274 	}
1275 
1276 	// Load the second link candidate file
1277 	pLnkAnim = (PXanim *)rs_anims->Res_open(log->voxel_info->get_info_name(opt_link2), log->voxel_info->info_name_hash[opt_link2], log->voxel_info->base_path,
1278 	                                        log->voxel_info->base_path_hash); //
1279 
1280 	// see which has the closest leg position
1281 	for (j = 0; j < (pLnkAnim->frame_qty - 1); j++) {
1282 		int32 foot = PXFrameEnOfAnim(j, pLnkAnim)->left_foot_distance;
1283 		int32 d = twabs(foot - old_leg_pos);
1284 		if (d < diff) {
1285 			diff = d;
1286 			log->anim_pc = j; // this frame is best so far
1287 			log->cur_anim_type = opt_link2;
1288 		}
1289 	}
1290 
1291 	// set to linking mode
1292 	player_status = FAST_LINKING;
1293 
1294 	// remember new mode to switch in after link anim
1295 	stat_after_link = new_mode;
1296 }
1297 
Process_strike()1298 __mode_return _player::Process_strike() {
1299 	// run the strike anim
1300 	bool8 ret;
1301 	int32 retval;
1302 	PXreal int_x = REAL_ZERO;
1303 	PXreal int_z = REAL_ZERO; // for the marker
1304 	PXreal hit_x, hit_z; //
1305 
1306 	if ((has_weapon) && (cur_state.IsButtonSet(__ARMUNARM))) { // pull gun
1307 
1308 		MS->Set_pose(__GUN);
1309 		MS->Change_pose_in_current_anim_set();
1310 
1311 		if (armedChangesMode == 1)
1312 			Push_control_mode(ACTOR_RELATIVE);
1313 
1314 		Hard_start_new_mode(NEW_AIM, __PULL_OUT_WEAPON);
1315 
1316 		return (__FINISHED_THIS_CYCLE);
1317 	}
1318 
1319 	// get animation
1320 	PXanim *pAnim = (PXanim *)rs_anims->Res_open(log->voxel_info->get_info_name(log->cur_anim_type), log->voxel_info->info_name_hash[log->cur_anim_type],
1321 	                                             log->voxel_info->base_path, log->voxel_info->base_path_hash); //
1322 
1323 	// last frame?
1324 	if ((int32)(log->anim_pc + 1) == (pAnim->frame_qty - 1)) {
1325 		// we displayed the last frame last cycle - so display first of new mode this cycle
1326 
1327 		player_status = STOOD;
1328 
1329 		// reset pc
1330 		log->anim_pc = 0;
1331 
1332 		// kick in now
1333 		return (__MORE_THIS_CYCLE);
1334 	}
1335 
1336 	// shift character and frame forward by the amount appropriate
1337 	ret = MS->Advance_frame_and_motion(log->cur_anim_type, TRUE8, 1);
1338 
1339 	if (!ret) { // could not move? Abandon the link and hit the mode (or perhaps stand?)
1340 		// set target after-link-anim-mode
1341 		player_status = STOOD;
1342 
1343 		// reset pc
1344 		log->anim_pc = 0;
1345 
1346 		// kick in now
1347 		return (__MORE_THIS_CYCLE);
1348 	}
1349 
1350 	// check for the hit frame
1351 	// The animation will have made the INT marker visible on the frame designated to be the "hit" frame
1352 	// Get the current frame from the anim
1353 	PXframe *currentFrame = NULL;
1354 	// Note the weird = NULL & then setting it removes GCC warnings
1355 	currentFrame = PXFrameEnOfAnim(log->anim_pc, pAnim);
1356 
1357 	if (currentFrame->marker_qty > INT_POS) {
1358 		if (INT_TYPE == currentFrame->markers[INT_POS].GetType()) {
1359 			// punching a prop
1360 			if ((interact_selected) && (MS->logic_structs[cur_interact_id]->image_type == PROP)) {
1361 				MS->Call_socket(cur_interact_id, "ko", &retval); // call a ko script if there is one
1362 			}
1363 			// punching an evil live mega character
1364 			else if ((interact_selected) && (MS->logic_structs[cur_interact_id]->image_type == VOXEL) &&
1365 			         (MS->logic_structs[cur_interact_id]->ob_status != OB_STATUS_HELD) && (MS->logic_structs[cur_interact_id]->mega->is_evil)) {
1366 
1367 				// ok, final check to see if mega is dead
1368 				if (MS->logic_structs[cur_interact_id]->mega->dead)
1369 					return __FINISHED_THIS_CYCLE; // dead
1370 
1371 				if (MS->logic_structs[cur_interact_id]->mega->Is_crouched())
1372 					return __FINISHED_THIS_CYCLE; // crouching mega
1373 
1374 				// get interact marker offset
1375 				PXreal x_org, z_org, unused;
1376 				PXFrameEnOfAnim(0, pAnim)->markers[ORG_POS].GetXYZ(&x_org, &unused, &z_org);
1377 
1378 				// The interact marker exists
1379 				PXreal x_int, z_int;
1380 
1381 				currentFrame->markers[INT_POS].GetXYZ(&x_int, &unused, &z_int);
1382 
1383 				int_x = x_int - x_org;
1384 				int_z = z_int - z_org;
1385 
1386 				// now project the interaction offset forward from our org marker pan
1387 				// this will give us our interact (fist) coordinate
1388 				PXfloat ang = log->pan * TWO_PI;
1389 				PXfloat cang = (PXfloat)PXcos(ang);
1390 				PXfloat sang = (PXfloat)PXsin(ang);
1391 
1392 				hit_x = log->mega->actor_xyz.x + PXfloat2PXreal(int_x * cang + int_z * sang);
1393 				hit_z = log->mega->actor_xyz.z + PXfloat2PXreal(int_z * cang - int_x * sang);
1394 
1395 				if ((PXfabs(hit_x - MS->logic_structs[cur_interact_id]->mega->actor_xyz.x) < (PXreal)150) && /*original EU PSX release is 100*/
1396 				    (PXfabs(hit_z - MS->logic_structs[cur_interact_id]->mega->actor_xyz.z) < (PXreal)150)) {
1397 
1398 					if (!g_oLineOfSight->LineOfSight(cur_interact_id, Fetch_player_id())) {
1399 						//								behind
1400 						ret = MS->Call_socket(cur_interact_id, "ko", &retval);
1401 						if (!ret)
1402 							Fatal_error("no ko script for object [%s]", MS->socket_object->GetName());
1403 					} else { // infront
1404 						ret = MS->Call_socket(cur_interact_id, "see_ko", &retval);
1405 						if (!ret)
1406 							Fatal_error("no see_ko script for object [%s]", MS->socket_object->GetName());
1407 					}
1408 					MS->Signal_to_other_guards(); // make other guards see this!
1409 					return __FINISHED_THIS_CYCLE;
1410 				}
1411 			}
1412 		}
1413 		MS->Signal_to_guards(); // make all guards see this!
1414 	}
1415 
1416 	return __FINISHED_THIS_CYCLE;
1417 }
1418 
Process_fast_link()1419 __mode_return _player::Process_fast_link() {
1420 	// DOUBLE SPEED LINK
1421 	// play link anim until finished then switch in next mode WHEN LAST FRAME is reached
1422 	// link plays without user input
1423 
1424 	// last frame? Then move mode on
1425 
1426 	bool8 ret;
1427 
1428 	// get animation
1429 	PXanim *anim = (PXanim *)rs_anims->Res_open(log->voxel_info->get_info_name(log->cur_anim_type), log->voxel_info->info_name_hash[log->cur_anim_type],
1430 	                                            log->voxel_info->base_path, log->voxel_info->base_path_hash); //
1431 
1432 	// skip a frame
1433 	//	log->anim_pc+=1;
1434 
1435 	// last frame?
1436 	if ((int32)(log->anim_pc + 2) >= (anim->frame_qty - 1)) {
1437 		// we displayed the last frame last cycle - so display first of new mode this cycle
1438 
1439 		// set target after-link-anim-mode
1440 		player_status = stat_after_link;
1441 
1442 		// reset pc
1443 		log->anim_pc = 0;
1444 
1445 		// kick in now
1446 		return (__MORE_THIS_CYCLE);
1447 	}
1448 
1449 	// shift character and frame forward by the amount appropriate
1450 	ret = MS->Advance_frame_and_motion(log->cur_anim_type, TRUE8, 2);
1451 
1452 	if (!ret) { // could not move? Abandon the link and hit the mode (or perhaps stand?)
1453 		player_status = stat_after_link;
1454 
1455 		// reset pc
1456 		log->anim_pc = 0;
1457 
1458 		// kick in now
1459 		return (__MORE_THIS_CYCLE);
1460 	}
1461 
1462 	return (__FINISHED_THIS_CYCLE);
1463 }
1464 
Process_link()1465 __mode_return _player::Process_link() {
1466 	// play link anim until finished then switch in next mode WHEN LAST FRAME is reached
1467 	// link plays without user input
1468 
1469 	// last frame? Then move mode on
1470 
1471 	bool8 ret;
1472 
1473 	// get animation
1474 	PXanim *anim = (PXanim *)rs_anims->Res_open(log->voxel_info->get_info_name(log->cur_anim_type), log->voxel_info->info_name_hash[log->cur_anim_type],
1475 	                                            log->voxel_info->base_path, log->voxel_info->base_path_hash); //
1476 
1477 	// last frame?
1478 	if ((int32)(log->anim_pc + 1) == (anim->frame_qty - 1)) {
1479 		//		we displayed the last frame last cycle - so display first of new mode this cycle
1480 		player_status = stat_after_link;
1481 
1482 		//		reset pc
1483 		log->anim_pc = 0;
1484 
1485 		//		kick in now
1486 		return (__MORE_THIS_CYCLE);
1487 	}
1488 
1489 	// shift character and frame forward by the amount appropriate
1490 	ret = MS->Advance_frame_and_motion(log->cur_anim_type, TRUE8, 1);
1491 
1492 	// Very nasty hard wiring but hey it is the last day of the project
1493 	if (((log->cur_anim_type == __LOAD_GUN) || (log->cur_anim_type == __LOAD_GUN_2) || (log->cur_anim_type == __LOAD_GUN_CROUCH_2)) && (log->anim_pc == 6)) {
1494 		// Play the clip sound !
1495 		RegisterSoundSpecial(defaultAddingClipSfx, addingClipDesc, 127, 0);
1496 	}
1497 
1498 	if (!ret) { // could not move? Abandon the link and hit the mode (or perhaps stand?)
1499 
1500 		//		set target after-link-anim-mode
1501 		player_status = stat_after_link;
1502 
1503 		//		reset pc
1504 		log->anim_pc = 0;
1505 
1506 		//		kick in now
1507 		return (__MORE_THIS_CYCLE);
1508 	}
1509 
1510 	return (__FINISHED_THIS_CYCLE);
1511 }
1512 
Process_easy_link()1513 __mode_return _player::Process_easy_link() {
1514 	// play link anim until finished then switch in next mode WHEN LAST FRAME is reached
1515 	// link plays without user input
1516 
1517 	// last frame? Then move mode on
1518 
1519 	// get animation
1520 	PXanim *anim = (PXanim *)rs_anims->Res_open(log->voxel_info->get_info_name(log->cur_anim_type), log->voxel_info->info_name_hash[log->cur_anim_type],
1521 	                                            log->voxel_info->base_path, log->voxel_info->base_path_hash); //
1522 
1523 	// last frame?
1524 	if ((int32)(log->anim_pc + 1) == (anim->frame_qty - 1)) {
1525 		// we displayed the last frame last cycle - so display first of new mode this cycle
1526 		// set target after-link-anim-mode
1527 		player_status = stat_after_link;
1528 
1529 		// reset pc
1530 		log->anim_pc = 0;
1531 
1532 		// kick in now
1533 		return (__MORE_THIS_CYCLE);
1534 	}
1535 
1536 	// shift character and frame forward by the amount appropriate
1537 	MS->Easy_frame_and_motion(log->cur_anim_type, TRUE8, 1);
1538 
1539 	return (__FINISHED_THIS_CYCLE);
1540 }
1541 
Process_still_link()1542 __mode_return _player::Process_still_link() {
1543 	// play anim with no movement - v easy!
1544 
1545 	PXanim *anim = (PXanim *)rs_anims->Res_open(log->voxel_info->get_info_name(log->cur_anim_type), log->voxel_info->info_name_hash[log->cur_anim_type],
1546 	                                            log->voxel_info->base_path, log->voxel_info->base_path_hash); //
1547 
1548 	// last frame currently displayed?
1549 	if ((int32)(log->anim_pc + 1) == (anim->frame_qty - 1)) {
1550 		// we displayed the last frame last cycle
1551 
1552 		player_status = stat_after_link;
1553 
1554 		// kick in now
1555 		return (__MORE_THIS_CYCLE);
1556 	}
1557 
1558 	//	ok, advance frame but not position
1559 	log->anim_pc = (log->anim_pc + 1) % (anim->frame_qty - 1);
1560 
1561 	return __FINISHED_THIS_CYCLE;
1562 }
1563 
Process_reverse_still_link()1564 __mode_return _player::Process_reverse_still_link() {
1565 	// play anim with no movement - v easy!
1566 
1567 	// last frame currently displayed?
1568 	if (!log->anim_pc) {
1569 		// we displayed the last frame last cycle
1570 
1571 		player_status = stat_after_link;
1572 
1573 		// kick in now
1574 		return (__MORE_THIS_CYCLE);
1575 	}
1576 
1577 	//	ok, advance frame but not position
1578 	log->anim_pc -= 1;
1579 
1580 	return __FINISHED_THIS_CYCLE;
1581 }
1582 
Process_reverse_link()1583 __mode_return _player::Process_reverse_link() {
1584 	// play link anim until finished then switch in next mode WHEN FIRST FRAME is reached
1585 	// link plays without user input
1586 
1587 	// last frame? Then move mode on
1588 
1589 	bool8 ret;
1590 
1591 	// last frame?
1592 	if (!log->anim_pc) {
1593 		// we displayed the last frame last cycle - so display first of new mode this cycle
1594 
1595 		// set target after-link-anim-mode
1596 		player_status = stat_after_link;
1597 
1598 		// reset pc
1599 		log->anim_pc = 0;
1600 
1601 		// kick in now
1602 		return (__MORE_THIS_CYCLE);
1603 	}
1604 
1605 	// shift character and frame forward by the amount appropriate
1606 	ret = MS->Reverse_frame_and_motion(log->cur_anim_type, TRUE8, 1);
1607 
1608 	if (!ret) { // could not move forward? Abandon the link and hit the mode (or perhaps stand?)
1609 		// set target after-link-anim-mode
1610 		player_status = stat_after_link;
1611 
1612 		// reset pc
1613 		log->anim_pc = 0;
1614 
1615 		// kick in now
1616 		return (__MORE_THIS_CYCLE);
1617 	}
1618 
1619 	return (__FINISHED_THIS_CYCLE);
1620 }
1621 
Player_running_on_stairs()1622 __mode_return _player::Player_running_on_stairs() {
1623 	if (stair_dir) { // up
1624 		//		not our first step up
1625 		if (was_climbing)
1626 			log->mega->actor_xyz.y += (REAL_ONE * 36);
1627 
1628 		if ((MS->stairs[stair_num].units - stair_unit) < 2) { // 1 or 0
1629 			// check for 1 step left
1630 			if ((MS->stairs[stair_num].units - stair_unit)) { // 1
1631 				Still_start_new_mode(STOOD_ON_STAIRS, __WALK_UPSTAIRS_RIGHT_TO_STOOD_ON_STAIRS_FACING_UP);
1632 				return (__MORE_THIS_CYCLE);
1633 			}
1634 
1635 			if (begun_at_bottom) // begun at bottom so write the history
1636 				Add_to_interact_history();
1637 
1638 			Leave_stair();
1639 			return (__FINISHED_THIS_CYCLE);
1640 		} else {
1641 			// still going, turning, stopping
1642 
1643 			step_sample_num += 2; // up 2
1644 			if (step_sample_num >= MAX_stair_length)
1645 				Fatal_error("stair correction system ran out of space");
1646 
1647 			if (left_right) { // left leg
1648 				if (((stair_unit > 2)) && ((cur_state.momentum == __STILL) || (cur_state.momentum == __BACKWARD_1))) {
1649 					Still_start_new_mode(STOOD_ON_STAIRS, __WALK_UPSTAIRS_RIGHT_TO_STOOD_ON_STAIRS_FACING_UP);
1650 					return (__MORE_THIS_CYCLE);
1651 				}
1652 				Easy_start_new_mode(RUNNING_ON_STAIRS, __RUN_UPSTAIRS_LEFT); // still going
1653 			} else { // right leg
1654 				if (((stair_unit > 2)) && ((cur_state.momentum == __STILL) || (cur_state.momentum == __BACKWARD_1))) {
1655 					Still_start_new_mode(STOOD_ON_STAIRS, __WALK_UPSTAIRS_LEFT_TO_STOOD_ON_STAIRS_FACING_UP);
1656 					return (__MORE_THIS_CYCLE);
1657 				}
1658 				Easy_start_new_mode(RUNNING_ON_STAIRS, __RUN_UPSTAIRS_RIGHT); // still going
1659 			}
1660 
1661 			left_right = (uint8)(1 - left_right); // toggle
1662 		}
1663 	} else { // down
1664 		// not our first step up
1665 		if (was_climbing)
1666 			log->mega->actor_xyz.y -= (REAL_ONE * 36);
1667 
1668 		if ((MS->stairs[stair_num].units - stair_unit) < 2) { // 1 or 0
1669 
1670 			// check for 1 step left
1671 			if ((MS->stairs[stair_num].units - stair_unit)) { // 1
1672 				Still_start_new_mode(STOOD_ON_STAIRS, __WALK_DOWNSTAIRS_RIGHT_TO_STOOD_ON_STAIRS_FACING_DOWN);
1673 				return (__MORE_THIS_CYCLE);
1674 			}
1675 
1676 			if (!begun_at_bottom) // didnt begin at bottom so write the history
1677 				Add_to_interact_history();
1678 
1679 			Leave_stair();
1680 			return (__FINISHED_THIS_CYCLE);
1681 		} else {
1682 
1683 			if (step_sample_num == 0)
1684 				Fatal_error("stair correction system ran out of space");
1685 			step_sample_num -= 2; // down
1686 
1687 			if (left_right) { // left
1688 
1689 				if ((cur_state.momentum == __STILL) && (stair_unit > 2)) {
1690 					Still_start_new_mode(STOOD_ON_STAIRS, __WALK_DOWNSTAIRS_RIGHT_TO_STOOD_ON_STAIRS_FACING_DOWN);
1691 					return (__MORE_THIS_CYCLE);
1692 				}
1693 				Easy_start_new_mode(RUNNING_ON_STAIRS, __RUN_DOWNSTAIRS_LEFT);
1694 			} else { // right
1695 				if ((cur_state.momentum == __STILL) && (stair_unit > 2)) {
1696 					Still_start_new_mode(STOOD_ON_STAIRS, __WALK_DOWNSTAIRS_LEFT_TO_STOOD_ON_STAIRS_FACING_DOWN);
1697 					return (__MORE_THIS_CYCLE);
1698 				}
1699 				Easy_start_new_mode(RUNNING_ON_STAIRS, __RUN_DOWNSTAIRS_RIGHT);
1700 			}
1701 
1702 			left_right = (uint8)(1 - left_right); // toggle
1703 		}
1704 	}
1705 
1706 	was_climbing = TRUE8;
1707 	stair_unit += 2; // doing another 2 steps
1708 	return (__MORE_THIS_CYCLE);
1709 }
1710 
Player_stairs()1711 __mode_return _player::Player_stairs() {
1712 	if (stair_dir) { // up
1713 		//		not our first step up
1714 		if (was_climbing)
1715 			log->mega->actor_xyz.y += (REAL_ONE * 18);
1716 
1717 		if (stair_unit == MS->stairs[stair_num].units) {
1718 			if (begun_at_bottom) // begun at bottom so write the history
1719 				Add_to_interact_history();
1720 
1721 			Leave_stair();
1722 			return (__FINISHED_THIS_CYCLE);
1723 		} else {
1724 			step_sample_num++; // up
1725 			if (step_sample_num >= MAX_stair_length) {
1726 				Message_box("stair correction system ran out of space");
1727 
1728 				log->mega->actor_xyz.x = MS->hist_pin_x;
1729 				log->mega->actor_xyz.y = MS->hist_pin_y;
1730 				log->mega->actor_xyz.z = MS->hist_pin_z;
1731 				log->mega->on_stairs = FALSE8;
1732 				Set_player_status(STOOD);
1733 				return (__FINISHED_THIS_CYCLE);
1734 			}
1735 
1736 			if (step_samples[step_sample_num].stepped_on_step) {
1737 				log->mega->actor_xyz.x = step_samples[step_sample_num].x;
1738 				log->mega->actor_xyz.z = step_samples[step_sample_num].z;
1739 			} else {
1740 				step_samples[step_sample_num].stepped_on_step = TRUE8;
1741 				step_samples[step_sample_num].x = log->mega->actor_xyz.x;
1742 				step_samples[step_sample_num].z = log->mega->actor_xyz.z;
1743 			}
1744 
1745 			if ((stair_unit > 1) && (stair_unit < MS->stairs[stair_num].units - 1)) {
1746 				//          still going, turning, stopping
1747 				if ((cur_state.momentum == __STILL) || (cur_state.momentum == __BACKWARD_1)) {
1748 					if (left_right)
1749 						Still_start_new_mode(STOOD_ON_STAIRS, __WALK_UPSTAIRS_RIGHT_TO_STOOD_ON_STAIRS_FACING_UP);
1750 					else
1751 						Still_start_new_mode(STOOD_ON_STAIRS, __WALK_UPSTAIRS_LEFT_TO_STOOD_ON_STAIRS_FACING_UP);
1752 
1753 					return (__MORE_THIS_CYCLE);
1754 				} else if ((cur_state.turn != __NO_TURN)) { // turn around
1755 					if (!left_right)
1756 						Hard_start_new_mode(REVERSE_ON_STAIRS, __WALK_UPSTAIRS_LEFT_TO_WALK_DOWNSTAIRS_RIGHT);
1757 					else
1758 						Hard_start_new_mode(REVERSE_ON_STAIRS, __WALK_UPSTAIRS_RIGHT_TO_WALK_DOWNSTAIRS_LEFT);
1759 					player_status = EASY_LINKING; // no first frame push, and no barrier checking
1760 					stair_dir = 0;
1761 					stair_unit = (uint8)((MS->stairs[stair_num].units - stair_unit) + 1);
1762 					return (__MORE_THIS_CYCLE);
1763 				}
1764 			}
1765 
1766 			if (left_right)
1767 				Easy_start_new_mode(ON_STAIRS, __WALK_UPSTAIRS_LEFT); // still going
1768 			else
1769 				Easy_start_new_mode(ON_STAIRS, __WALK_UPSTAIRS_RIGHT); // still going
1770 
1771 			left_right = (uint8)(1 - left_right); // toggle
1772 		}
1773 
1774 	} else { // down
1775 		//		not our first step up
1776 		if (was_climbing)
1777 			log->mega->actor_xyz.y -= (REAL_ONE * 18);
1778 
1779 		if (stair_unit == MS->stairs[stair_num].units) {
1780 
1781 			if (!begun_at_bottom) // didnt begin at bottom so write the history
1782 				Add_to_interact_history();
1783 
1784 			Leave_stair();
1785 			return (__FINISHED_THIS_CYCLE);
1786 		} else {
1787 			if (!step_sample_num) {
1788 				Message_box("stair correction system ran out of space (went negative)");
1789 
1790 				log->mega->actor_xyz.x = MS->hist_pin_x;
1791 				log->mega->actor_xyz.y = MS->hist_pin_y;
1792 				log->mega->actor_xyz.z = MS->hist_pin_z;
1793 				log->mega->on_stairs = FALSE8;
1794 				Set_player_status(STOOD);
1795 				return (__FINISHED_THIS_CYCLE);
1796 			}
1797 
1798 			step_sample_num--; // down
1799 
1800 			if ((stair_unit > 1) && (stair_unit < MS->stairs[stair_num].units - 1)) {
1801 				if ((cur_state.momentum == __STILL) || (cur_state.momentum == __BACKWARD_1)) {
1802 					if (left_right)
1803 						Still_start_new_mode(STOOD_ON_STAIRS, __WALK_DOWNSTAIRS_RIGHT_TO_STOOD_ON_STAIRS_FACING_DOWN);
1804 					else
1805 						Still_start_new_mode(STOOD_ON_STAIRS, __WALK_DOWNSTAIRS_LEFT_TO_STOOD_ON_STAIRS_FACING_DOWN);
1806 
1807 					return (__MORE_THIS_CYCLE);
1808 				} else if ((cur_state.turn != __NO_TURN) && ((stair_unit + 1) != MS->stairs[stair_num].units)) { // turn around
1809 					if (!left_right)
1810 						Hard_start_new_mode(REVERSE_ON_STAIRS, __WALK_DOWNSTAIRS_LEFT_TO_WALK_UPSTAIRS_RIGHT);
1811 					else
1812 						Hard_start_new_mode(REVERSE_ON_STAIRS, __WALK_DOWNSTAIRS_RIGHT_TO_WALK_UPSTAIRS_LEFT);
1813 
1814 					player_status = EASY_LINKING; // no first frame push, and no barrier checking
1815 
1816 					stair_dir = 1;
1817 					stair_unit = (uint8)((MS->stairs[stair_num].units - stair_unit) + 1);
1818 					return (__MORE_THIS_CYCLE);
1819 				}
1820 			}
1821 
1822 			if (left_right)
1823 				Easy_start_new_mode(ON_STAIRS, __WALK_DOWNSTAIRS_LEFT);
1824 			else
1825 				Easy_start_new_mode(ON_STAIRS, __WALK_DOWNSTAIRS_RIGHT);
1826 
1827 			left_right = (uint8)(1 - left_right); // toggle
1828 		}
1829 	}
1830 
1831 	was_climbing = TRUE8;
1832 	stair_unit++; // doing another
1833 	return (__MORE_THIS_CYCLE);
1834 }
1835 
Player_stood_on_stairs()1836 __mode_return _player::Player_stood_on_stairs() {
1837 	if (stair_dir) { // up
1838 		if ((cur_state.momentum != __STILL) && (cur_state.momentum != __BACKWARD_1)) {
1839 			stair_unit++; // doing another
1840 
1841 			if (left_right)
1842 				Easy_start_new_mode(ON_STAIRS, __WALK_UPSTAIRS_LEFT);
1843 			else
1844 				Easy_start_new_mode(ON_STAIRS, __WALK_UPSTAIRS_RIGHT);
1845 
1846 			left_right = (uint8)(1 - left_right); // toggle
1847 			return (__MORE_THIS_CYCLE);
1848 		} else if (cur_state.turn != __NO_TURN) { // turn around
1849 			if (!left_right)
1850 				Hard_start_new_mode(REVERSE_ON_STAIRS, __WALK_UPSTAIRS_LEFT_TO_WALK_DOWNSTAIRS_RIGHT);
1851 			else
1852 				Hard_start_new_mode(REVERSE_ON_STAIRS, __WALK_UPSTAIRS_RIGHT_TO_WALK_DOWNSTAIRS_LEFT);
1853 			player_status = EASY_LINKING; // no first frame push, and no barrier checking
1854 			stair_dir = 0;
1855 			stair_unit = (uint8)((MS->stairs[stair_num].units - stair_unit) + 1);
1856 			return (__MORE_THIS_CYCLE);
1857 		}
1858 
1859 	} else { // down
1860 		if ((cur_state.momentum != __STILL) && (cur_state.momentum != __BACKWARD_1)) {
1861 			stair_unit++; // doing another
1862 
1863 			if (left_right)
1864 				Easy_start_new_mode(ON_STAIRS, __WALK_DOWNSTAIRS_LEFT);
1865 			else
1866 				Easy_start_new_mode(ON_STAIRS, __WALK_DOWNSTAIRS_RIGHT);
1867 
1868 			left_right = (uint8)(1 - left_right); // toggle
1869 			return (__MORE_THIS_CYCLE);
1870 		} else if ((cur_state.turn != __NO_TURN) && ((stair_unit + 1) != MS->stairs[stair_num].units)) { // turn around
1871 			if (!left_right)
1872 				Hard_start_new_mode(REVERSE_ON_STAIRS, __WALK_DOWNSTAIRS_LEFT_TO_WALK_UPSTAIRS_RIGHT);
1873 			else
1874 				Hard_start_new_mode(REVERSE_ON_STAIRS, __WALK_DOWNSTAIRS_RIGHT_TO_WALK_UPSTAIRS_LEFT);
1875 			player_status = EASY_LINKING; // no first frame push, and no barrier checking
1876 			stair_dir = 1;
1877 			stair_unit = (uint8)((MS->stairs[stair_num].units - stair_unit) + 1);
1878 			return (__MORE_THIS_CYCLE);
1879 		}
1880 	}
1881 
1882 	return (__FINISHED_THIS_CYCLE);
1883 }
1884 
Leave_stair()1885 void _player::Leave_stair() {
1886 	// player is stepping off a ladder or stair
1887 
1888 	// align with floor
1889 	// set next mode according to momentum
1890 
1891 	MS->floor_def->Allign_with_floor(log->mega);
1892 
1893 	// coming off the stair
1894 	if (MS->stairs[stair_num].is_stair) {
1895 		if ((cur_state.momentum == __STILL) || (cur_state.momentum == __BACKWARD_1))
1896 			Soft_start_new_mode(WALKING, __WALK); // Soft_start_new_mode(STOOD, __WALK_TO_STAND);
1897 		else if (cur_state.momentum == __FORWARD_1)
1898 			Soft_start_new_mode(WALKING, __WALK);
1899 		else
1900 			Soft_start_new_mode(RUNNING, __RUN);
1901 	} else { // ladder
1902 		Set_player_status(STOOD);
1903 	}
1904 }
1905 
Add_to_interact_history()1906 void _player::Add_to_interact_history() {
1907 	// add current stair or ladder
1908 
1909 	// advance history
1910 	MS->cur_history++;
1911 	if (MS->cur_history == MAX_player_history)
1912 		MS->cur_history = 0; // wrap
1913 	// record it
1914 	MS->history[MS->cur_history].interaction = TRUE8;
1915 	MS->history[MS->cur_history].id = MS->stairs[stair_num].stair_id;
1916 	Tdebug("history.txt", "Stair [%s]", MS->objects->Fetch_items_name_by_number(MS->stairs[stair_num].stair_id));
1917 
1918 	MS->floor_def->Set_floor_rect_flag(log);
1919 	Tdebug("history.txt", "...%d", log->owner_floor_rect);
1920 }
1921 
Player_ladder()1922 __mode_return _player::Player_ladder() {
1923 	if (stair_dir) { // up
1924 
1925 		log->pan = MS->stairs[stair_num].pan_ref;
1926 
1927 		//		not our first step up
1928 		if (was_climbing)
1929 			log->mega->actor_xyz.y += (REAL_ONE * 24);
1930 
1931 		if (stair_unit == (MS->stairs[stair_num].units) - 5) {
1932 			if (begun_at_bottom) // began at bottom so write the history
1933 				Add_to_interact_history();
1934 
1935 			MS->camera_lock = TRUE8; // stop rough room cut through effect
1936 			Easy_start_new_mode(LEAVE_LADDER, __CLIMB_UP_LADDER_RIGHT_TO_STAND); // get off
1937 			return (__MORE_THIS_CYCLE);
1938 		} else {
1939 			//			still going, turning, stopping
1940 			if (cur_state.momentum == __STILL) { //||(cur_state.momentum==__BACKWARD_1))
1941 				was_climbing = 0;
1942 
1943 				if (left_right)
1944 					Set_to_first_frame(__CLIMB_UP_LADDER_LEFT); // still going
1945 				else
1946 					Set_to_first_frame(__CLIMB_UP_LADDER_RIGHT); // still going
1947 
1948 				return __FINISHED_THIS_CYCLE;
1949 			}
1950 			if (cur_state.momentum == __BACKWARD_1) { // pulling down
1951 				was_climbing = 0;
1952 				stair_dir = 0;
1953 				stair_unit = (uint8)((MS->stairs[stair_num].units - stair_unit));
1954 				left_right = (uint8)(1 - left_right); // toggle
1955 				return __MORE_THIS_CYCLE;
1956 			}
1957 			if (cur_state.momentum == __FORWARD_2) {
1958 				stair_unit = (uint8)((MS->stairs[stair_num].units - stair_unit));
1959 
1960 				if (!begun_at_bottom) // didnt begin at bottom so write the history
1961 					Add_to_interact_history();
1962 
1963 				Set_to_first_frame(__SLIDE_DOWN_LADDER); //
1964 				Set_player_status(SLIP_SLIDIN_AWAY);
1965 				return __MORE_THIS_CYCLE;
1966 			}
1967 
1968 			if (left_right)
1969 				Easy_start_new_mode(ON_LADDER, __CLIMB_UP_LADDER_LEFT); // still going
1970 			else
1971 				Easy_start_new_mode(ON_LADDER, __CLIMB_UP_LADDER_RIGHT); // still going
1972 
1973 			left_right = (uint8)(1 - left_right); // toggle
1974 		}
1975 
1976 	} else { // down
1977 
1978 		log->pan = MS->stairs[stair_num].pan_ref + HALF_TURN;
1979 		//		not our first step up
1980 		if (was_climbing)
1981 			log->mega->actor_xyz.y -= (REAL_ONE * 24);
1982 
1983 		if (stair_unit == (MS->stairs[stair_num].units + 0)) {
1984 			if (!begun_at_bottom) // didnt begin at bottom so write the history
1985 				Add_to_interact_history();
1986 
1987 			log->mega->actor_xyz.y -= (REAL_ONE * 24);
1988 			log->mega->drawShadow = TRUE8; // shadows om
1989 			Easy_start_new_mode(LEAVE_LADDER_BOTTOM, __CLIMB_DOWN_LADDER_RIGHT_TO_STAND); // get off
1990 			return (__MORE_THIS_CYCLE);
1991 		} else {
1992 			if (cur_state.momentum == __STILL) { //||(cur_state.momentum==__BACKWARD_1))
1993 				was_climbing = 0;
1994 
1995 				if (left_right)
1996 					Set_to_first_frame(__CLIMB_DOWN_LADDER_LEFT); // still going
1997 				else
1998 					Set_to_first_frame(__CLIMB_DOWN_LADDER_RIGHT); // still going
1999 
2000 				return __FINISHED_THIS_CYCLE;
2001 			}
2002 			if (cur_state.momentum == __FORWARD_1) { // pushing up
2003 				was_climbing = 0;
2004 				stair_dir = 1;
2005 				stair_unit = (uint8)((MS->stairs[stair_num].units - stair_unit));
2006 				left_right = (uint8)(1 - left_right); // toggle
2007 				return __MORE_THIS_CYCLE;
2008 			}
2009 			if (cur_state.IsButtonSet(__JOG)) {
2010 				if (!begun_at_bottom) // didnt begin at bottom so write the history
2011 					Add_to_interact_history();
2012 
2013 				log->pan = MS->stairs[stair_num].pan_ref; // if we are not traveling in the stairs original direction then we reverse the pan by 180deg
2014 				Set_to_first_frame(__SLIDE_DOWN_LADDER); //
2015 				Set_player_status(SLIP_SLIDIN_AWAY);
2016 				return __MORE_THIS_CYCLE;
2017 			}
2018 
2019 			if (left_right)
2020 				Easy_start_new_mode(ON_LADDER, __CLIMB_DOWN_LADDER_LEFT);
2021 			else
2022 				Easy_start_new_mode(ON_LADDER, __CLIMB_DOWN_LADDER_RIGHT);
2023 
2024 			left_right = (uint8)(1 - left_right); // toggle
2025 		}
2026 	}
2027 
2028 	log->mega->drawShadow = FALSE8; // shadows off
2029 	MS->camera_lock = FALSE8; // stop rough room cut through effect
2030 	was_climbing = TRUE8;
2031 	stair_unit++; // doing another
2032 	return (__MORE_THIS_CYCLE);
2033 }
2034 
Player_slide_on_ladder()2035 __mode_return _player::Player_slide_on_ladder() {
2036 	if (stair_unit == (MS->stairs[stair_num].units + 1)) {
2037 
2038 		MS->floor_def->Allign_with_floor(log->mega);
2039 
2040 		log->mega->drawShadow = TRUE8; // shadows on
2041 		Easy_start_new_mode(STOOD, __SLIDE_DOWN_LADDER_TO_STAND); // get off
2042 		return (__MORE_THIS_CYCLE);
2043 	}
2044 
2045 	log->mega->drawShadow = FALSE8; // shadows off
2046 	log->mega->actor_xyz.y -= (REAL_ONE * 24);
2047 	MS->camera_lock = FALSE8; // stop rough room cut through effect
2048 	stair_unit++; // doing another
2049 
2050 	return __FINISHED_THIS_CYCLE;
2051 }
2052 
Player_new_aim()2053 __mode_return _player::Player_new_aim() {
2054 	// this is the new aim mode where aim button must be held down to remain in the mode
2055 
2056 	// check if key released
2057 	if (!cur_state.IsButtonSet(__ARMUNARM)) { // let go of aim button
2058 
2059 		// g_oLineOfSight->SetFieldOfView( Fetch_player_id(), 90 );
2060 
2061 		Hard_start_reverse_new_mode(PUTTING_AWAY_GUN, __PULL_OUT_WEAPON);
2062 
2063 		return (__FINISHED_THIS_CYCLE);
2064 	}
2065 
2066 	// if we are newly armed then tell all the guards who may decide to react
2067 	if (log->cur_anim_type != __STAND)
2068 		MS->Signal_to_guards();
2069 
2070 	// must do this fist in-case coming from a link and diving straight out again
2071 	log->cur_anim_type = __STAND;
2072 	MS->Set_can_save(TRUE8); // can save
2073 
2074 	if ((cur_state.IsButtonSet(__INVENTORY)) && (!inv_lock)) {
2075 		if ((GetNoAmmoClips()) && (GetNoBullets() < (int32)GetBulletsPerClip())) {
2076 			inv_lock = TRUE8; // not auto-repeat
2077 
2078 			//			reload
2079 			UseAmmoClips(1); // use a clip
2080 
2081 			int32 bull_per_clip = GetBulletsPerClip();
2082 
2083 			SetBullets(bull_per_clip); // reload
2084 
2085 			Hard_start_new_mode(NEW_AIM, __LOAD_GUN);
2086 
2087 			return (__FINISHED_THIS_CYCLE);
2088 		}
2089 	} else {
2090 		// Stopped inventory dropping in repeatedly when you hold down the key.
2091 		if (!(cur_state.IsButtonSet(__INVENTORY))) {
2092 			inv_lock = FALSE8; // released
2093 		}
2094 	}
2095 
2096 	// check for
2097 	// forward step
2098 	// step backward?
2099 	if ((cur_state.momentum == __FORWARD_1) && (!forward_lock)) {
2100 		Hard_start_new_mode(NEW_AIM, __STEP_FORWARD);
2101 		player_status = GUN_LINKING;
2102 		return (__FINISHED_THIS_CYCLE);
2103 	} else if (cur_state.momentum == __STILL)
2104 		forward_lock = FALSE8;
2105 
2106 	// step backward?
2107 	if ((cur_state.momentum == __BACKWARD_1) && (backward_lock == FALSE8)) {
2108 		Hard_start_new_mode(NEW_AIM, __STEP_BACKWARD);
2109 		forward_lock = FALSE8; // release a lock caused by hitting a wall
2110 		return (__FINISHED_THIS_CYCLE);
2111 	}
2112 	// sidestep left?
2113 	if ((cur_state.IsButtonSet(__SIDESTEP)) && (cur_state.turn == __LEFT)) {
2114 		Hard_start_new_mode(NEW_AIM, __SIDESTEP_LEFT);
2115 		forward_lock = FALSE8; // release a lock caused by hitting a wall
2116 		backward_lock = FALSE8; // release a lock caused by hitting a wall
2117 		return (__FINISHED_THIS_CYCLE);
2118 	} else if ((cur_state.IsButtonSet(__SIDESTEP)) && (cur_state.turn == __RIGHT)) {
2119 		Hard_start_reverse_new_mode(NEW_AIM, __SIDESTEP_LEFT);
2120 		forward_lock = FALSE8; // release a lock caused by hitting a wall
2121 		backward_lock = FALSE8; // release a lock caused by hitting a wall
2122 		return (__FINISHED_THIS_CYCLE);
2123 	}
2124 
2125 	// are we turning on the spot
2126 	if (cur_state.turn == __LEFT) {
2127 		//  animate if frames present
2128 		if (log->voxel_info->IsAnimTable(__TURN_ON_THE_SPOT_CLOCKWISE)) {
2129 
2130 			log->cur_anim_type = __TURN_ON_THE_SPOT_CLOCKWISE;
2131 			Reverse_frame_motion_and_pan(__TURN_ON_THE_SPOT_CLOCKWISE);
2132 			log->pan += aim_turn_amount;
2133 
2134 			forward_lock = FALSE8; // release a lock caused by hitting a wall
2135 		}
2136 	} else if (cur_state.turn == __RIGHT) {
2137 		//		animate if frames present
2138 		if (log->voxel_info->IsAnimTable(__TURN_ON_THE_SPOT_CLOCKWISE)) {
2139 			log->cur_anim_type = __TURN_ON_THE_SPOT_CLOCKWISE;
2140 			Advance_frame_motion_and_pan(__TURN_ON_THE_SPOT_CLOCKWISE);
2141 			log->pan -= aim_turn_amount;
2142 
2143 			forward_lock = FALSE8; // release a lock caused by hitting a wall
2144 		}
2145 	} else if (cur_state.IsButtonSet(__CROUCH)) { // crouch down
2146 		MS->Set_pose(__CROUCH_GUN);
2147 		MS->Change_pose_in_current_anim_set();
2148 		Hard_start_reverse_new_mode(CROUCH_AIM, __STAND_CROUCHED_TO_STAND);
2149 		return (__FINISHED_THIS_CYCLE);
2150 	} else {
2151 		log->anim_pc = 0; // just stood
2152 
2153 		__mode_return ret;
2154 		ret = Player_press_remora_button();
2155 		if (ret == __FINISHED_THIS_CYCLE)
2156 			return (ret); //
2157 	}
2158 
2159 	return (__FINISHED_THIS_CYCLE);
2160 }
2161 
Player_crouch_aim()2162 __mode_return _player::Player_crouch_aim() {
2163 	// this is the new aim mode where aim button must be held down to remain in the mode
2164 
2165 	// check if key released
2166 	if (!cur_state.IsButtonSet(__ARMUNARM)) { // let go of aim button
2167 		Hard_start_reverse_new_mode(PUTTING_AWAY_CROUCH_GUN, __PULL_OUT_WEAPON);
2168 
2169 		return (__FINISHED_THIS_CYCLE);
2170 	}
2171 
2172 	// must do this fist in-case coming from a link and diving straight out again
2173 	log->cur_anim_type = __STAND;
2174 	MS->Set_can_save(TRUE8); // can save
2175 
2176 	if ((cur_state.IsButtonSet(__INVENTORY)) && (!inv_lock)) {
2177 		if ((GetNoAmmoClips()) && (GetNoBullets() < (int32)GetBulletsPerClip())) {
2178 			inv_lock = TRUE8; // not auto-repeat
2179 
2180 			//			reload
2181 			UseAmmoClips(1); // use a clip
2182 
2183 			int32 bull_per_clip = GetBulletsPerClip();
2184 
2185 			SetBullets(bull_per_clip); // reload
2186 
2187 			Hard_start_new_mode(CROUCH_AIM, __LOAD_GUN);
2188 
2189 			return (__FINISHED_THIS_CYCLE);
2190 		}
2191 	} else {
2192 		// Stopped inventory dropping in repeatedly when you hold down the key.
2193 		if (!(cur_state.IsButtonSet(__INVENTORY))) {
2194 			inv_lock = FALSE8; // released
2195 		}
2196 	}
2197 
2198 	// check for
2199 	// forward step
2200 	// step backward?
2201 	if ((cur_state.momentum == __FORWARD_1) && (!forward_lock)) {
2202 		Hard_start_new_mode(CROUCH_AIM, __STEP_FORWARD);
2203 		player_status = GUN_LINKING;
2204 		return (__FINISHED_THIS_CYCLE);
2205 	} else if (cur_state.momentum == __STILL)
2206 		forward_lock = FALSE8;
2207 
2208 	// step backward?
2209 	if ((cur_state.momentum == __BACKWARD_1) && (backward_lock == FALSE8)) {
2210 		Hard_start_new_mode(CROUCH_AIM, __STEP_BACKWARD);
2211 		forward_lock = FALSE8; // release a lock caused by hitting a wall
2212 		return (__FINISHED_THIS_CYCLE);
2213 	}
2214 	// sidestep left?
2215 	if ((cur_state.IsButtonSet(__SIDESTEP)) && (cur_state.turn == __LEFT)) {
2216 		Hard_start_new_mode(CROUCH_AIM, __SIDESTEP_LEFT);
2217 		forward_lock = FALSE8; // release a lock caused by hitting a wall
2218 		backward_lock = FALSE8; // release a lock caused by hitting a wall
2219 		return (__FINISHED_THIS_CYCLE);
2220 	} else if ((cur_state.IsButtonSet(__SIDESTEP)) && (cur_state.turn == __RIGHT)) {
2221 		Hard_start_reverse_new_mode(CROUCH_AIM, __SIDESTEP_LEFT);
2222 		forward_lock = FALSE8; // release a lock caused by hitting a wall
2223 		backward_lock = FALSE8; // release a lock caused by hitting a wall
2224 		return (__FINISHED_THIS_CYCLE);
2225 	}
2226 
2227 	// are we turning on the spot
2228 	if (cur_state.turn == __LEFT) {
2229 		//  animate if frames present
2230 		if (log->voxel_info->IsAnimTable(__TURN_ON_THE_SPOT_CLOCKWISE)) {
2231 			//			ok, frames are present so we can do this thing
2232 			//			set type for stageDraw
2233 
2234 			log->cur_anim_type = __TURN_ON_THE_SPOT_CLOCKWISE;
2235 			Reverse_frame_motion_and_pan(__TURN_ON_THE_SPOT_CLOCKWISE);
2236 			log->pan += aim_turn_amount;
2237 			forward_lock = FALSE8; // release a lock caused by hitting a wall
2238 		}
2239 	} else if (cur_state.turn == __RIGHT) {
2240 		//		animate if frames present
2241 		if (log->voxel_info->IsAnimTable(__TURN_ON_THE_SPOT_CLOCKWISE)) {
2242 			//			ok, frames are present so we can do this thing
2243 			//			set type for stageDraw
2244 
2245 			log->cur_anim_type = __TURN_ON_THE_SPOT_CLOCKWISE;
2246 			Advance_frame_motion_and_pan(__TURN_ON_THE_SPOT_CLOCKWISE);
2247 			log->pan -= aim_turn_amount;
2248 			forward_lock = FALSE8; // release a lock caused by hitting a wall
2249 		}
2250 	} else if (!cur_state.IsButtonSet(__CROUCH)) { // crouch down
2251 		Hard_start_new_mode(CROUCH_TO_STAND_ARMED, __STAND_CROUCHED_TO_STAND);
2252 		return (__FINISHED_THIS_CYCLE);
2253 	} else {
2254 		log->anim_pc = 0; // just stood
2255 
2256 		__mode_return ret;
2257 		ret = Player_press_remora_button();
2258 		if (ret == __FINISHED_THIS_CYCLE)
2259 			return (ret); //
2260 	}
2261 
2262 	return (__FINISHED_THIS_CYCLE);
2263 }
2264 
Player_crouching()2265 __mode_return _player::Player_crouching() {
2266 	// must do this fist in-case coming from a link and diving straight out again
2267 	log->cur_anim_type = __STAND;
2268 	MS->Set_can_save(TRUE8); // can save
2269 
2270 	MS->Process_guard_alert(__ASTOOD);
2271 
2272 	if (log->mega->Fetch_armed_status()) {
2273 		MS->Set_pose(__CROUCH_NOT_ARMED);
2274 		MS->Change_pose_in_current_anim_set();
2275 		Message_box("just caught crouching player in armed set!");
2276 	}
2277 
2278 	if (!cur_state.IsButtonSet(__CROUCH)) { // crouch down
2279 		Still_start_new_mode(CROUCH_TO_STAND_UNARMED, __STAND_CROUCHED_TO_STAND);
2280 		return (__FINISHED_THIS_CYCLE);
2281 	}
2282 
2283 	// starting to walk again?
2284 	if ((!forward_lock) && (cur_state.momentum == __FORWARD_1)) {
2285 		Start_new_mode(CROUCH_WALK /*__STAND_TO_WALK*/);
2286 
2287 		return (__FINISHED_THIS_CYCLE);
2288 	} else if (cur_state.momentum == __STILL)
2289 		forward_lock = FALSE8;
2290 
2291 	// step backward?
2292 	if ((cur_state.momentum == __BACKWARD_1) && (backward_lock == FALSE8)) {
2293 		Hard_start_new_mode(CROUCHING, __STEP_BACKWARD);
2294 		forward_lock = FALSE8; // release a lock caused by hitting a wall
2295 		return (__FINISHED_THIS_CYCLE);
2296 	}
2297 
2298 	// are we turning on the spot
2299 	if (cur_state.turn == __LEFT) {
2300 		//		animate if frames present
2301 		if (log->voxel_info->IsAnimTable(__TURN_ON_THE_SPOT_CLOCKWISE)) {
2302 			log->cur_anim_type = __TURN_ON_THE_SPOT_CLOCKWISE; // set type for stageDraw
2303 
2304 			Reverse_frame_motion_and_pan(__TURN_ON_THE_SPOT_CLOCKWISE);
2305 
2306 			log->pan += crouch_turn_amount;
2307 			forward_lock = FALSE8; // release a lock caused by hitting a wall
2308 		}
2309 	} else if (cur_state.turn == __RIGHT) {
2310 		//		animate if frames present
2311 		if (log->voxel_info->IsAnimTable(__TURN_ON_THE_SPOT_CLOCKWISE)) { // ok, frames are present so we can do this thing
2312 			log->cur_anim_type = __TURN_ON_THE_SPOT_CLOCKWISE; // set type for stageDraw
2313 			Advance_frame_motion_and_pan(__TURN_ON_THE_SPOT_CLOCKWISE);
2314 			log->pan -= crouch_turn_amount;
2315 			forward_lock = FALSE8; // release a lock caused by hitting a wall
2316 		}
2317 	} else if ((has_weapon) && (cur_state.IsButtonSet(__ARMUNARM))) { // pull gun
2318 
2319 		MS->Set_pose(__CROUCH_GUN);
2320 		MS->Change_pose_in_current_anim_set();
2321 
2322 		if (armedChangesMode == 1)
2323 			Push_control_mode(ACTOR_RELATIVE);
2324 
2325 		Hard_start_new_mode(CROUCH_AIM, __PULL_OUT_WEAPON);
2326 
2327 		return (__FINISHED_THIS_CYCLE);
2328 
2329 	} else {
2330 		log->anim_pc = 0; // in-case stopping turning
2331 
2332 		__mode_return ret = Player_press_inv_button();
2333 		if (ret == __FINISHED_THIS_CYCLE)
2334 			return (ret); //
2335 
2336 		ret = Player_press_remora_button();
2337 		if (ret == __FINISHED_THIS_CYCLE)
2338 			return (ret); //
2339 	}
2340 
2341 	return (__FINISHED_THIS_CYCLE);
2342 }
2343 
Player_stood()2344 __mode_return _player::Player_stood() {
2345 
2346 	walk_count = 0; // reset walk count
2347 
2348 	// must do this fist in-case coming from a link and diving straight out again
2349 	log->cur_anim_type = __STAND;
2350 	MS->Set_motion(__MOTION_WALK); // back to walk in-case were running
2351 	MS->Set_can_save(TRUE8); // can save
2352 	MS->floor_def->Allign_with_floor(log->mega);
2353 
2354 	MS->Process_guard_alert(__ASTOOD);
2355 
2356 	//	check for new parent box and if so bring barriers
2357 	MS->Prepare_megas_route_barriers(TRUE8);
2358 
2359 	// attempt to catch the armed set when not really bug
2360 
2361 	if (log->mega->Fetch_armed_status()) {
2362 		MS->Set_pose(__NOT_ARMED);
2363 		MS->Change_pose_in_current_anim_set();
2364 		Message_box("just caught player in armed set!");
2365 	}
2366 
2367 	// starting to walk again?
2368 	if ((!forward_lock) && (cur_state.momentum == __FORWARD_1)) {
2369 		Hard_start_new_mode(WALKING, __STAND_TO_WALK);
2370 
2371 		return (__FINISHED_THIS_CYCLE);
2372 	} else if (cur_state.momentum == __STILL)
2373 		forward_lock = FALSE8;
2374 
2375 	// step backward?
2376 	if ((cur_state.momentum == __BACKWARD_1) && (backward_lock == FALSE8)) {
2377 		Hard_start_new_mode(STOOD, __STEP_BACKWARD);
2378 		forward_lock = FALSE8; // release a lock caused by hitting a wall
2379 		return (__FINISHED_THIS_CYCLE);
2380 	}
2381 
2382 	// sidestep left?
2383 	if ((cur_state.IsButtonSet(__SIDESTEP)) && (cur_state.turn == __LEFT)) {
2384 		Hard_start_new_mode(STOOD, __SIDESTEP_LEFT);
2385 		forward_lock = FALSE8; // release a lock caused by hitting a wall
2386 		backward_lock = FALSE8; // release a lock caused by hitting a wall
2387 		return (__FINISHED_THIS_CYCLE);
2388 	} else if ((cur_state.IsButtonSet(__SIDESTEP)) && (cur_state.turn == __RIGHT)) {
2389 		Hard_start_reverse_new_mode(STOOD, __SIDESTEP_LEFT);
2390 		forward_lock = FALSE8; // release a lock caused by hitting a wall
2391 		backward_lock = FALSE8; // release a lock caused by hitting a wall
2392 		return (__FINISHED_THIS_CYCLE);
2393 	}
2394 
2395 	// are we turning on the spot
2396 	if ((cur_state.turn == __LEFT) && (log->voxel_info->IsAnimTable(__TURN_ON_THE_SPOT_CLOCKWISE))) { // animate if frames present
2397 		log->cur_anim_type = __TURN_ON_THE_SPOT_CLOCKWISE; // set type for stageDraw
2398 		Reverse_frame_motion_and_pan(__TURN_ON_THE_SPOT_CLOCKWISE);
2399 
2400 		if (player_status != STOOD)
2401 			return __FINISHED_THIS_CYCLE; // got on a ladder?
2402 
2403 		log->pan += stood_turn_amount;
2404 		forward_lock = FALSE8; // release a lock caused by hitting a wall
2405 	} else if ((cur_state.turn == __RIGHT) && (log->voxel_info->IsAnimTable(__TURN_ON_THE_SPOT_CLOCKWISE))) { // animate if frames present
2406 		log->cur_anim_type = __TURN_ON_THE_SPOT_CLOCKWISE; // set type for stageDraw
2407 		Advance_frame_motion_and_pan(__TURN_ON_THE_SPOT_CLOCKWISE);
2408 
2409 		if (player_status != STOOD)
2410 			return __FINISHED_THIS_CYCLE; // got on a ladder?
2411 
2412 		log->pan -= stood_turn_amount;
2413 		forward_lock = FALSE8; // release a lock caused by hitting a wall
2414 	} else if ((cur_state.turn == __HARD_LEFT) && (log->voxel_info->IsAnimTable(__TURN_ON_THE_SPOT_CLOCKWISE))) { // animate if frames present
2415 		log->cur_anim_type = __TURN_ON_THE_SPOT_CLOCKWISE; // set type for stageDraw
2416 		Reverse_frame_motion_and_pan(__TURN_ON_THE_SPOT_CLOCKWISE);
2417 
2418 		if (player_status != STOOD)
2419 			return __FINISHED_THIS_CYCLE; // got on a ladder?
2420 
2421 		log->pan += stood_fast_turn_amount;
2422 		forward_lock = FALSE8; // release a lock caused by hitting a wall
2423 	} else if ((cur_state.turn == __HARD_RIGHT) && (log->voxel_info->IsAnimTable(__TURN_ON_THE_SPOT_CLOCKWISE))) { // animate if frames present
2424 		log->cur_anim_type = __TURN_ON_THE_SPOT_CLOCKWISE; // set type for stageDraw
2425 		Advance_frame_motion_and_pan(__TURN_ON_THE_SPOT_CLOCKWISE);
2426 
2427 		if (player_status != STOOD)
2428 			return __FINISHED_THIS_CYCLE; // got on a ladder?
2429 
2430 		log->pan -= stood_fast_turn_amount;
2431 		forward_lock = FALSE8; // release a lock caused by hitting a wall
2432 	}
2433 
2434 	else if ((has_weapon) && (cur_state.IsButtonSet(__ARMUNARM))) { // pull gun
2435 
2436 		MS->Set_pose(__GUN);
2437 		MS->Change_pose_in_current_anim_set();
2438 
2439 		if (armedChangesMode == 1)
2440 			Push_control_mode(ACTOR_RELATIVE);
2441 
2442 		Hard_start_new_mode(NEW_AIM, __PULL_OUT_WEAPON);
2443 
2444 		return (__FINISHED_THIS_CYCLE);
2445 	} else if (cur_state.IsButtonSet(__CROUCH)) { // crouch down
2446 		MS->Set_pose(__CROUCH_NOT_ARMED);
2447 		MS->Change_pose_in_current_anim_set();
2448 		Still_reverse_start_new_mode(CROUCHING, __STAND_CROUCHED_TO_STAND);
2449 		return (__FINISHED_THIS_CYCLE);
2450 	}
2451 
2452 	else {
2453 		log->anim_pc = 0; // in-case stopping turning
2454 
2455 		__mode_return ret = Player_press_inv_button();
2456 		if (ret == __FINISHED_THIS_CYCLE)
2457 			return (ret); //
2458 
2459 		ret = Player_press_remora_button();
2460 		if (ret == __FINISHED_THIS_CYCLE)
2461 			return (ret);
2462 	}
2463 
2464 	return (__FINISHED_THIS_CYCLE);
2465 }
2466 
Player_crouch_walk()2467 __mode_return _player::Player_crouch_walk() {
2468 	// player is crouching and walking
2469 	// see what happens this cycle
2470 
2471 	bool8 ret;
2472 
2473 	// uncrouch when walking
2474 	if (!cur_state.IsButtonSet(__CROUCH)) { // crouch down
2475 		Hard_start_new_mode(CROUCH_TO_STAND_UNARMED, __STAND_CROUCHED_TO_STAND);
2476 		return (__FINISHED_THIS_CYCLE);
2477 	}
2478 
2479 	// set anim set
2480 	log->cur_anim_type = __WALK;
2481 	MS->Set_motion(__MOTION_WALK); // high level
2482 	MS->Set_can_save(TRUE8); // can save
2483 	MS->Process_guard_alert(__ASTOOD);
2484 
2485 	// is the player still moving forward?
2486 	if (cur_state.momentum == __FORWARD_1) {
2487 		if (cur_state.turn == __LEFT) {
2488 			log->pan += walk_turn_amount;
2489 			if (log->pan >= HALF_TURN)
2490 				log->pan -= FULL_TURN;
2491 		}
2492 
2493 		else if (cur_state.turn == __RIGHT) {
2494 			log->pan -= walk_turn_amount;
2495 			if (log->pan <= -HALF_TURN)
2496 				log->pan += FULL_TURN;
2497 		}
2498 
2499 		// shift character and frame forward by the amount appropriate
2500 
2501 		ret = MS->Advance_frame_and_motion(__WALK, TRUE8, 1);
2502 		MS->Normalise_anim_pc();
2503 
2504 		if (!ret) {
2505 			//			could not walk forward
2506 
2507 			forward_lock = TRUE8;
2508 
2509 			Start_new_mode(CROUCHING);
2510 
2511 			return (__FINISHED_THIS_CYCLE);
2512 		}
2513 
2514 		if (cur_state.IsButtonSet(__ARMUNARM)) { // pull gun
2515 			forward_lock = TRUE8;
2516 
2517 			MS->Set_pose(__CROUCH_GUN);
2518 			MS->Change_pose_in_current_anim_set();
2519 			if (armedChangesMode == 1)
2520 				Push_control_mode(ACTOR_RELATIVE);
2521 			Hard_start_new_mode(CROUCH_AIM, __WALK_TO_PULL_OUT_WEAPON);
2522 
2523 			return (__FINISHED_THIS_CYCLE);
2524 		}
2525 
2526 		// enough for now
2527 		return (__FINISHED_THIS_CYCLE);
2528 	}
2529 
2530 	Start_new_mode(CROUCHING);
2531 
2532 	return (__FINISHED_THIS_CYCLE);
2533 }
2534 
Player_walking()2535 __mode_return _player::Player_walking() {
2536 	// player is walking
2537 	// see what happens this cycle
2538 
2539 	// we have rotate left/right and forward
2540 
2541 	// keys same as last go?
2542 
2543 	bool8 ret;
2544 
2545 	if (log->mega->Fetch_armed_status()) {
2546 		MS->Set_pose(__NOT_ARMED);
2547 		MS->Change_pose_in_current_anim_set();
2548 		Message_box("player_walking  - just caught player in armed set!");
2549 	}
2550 
2551 	walk_count++; // up the walk count
2552 	MS->Process_guard_alert(__AWALKING);
2553 
2554 	// set anim set
2555 	log->cur_anim_type = __WALK;
2556 	MS->Set_motion(__MOTION_WALK); // high level
2557 	MS->Set_can_save(TRUE8); // can save
2558 
2559 	// arm?
2560 	if ((has_weapon) && (cur_state.IsButtonSet(__ARMUNARM))) { // pull gun
2561 		MS->Reset_guard_alert();
2562 		forward_lock = TRUE8;
2563 		MS->Set_pose(__GUN);
2564 		MS->Change_pose_in_current_anim_set();
2565 		if (armedChangesMode == 1)
2566 			Push_control_mode(ACTOR_RELATIVE);
2567 		Soft_start_new_mode(NEW_AIM, __WALK_TO_PULL_OUT_WEAPON);
2568 		return (__FINISHED_THIS_CYCLE);
2569 	}
2570 
2571 	if (cur_state.IsButtonSet(__CROUCH)) { // crouch down
2572 		MS->Reset_guard_alert();
2573 		walk_count = 0; // cancel walk count
2574 		MS->Set_pose(__CROUCH_NOT_ARMED);
2575 		MS->Change_pose_in_current_anim_set();
2576 		Hard_start_reverse_new_mode(CROUCH_WALK, __STAND_CROUCHED_TO_STAND);
2577 		return (__FINISHED_THIS_CYCLE);
2578 	}
2579 
2580 	// is the player still moving forward?
2581 	if (cur_state.momentum == __FORWARD_1) {
2582 
2583 		if (cur_state.turn == __LEFT) {
2584 			log->pan += walk_turn_amount;
2585 			if (log->pan >= HALF_TURN)
2586 				log->pan -= FULL_TURN;
2587 		}
2588 
2589 		else if (cur_state.turn == __RIGHT) {
2590 			log->pan -= walk_turn_amount;
2591 			if (log->pan <= -HALF_TURN)
2592 				log->pan += FULL_TURN;
2593 		}
2594 
2595 		//		shift character and frame forward by the amount appropriate
2596 		ret = MS->Advance_frame_and_motion(__WALK, TRUE8, 1);
2597 		MS->Normalise_anim_pc();
2598 
2599 		if (!ret) {
2600 			//			could not walk forward
2601 
2602 			forward_lock = TRUE8;
2603 
2604 			Soft_start_new_mode(STOOD, __STEP_BACKWARD_TO_STAND, __STEP_BACKWARD_TO_OTHER_STAND_LEFT);
2605 
2606 			return (__FINISHED_THIS_CYCLE);
2607 		}
2608 
2609 		// enough for now
2610 		return (__FINISHED_THIS_CYCLE);
2611 	} else if (cur_state.momentum == __FORWARD_2) { // run
2612 		//		break into a run
2613 
2614 		Start_new_mode(RUNNING); //, __WALK_TO_STAND, __WALK_TO_OTHER_STAND_LEFT_LEG);
2615 
2616 		return (__MORE_THIS_CYCLE);
2617 	}
2618 
2619 	// otherwise, we must be stopping
2620 	MS->Reset_guard_alert();
2621 	Soft_start_new_mode(STOOD, __WALK_TO_STAND, __WALK_TO_OTHER_STAND_LEFT_LEG);
2622 
2623 	return (__FINISHED_THIS_CYCLE);
2624 }
2625 
Player_running()2626 __mode_return _player::Player_running() {
2627 	// player is running
2628 	// see what happens this cycle
2629 
2630 	// we have rotate left/right and forward
2631 
2632 	// keys same as last go?
2633 
2634 	bool8 ret;
2635 
2636 	if (log->mega->Fetch_armed_status()) {
2637 		MS->Set_pose(__NOT_ARMED);
2638 		MS->Change_pose_in_current_anim_set();
2639 		Message_box("player_running  - just caught player in armed set!");
2640 	}
2641 
2642 	MS->Process_guard_alert(__ARUNNING);
2643 
2644 	// set anim set
2645 	log->cur_anim_type = __RUN;
2646 	MS->Set_motion(__MOTION_RUN); // wtf is this for?
2647 	MS->Set_can_save(TRUE8); // can save
2648 
2649 	// arm?
2650 	if ((has_weapon) && (cur_state.IsButtonSet(__ARMUNARM))) { // pull gun
2651 		MS->Reset_guard_alert();
2652 		forward_lock = TRUE8;
2653 		MS->Set_pose(__GUN);
2654 		MS->Change_pose_in_current_anim_set();
2655 		if (armedChangesMode == 1)
2656 			Push_control_mode(ACTOR_RELATIVE);
2657 		Soft_start_new_mode(NEW_AIM, __RUN_TO_PULL_OUT_WEAPON);
2658 		return (__FINISHED_THIS_CYCLE);
2659 	}
2660 
2661 	// is the player still moving forward?
2662 	if (cur_state.momentum == __FORWARD_2) {
2663 
2664 		if (cur_state.turn == __LEFT) {
2665 			log->pan += run_turn_amount;
2666 			if (log->pan >= HALF_TURN)
2667 				log->pan -= FULL_TURN;
2668 		}
2669 
2670 		else if (cur_state.turn == __RIGHT) {
2671 			log->pan -= run_turn_amount;
2672 			if (log->pan <= -HALF_TURN)
2673 				log->pan += FULL_TURN;
2674 		}
2675 
2676 		// shift character and frame forward by the amount appropriate
2677 		ret = MS->Advance_frame_and_motion(__RUN, TRUE8, 1);
2678 		MS->Normalise_anim_pc();
2679 
2680 		if (!ret) {
2681 			//			could not run forward
2682 
2683 			forward_lock = TRUE8;
2684 
2685 			Soft_start_new_mode(STOOD, __STEP_BACKWARD_TO_STAND, __STEP_BACKWARD_TO_OTHER_STAND_LEFT);
2686 
2687 			return (__FINISHED_THIS_CYCLE);
2688 		}
2689 
2690 		// enough for now
2691 		return (__FINISHED_THIS_CYCLE);
2692 	} else if (cur_state.momentum == __FORWARD_1) { // walk
2693 		//		break into a walk
2694 
2695 		Soft_start_new_mode_no_link(WALKING, __WALK); //, __WALK_TO_STAND, __WALK_TO_OTHER_STAND_LEFT_LEG);
2696 
2697 		return (__FINISHED_THIS_CYCLE);
2698 	}
2699 
2700 	// otherwise, we must be stopping
2701 	MS->Reset_guard_alert();
2702 	Hard_start_new_mode(STOOD, __RUN_TO_STAND);
2703 	log->anim_pc = 4; // TOTAL BODGE TO CHOP OFF INITIAL FRAMES THAT PROPEL THE CHARACTER FORWARD IN UNNATURAL MANNER
2704 
2705 	return (__FINISHED_THIS_CYCLE);
2706 }
2707 
Advance_frame_motion_and_pan(__mega_set_names anim_type)2708 bool8 _player::Advance_frame_motion_and_pan(__mega_set_names anim_type) {
2709 	// attempts to move the frame forward and move the character
2710 	// returns fail and frame is not changed if the way forward is blocked by a barrier
2711 	// the frame counter will be looped
2712 	__barrier_result ret;
2713 	PXreal xnext, znext;
2714 	PXreal x, z;
2715 
2716 	// get anim set
2717 	PXanim *pAnim = (PXanim *)rs_anims->Res_open(log->voxel_info->get_info_name(anim_type), log->voxel_info->info_name_hash[anim_type], log->voxel_info->base_path,
2718 	                                             log->voxel_info->base_path_hash); //
2719 
2720 	if (log->anim_pc + 1 >= pAnim->frame_qty)
2721 		Fatal_error("Advance_frame_motion_and_pan finds [%s] has illegal frame in anim [%s] %d %d", (const char *)log->GetName(),
2722 		            (const char *)log->voxel_info->get_info_name(anim_type), log->anim_pc, pAnim->frame_qty);
2723 
2724 	// get pan of previous frame and next frame so we can advance the engine pan by the difference
2725 	// update engine pan
2726 	PXreal pan1, pan2;
2727 
2728 	// Get the next frame from the anim
2729 	PXframe *nextFrame = PXFrameEnOfAnim(log->anim_pc + 1, pAnim);
2730 	// Get the current frame from the anim
2731 	PXframe *currentFrame = PXFrameEnOfAnim(log->anim_pc, pAnim);
2732 
2733 	nextFrame->markers[ORG_POS].GetPan(&pan1);
2734 	currentFrame->markers[ORG_POS].GetPan(&pan2);
2735 
2736 	log->pan += (pan1 - pan2); // update by difference
2737 
2738 	// get motion displacement from currently displayed frame to next one
2739 	// note that we always read frame+1 for motion of next frame even though the voxel frame itself will be looped back to 0
2740 	PXreal x1, x2, z1, z2, unused;
2741 	nextFrame->markers[ORG_POS].GetXYZ(&x1, &unused, &z1);
2742 	currentFrame->markers[ORG_POS].GetXYZ(&x2, &unused, &z2);
2743 
2744 	xnext = x1 - x2;
2745 	znext = z1 - z2;
2746 
2747 	// update pc
2748 	log->anim_pc = (log->anim_pc + 1) % (pAnim->frame_qty - 1);
2749 
2750 	// get the pan unwind value of the frame to be printed
2751 	PXreal pan;
2752 	PXFrameEnOfAnim(log->anim_pc, pAnim)->markers[ORG_POS].GetPan(&pan);
2753 	log->pan_adjust = pan; // this value will be unwound from the orientation of the frame at render time in stage draw
2754 
2755 	// calculate the new x and z coordinate from this frames motion offset
2756 	// do the z and x together
2757 
2758 	PXfloat ang = (log->pan - log->pan_adjust) * TWO_PI;
2759 	PXfloat cang = (PXfloat)PXcos(ang);
2760 	PXfloat sang = (PXfloat)PXsin(ang);
2761 
2762 	x = log->mega->actor_xyz.x + PXfloat2PXreal(xnext * cang + znext * sang);
2763 	z = log->mega->actor_xyz.z + PXfloat2PXreal(znext * cang - xnext * sang);
2764 	//	x and z are the new coordinates
2765 
2766 	PXfloat safe_pan = log->pan; // save the pan
2767 
2768 	// ok, check for a new collision with a barrier
2769 	ret = MS->Check_barrier_bump_and_bounce(x, log->mega->actor_xyz.y, z,                                           // new position
2770 	                                        log->mega->actor_xyz.x, log->mega->actor_xyz.y, log->mega->actor_xyz.z, // old position
2771 	                                        TRUE8);
2772 
2773 	if (ret == __NUDGED)
2774 		return TRUE8; // on ladder?
2775 
2776 	//	did we move forward without a problem?
2777 	if (ret == __OK) {
2778 		//		record the new true actor position
2779 		log->mega->actor_xyz.x = x;
2780 		log->mega->actor_xyz.z = z;
2781 
2782 		//		check for new parent box and if so bring barriers
2783 		MS->Prepare_megas_route_barriers(TRUE8);
2784 
2785 	} else {
2786 		log->pan = safe_pan; // we bounced so cancel the pan correction that will have been done
2787 	}
2788 
2789 	CORRECT_PAN // stop the wrap
2790 
2791 	    return (TRUE8);
2792 }
2793 
Reverse_frame_motion_and_pan(__mega_set_names anim_type)2794 bool8 _player::Reverse_frame_motion_and_pan(__mega_set_names anim_type) {
2795 	// frames go backward
2796 	// each frame projects its motion in the normal manner, but, obviously, the effect is of the anim moving backward
2797 
2798 	// the frame counter will be looped
2799 
2800 	PXreal xnext, znext;
2801 	PXreal x, z;
2802 	uint32 next_pc;
2803 	__barrier_result ret;
2804 
2805 	// get anim set
2806 	PXanim *pAnim = (PXanim *)rs_anims->Res_open(log->voxel_info->get_info_name(anim_type), log->voxel_info->info_name_hash[anim_type], log->voxel_info->base_path,
2807 	                                             log->voxel_info->base_path_hash); //
2808 
2809 	// if we are on frame 0 then shift up to pretend we're coming in off the dummy frame
2810 	if (!log->anim_pc) {
2811 		next_pc = pAnim->frame_qty - 2;
2812 		log->anim_pc = pAnim->frame_qty - 1;
2813 	} else
2814 		next_pc = (log->anim_pc - 1) % (pAnim->frame_qty - 1); // next_pc=log->anim_pc-1;
2815 
2816 	if ((next_pc >= pAnim->frame_qty) || (log->anim_pc >= pAnim->frame_qty))
2817 		Fatal_error("Reverse_frame_motion_and_pan finds [%s] has illegal frame in anim [%s] %d %d %d", (const char *)log->GetName(),
2818 		            (const char *)log->voxel_info->get_info_name(anim_type), next_pc, log->anim_pc, pAnim->frame_qty);
2819 
2820 	// get pan of previous frame and next frame so we can advance the engine pan by the difference
2821 	// update engine pan
2822 	PXreal pan1, pan2;
2823 
2824 	// Get the next frame from the anim
2825 	PXframe *nextFrame = PXFrameEnOfAnim(next_pc, pAnim);
2826 	// Get the current frame from the anim
2827 	PXframe *currentFrame = PXFrameEnOfAnim(log->anim_pc, pAnim);
2828 
2829 	nextFrame->markers[ORG_POS].GetPan(&pan1);
2830 	currentFrame->markers[ORG_POS].GetPan(&pan2);
2831 
2832 	log->pan += (pan1 - pan2); // update by difference
2833 
2834 	// get motion displacement from currently displayed frame to next one
2835 	// note that we always read frame+1 for motion of next frame even though the voxel frame itself will be looped back to 0
2836 	PXreal x1, x2, z1, z2, unused;
2837 	nextFrame->markers[ORG_POS].GetXYZ(&x1, &unused, &z1);
2838 	currentFrame->markers[ORG_POS].GetXYZ(&x2, &unused, &z2);
2839 
2840 	xnext = x1 - x2;
2841 	znext = z1 - z2;
2842 
2843 	// update pc
2844 	log->anim_pc = next_pc; // allready computed
2845 
2846 	// get the pan unwind value of the frame to be printed
2847 	PXreal pan;
2848 	nextFrame->markers[ORG_POS].GetPan(&pan);
2849 
2850 	log->pan_adjust = pan;
2851 
2852 	// calculate the new x and z coordinate from this frames motion offset
2853 	// do the z and x together
2854 	PXfloat ang = (log->pan - log->pan_adjust) * TWO_PI;
2855 	PXfloat cang = (PXfloat)PXcos(ang);
2856 	PXfloat sang = (PXfloat)PXsin(ang);
2857 
2858 	x = log->mega->actor_xyz.x + PXfloat2PXreal(xnext * cang + znext * sang);
2859 	z = log->mega->actor_xyz.z + PXfloat2PXreal(znext * cang - xnext * sang);
2860 	// x and z are the new coordinates
2861 
2862 	PXfloat safe_pan = log->pan; // save the pan
2863 
2864 	// ok, check for a new collision with a barrier
2865 	ret = MS->Check_barrier_bump_and_bounce(x, log->mega->actor_xyz.y, z,                                           // new position
2866 	                                        log->mega->actor_xyz.x, log->mega->actor_xyz.y, log->mega->actor_xyz.z, // old position
2867 	                                        TRUE8);
2868 
2869 	if (ret == __NUDGED)
2870 		return TRUE8; // on ladder?
2871 
2872 	// did we move forward without a problem?
2873 	if (ret == __OK) {
2874 		//		record the new true actor position
2875 		log->mega->actor_xyz.x = x;
2876 		log->mega->actor_xyz.z = z;
2877 
2878 		//		check for new parent box and if so bring barriers
2879 		MS->Prepare_megas_route_barriers(TRUE8);
2880 	} else {
2881 		log->pan = safe_pan; // we bounced so cancel the pan correction that will have been done
2882 	}
2883 
2884 	CORRECT_PAN // stop the wrap
2885 
2886 	    return (TRUE8);
2887 }
2888 
Set_player_id(uint32 id)2889 void _player::Set_player_id(uint32 id) {
2890 	// declare object id of player to player system
2891 
2892 	// must be legal id
2893 	assert(id < MS->Fetch_number_of_objects());
2894 
2895 	player_id = id;
2896 
2897 	player_exists = TRUE8; // done for safety checks
2898 
2899 	Zdebug("\nSet_player_id %d", player_id);
2900 
2901 	// get player structures - we can be sure they wont get moved
2902 	log = g_mission->session->Fetch_object_struct(player_id);
2903 
2904 	// get initial barriers for player
2905 	MS->Prepare_megas_route_barriers(TRUE8);
2906 
2907 	// reset pointer to player parent barrier box
2908 	MS->logic_structs[id]->mega->cur_parent = NULL;
2909 
2910 	crouch = FALSE8; // not crouching
2911 
2912 	backward_lock = FALSE8; // back repeat stop
2913 	forward_lock = FALSE8;
2914 	interact_lock = FALSE8;
2915 
2916 	// set to stood
2917 	player_status = STOOD;
2918 }
2919 
AddMediPacks(uint32 num,bool8 bFlashIcons)2920 void _player::AddMediPacks(uint32 num, bool8 bFlashIcons) {
2921 	g_mission->num_medi += num;
2922 
2923 	// Check if flashing icon has been requested.
2924 	if (bFlashIcons)
2925 		g_oIconMenu->SetAddingMedipacksCount(num);
2926 }
2927 
AddAmmoClips(uint32 num,bool8 bFlashIcons)2928 void _player::AddAmmoClips(uint32 num, bool8 bFlashIcons) {
2929 	g_mission->num_clips += num;
2930 
2931 	uint32 maxClips = GetMaxClips();
2932 	if (g_mission->num_clips > maxClips)
2933 		g_mission->num_clips = maxClips;
2934 
2935 	// Check if flashing icon has been requested.
2936 	if (bFlashIcons)
2937 		g_oIconMenu->SetAddingClipsCount(num);
2938 }
2939 
SetBullets(uint32 num)2940 void _player::SetBullets(uint32 num) {
2941 	g_mission->num_bullets = num;
2942 }
2943 
UseBullets(uint32 num)2944 void _player::UseBullets(uint32 num) {
2945 	g_mission->num_bullets -= num;
2946 }
2947 
GetNoBullets()2948 int32 _player::GetNoBullets() {
2949 	return g_mission->num_bullets;
2950 }
2951 
UseAmmoClips(uint32 num)2952 void _player::UseAmmoClips(uint32 num) {
2953 	g_mission->num_clips -= num;
2954 }
2955 
GetNoAmmoClips()2956 int32 _player::GetNoAmmoClips() {
2957 	return g_mission->num_clips;
2958 }
2959 
UseMediPacks(uint32 num)2960 void _player::UseMediPacks(uint32 num) {
2961 	g_mission->num_medi -= num;
2962 }
2963 
GetNoMediPacks()2964 int32 _player::GetNoMediPacks() {
2965 	return g_mission->num_medi;
2966 }
2967 
Reset_guard_alert()2968 void _game_session::Reset_guard_alert() {
2969 	// clear all alerts - call this when leaving a mode that can cause alert
2970 
2971 	uint32 j;
2972 
2973 	for (j = 0; j < MAX_voxel_list; j++)
2974 		alert_list[j] = 0;
2975 }
2976 
Process_guard_alert(__alert alert_type)2977 void _game_session::Process_guard_alert(__alert alert_type) {
2978 	// player is walking or running
2979 	// check if he is behind any guards and if so alert them
2980 	// called the players cycle so can use L M etc
2981 
2982 #define TOUCH_ALERT_DIST (70 * 70)
2983 #define PUNCH_ALERT_DIST (200 * 200)
2984 #define WALK_ALERT_DIST (200 * 200)
2985 #define RUN_ALERT_DIST (400 * 400)
2986 
2987 	static bool8 reset = FALSE8;
2988 
2989 	uint32 j;
2990 	PXreal len;
2991 	int32 noise_level;
2992 
2993 	// if first game cycle then reset list
2994 	if (!reset)
2995 		for (j = 0; j < MAX_voxel_list; j++)
2996 			alert_list[j] = 0;
2997 
2998 	reset = TRUE8;
2999 
3000 	if ((alert_type == __AWALKING) && (player.walk_count < 8))
3001 		return; // walking but not enough steps taken
3002 
3003 	// we are running or have walked enough to make a sound
3004 
3005 	noise_level = GetCurrentSoundLevel();
3006 
3007 	Tdebug("fx.txt", "%d", noise_level);
3008 
3009 	for (j = 0; j < number_of_voxel_ids; j++) {
3010 		if (cur_id != voxel_id_list[j]) { // not us
3011 			if (!g_oLineOfSight->LineOfSight(voxel_id_list[j], player.Fetch_player_id())) { // cant see
3012 				if (PXfabs(logic_structs[voxel_id_list[j]]->mega->actor_xyz.y - M->actor_xyz.y) < (200 * REAL_ONE)) { // slack for height calc
3013 					PXreal sub1 = logic_structs[voxel_id_list[j]]->mega->actor_xyz.x - M->actor_xyz.x;
3014 					PXreal sub2 = logic_structs[voxel_id_list[j]]->mega->actor_xyz.z - M->actor_xyz.z;
3015 
3016 					len = (PXreal)((sub1 * sub1) + (sub2 * sub2)); // dist away
3017 
3018 					//					check for touching the guard
3019 					if (len < TOUCH_ALERT_DIST) {
3020 						alert_list[j] = TRUE8;
3021 						Force_context_check(voxel_id_list[j]);
3022 						return;
3023 					}
3024 
3025 					if (alert_type == __ARUNNING) {
3026 						if ((!alert_list[j]) && (len < RUN_ALERT_DIST) && (noise_level < 75)) {
3027 							alert_list[j] = TRUE8;
3028 							//							send event
3029 							Force_context_check(voxel_id_list[j]);
3030 						} else if (len >= RUN_ALERT_DIST) {
3031 							alert_list[j] = FALSE8;
3032 						}
3033 					} else if (alert_type == __AWALKING) { // walking
3034 						if ((!alert_list[j]) && (len < WALK_ALERT_DIST) && (noise_level < 50)) {
3035 							alert_list[j] = TRUE8;
3036 							//							send event
3037 							Force_context_check(voxel_id_list[j]);
3038 						} else if (len >= WALK_ALERT_DIST) {
3039 							alert_list[j] = FALSE8;
3040 						}
3041 
3042 					} else if (alert_type == __APUNCHING) { // punching
3043 						if ((!alert_list[j]) && (len < PUNCH_ALERT_DIST)) {
3044 							alert_list[j] = TRUE8;
3045 							//							send event
3046 							Force_context_check(voxel_id_list[j]);
3047 						} else if (len >= PUNCH_ALERT_DIST) {
3048 							alert_list[j] = FALSE8;
3049 						}
3050 					}
3051 				}
3052 			} else
3053 				alert_list[j] = FALSE8; // can see so cancel a previously set alert
3054 		}
3055 	}
3056 }
3057 
Signal_to_other_guards()3058 void _game_session::Signal_to_other_guards() {
3059 	// players just got gun out
3060 	// we need to tell all megas who can see us to rerun contexts because they may need to react
3061 
3062 	uint32 j;
3063 
3064 	for (j = 0; j < number_of_voxel_ids; j++) // run through them
3065 		if (logic_structs[voxel_id_list[j]]->mega->is_evil) // evil ones only
3066 			if (g_oLineOfSight->LineOfSight(voxel_id_list[j], player.Fetch_player_id())) { // can see player
3067 				if ((player.interact_selected) && (player.cur_interact_id == voxel_id_list[j])) {
3068 				} else {
3069 					Force_context_check(voxel_id_list[j]); // must rerun
3070 				}
3071 			}
3072 }
3073 
Signal_to_guards()3074 void _game_session::Signal_to_guards() {
3075 	// players just got gun out
3076 	// we need to tell all megas who can see us to rerun contexts because they may need to react
3077 
3078 	uint32 j;
3079 
3080 	for (j = 0; j < number_of_voxel_ids; j++) // run through them
3081 		if (logic_structs[voxel_id_list[j]]->mega->is_evil) // evil ones only
3082 			if (g_oLineOfSight->LineOfSight(voxel_id_list[j], player.Fetch_player_id())) // can see player
3083 				Force_context_check(voxel_id_list[j]); // must rerun
3084 }
3085 
fn_can_hear_players_feet(int32 & result,int32 *)3086 mcodeFunctionReturnCodes _game_session::fn_can_hear_players_feet(int32 &result, int32 *) {
3087 	// can this mega hear the players footsteps
3088 
3089 	uint32 j;
3090 
3091 	for (j = 0; j < MAX_voxel_list; j++)
3092 		if (voxel_id_list[j] == cur_id) {
3093 			result = alert_list[j];
3094 			return IR_CONT;
3095 		}
3096 
3097 	Fatal_error("fn_can_hear_players_feet says you should never see this");
3098 
3099 	return IR_CONT;
3100 }
3101 
fn_is_player_striking(int32 & result,int32 *)3102 mcodeFunctionReturnCodes _game_session::fn_is_player_striking(int32 &result, int32 *) {
3103 	// is the player punching, yes or no
3104 
3105 	if (player.player_status == STRIKING)
3106 		result = 1;
3107 	else
3108 		result = 0;
3109 
3110 	return IR_CONT;
3111 }
3112 
Reset_player()3113 void _player::Reset_player() {
3114 	// set the player back to standing
3115 	// used afer gunshot, etc
3116 	// see fn-reset-player
3117 
3118 	crouch = FALSE8; // not crouching
3119 
3120 	walk_count = 0; // reset walk count for guard alerting
3121 
3122 	forward_lock = FALSE8;
3123 	interact_lock = FALSE8;
3124 
3125 	Start_new_mode(STOOD);
3126 }
3127 
Restart_player()3128 void _game_session::Restart_player() {
3129 	camera_lock = FALSE8; // let the camera be working again
3130 
3131 	// for debugging purposes
3132 
3133 	cur_id = player.Fetch_player_id();
3134 	L = logic_structs[cur_id];
3135 	I = L->voxel_info;
3136 	M = L->mega;
3137 	MS->Set_pose(__NOT_ARMED);
3138 	MS->Change_pose_in_current_anim_set();
3139 
3140 	player.Reset_player();
3141 
3142 	int32 var_num;
3143 	c_game_object *ob;
3144 
3145 	ob = (c_game_object *)objects->Fetch_item_by_number(player.Fetch_player_id());
3146 
3147 	var_num = ob->GetVariable("state");
3148 	if (var_num == -1)
3149 		Fatal_error("Restart_player cant fetch state");
3150 	ob->SetIntegerVariable(var_num, 0); // alive
3151 
3152 	var_num = ob->GetVariable("hits");
3153 	if (var_num == -1)
3154 		Fatal_error("Restart_player cant fetch hits");
3155 	ob->SetIntegerVariable(var_num, MAX_HITS); // another 10 hits
3156 
3157 	L->logic_level = 0; // restart
3158 	L->logic_ref[1] = 0;
3159 
3160 	M->dead = 0; // not dead!!!
3161 
3162 	player.SetBullets(9);
3163 	player.AddAmmoClips(5, 0);
3164 }
3165 
GetBulletsPerClip()3166 uint32 _player::GetBulletsPerClip() {
3167 	uint32 bull_per_clip = g_globalScriptVariables->GetVariable("bullets_per_clip");
3168 	return bull_per_clip;
3169 }
3170 
GetMaxClips()3171 uint32 _player::GetMaxClips() {
3172 	return MAX_AMMO_CLIPS;
3173 }
3174 
3175 } // End of namespace ICB
3176