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