#include #include #include #include #include #include #include #include #include "bondaicommands.h" #include "bg.h" #include "cheat.h" #include "chr.h" #include "chrai.h" #include "chraction.h" #include "chrobjdata.h" #include "debugmenu_handler.h" #include "dyn.h" #include "glass.h" #include "file2.h" #include "propobj.h" #include "explosion.h" #include "file.h" #include "gun.h" #include "initanitable.h" #include "joy.h" #include "lv.h" #include "language.h" #include "matrixmath.h" #include "objecthandler.h" #include "player.h" #include "propobj.h" #include "stan.h" #include "model.h" #include "tex.h" #ifdef PORT #include #include #include "drawdistgameplay.h" /* GE_D193A=1 — per-second locomotion telemetry for one/all scripted chrs * (D193: "AI travels slower than N64" — the frame clock was ruled out in * M-80, so measure the anim-root-motion path directly). For each ticked * chr, once per wall-second: chrnum, actiontype, distance travelled in * world units over the last second (= travel speed), and the scalars that * feed the root-motion extraction in modelSetAnimFrame2WithChrStuff * (model.c:3060+): scale, anim_translation_scale, animrate, playspeed, * speed, endframe, plus g_GlobalTimerDelta for reference. Optionally * GE_D193A_CHR= restricts output to that chrnum. Test-only, env-gated. */ static int d193a_mode = -1; static int d193a_only = -1; struct D193aSlot { s16 chrnum; u8 used; f32 px, py, pz, accdist; OSTime t0; u32 ticks, moved, frozen; }; static struct D193aSlot d193a_slots[48]; static struct D193aSlot *d193aSlot(s16 n) { int free = -1; for (int i = 0; i < 48; i++) { if (d193a_slots[i].used && d193a_slots[i].chrnum == n) return &d193a_slots[i]; if (free < 0 && !d193a_slots[i].used) free = i; } if (free < 0) return NULL; d193a_slots[free].used = 1; d193a_slots[free].chrnum = n; d193a_slots[free].accdist = 0.0f; d193a_slots[free].t0 = 0; d193a_slots[free].ticks = d193a_slots[free].moved = d193a_slots[free].frozen = 0; return &d193a_slots[free]; } static s32 d193aAnimIndex(void *anim) { extern s32 animation_table_ptrs1[]; s32 i; if (anim == NULL) return -1; for (i = 0; animation_table_ptrs1[i] != 0; i++) { if ((void *)(uintptr_t)(u32)animation_table_ptrs1[i] == anim) return i; } return -1; } static void d193aSample(ChrRecord *chr, Model *model) { if (d193a_mode < 0) { d193a_mode = getenv("GE_D193A") != NULL; const char *o = getenv("GE_D193A_CHR"); d193a_only = o ? atoi(o) : -1; } if (!d193a_mode || model == NULL || chr->prop == NULL) return; if (d193a_only >= 0 && chr->chrnum != d193a_only) return; struct D193aSlot *s = d193aSlot(chr->chrnum); if (!s) return; s->ticks++; f32 x = chr->prop->pos.x, y = chr->prop->pos.y, z = chr->prop->pos.z; OSTime now = osGetTime(); if (s->t0 == 0) { s->t0 = now; s->px = x; s->py = y; s->pz = z; s->accdist = 0.0f; return; } f32 dx = x - s->px, dy = y - s->py, dz = z - s->pz; s->accdist += sqrtf(dx*dx + dy*dy + dz*dz); s->px = x; s->py = y; s->pz = z; if (now - s->t0 >= 1000000) { f32 secs = (f32)(now - s->t0) / 1e6f; fprintf(stderr, "[D193A] chr=%d act=%d speed=%.1fu/s gtd=%.2f | tier=%d gspd=%.2f | typ=%d tick=%u move=%u frz=%u hid=%d | scale=%.4f xlscale=%.4f " "animrate=%.4f playspeed=%.4f mspeed=%.4f endframe=%.1f anim=%p aidx=%d\n", chr->chrnum, (int)chr->actiontype, s->accdist / secs, g_GlobalTimerDelta, (chr->actiontype == ACT_GOPOS) ? (int)chr->act_gopos.unk59 : -1, (chr->actiontype == ACT_GOPOS) ? (double)chr->act_gopos.speed : -1.0, (int)chr->prop->type, s->ticks, s->moved, s->frozen, (int)((chr->chrflags & CHRFLAG_HIDDEN) != 0), model->scale, model->anim_translation_scale, model->animrate, model->playspeed, model->speed, model->endframe, (void *)model->anim, (int)d193aAnimIndex((void *)model->anim)); s->t0 = now; s->accdist = 0.0f; s->ticks = s->moved = s->frozen = 0; } } /* GE_D193A companion: called from chrUpdateAnim -- the ONLY path that * advances prop->pos from anim root motion. chrTick gates it behind * posIsOnScreen() for ACT_ANIM/ACT_STAND (chr.c:2540-2565): an off-screen * chr gets modelTickAnim(model, ticks, 0) instead, which skips * modelSetAnimFrame2WithChrStuff entirely and so does not move at all. * move << tick in the per-second line = the chr is being visibility-culled * out of its own locomotion; move == tick = the gate is clean and the * slowdown is a rate/magnitude problem inside the root-motion decode. */ static void d193aMoved(ChrRecord *chr, int frozen) { if (d193a_mode <= 0 || chr->prop == NULL) return; if (d193a_only >= 0 && chr->chrnum != d193a_only) return; struct D193aSlot *s = d193aSlot(chr->chrnum); if (!s) return; if (frozen) s->frozen++; else s->moved++; } #endif #ifdef VERSION_EU #define GROUND_SMOOTH_FACTOR 0.118799984f /* 0x3DF34D68 (PAL-scaled 0.1) */ #define FALLSPEED_DECAY 0.8812f /* 0x3F619653 (PAL-scaled 0.9) */ #else #define GROUND_SMOOTH_FACTOR 0.100000024f /* 0x3DCCCCD0 */ #define FALLSPEED_DECAY 0.9f /* 0x3F666666 */ #endif // forward declarations void chrUpdateAimProperties( ChrRecord *arg0); void chrUpdateAnim( ChrRecord *chr, s32 tickamount); void sub_GAME_7F057D44(f32 *arg0, f32 *arg1, f32 arg2); f32 get_007_health_mod(void); // end forward declarations // data f32 animation_rate = 0; s32 D_8002C904 = 0; /** * Address 0x8002C908. */ s32 g_AnimationTablePointerCountRelated = 0; s32 D_8002C90C = 0; s32 D_8002C910 = 0; /* * D:8002C914 * Per-body-part hit reaction table, indexed by HITTARGET. * Legend: iN/iSz = impact puff count/size, bN/bSz = back puff count/size, * u8/u14 = unused, dN/fN = death/flinch anim counts (filled at init by initWeaponAnimGroups). */ /* part, iN, u8, iSz, bN, u14, bSz, deathAnims, dN, flinchAnims, fN */ struct ChrHitReaction g_HitReactionTable[] = { /* HIT_NULL_PART */ {0 , 0, 0, 0, 0, 0, 0, NULL, 0, NULL, 0}, /* HIT_LEFT_FOOT */ {1 , 1, 0, 17.0, 3, 0, 34.0, death_left_foot, 0, flinch_left_foot, 0}, /* HIT_LEFT_LEG */ {2 , 1, 0, 17.0, 3, 0, 39.0, death_left_leg, 0, flinch_left_leg, 0}, /* HIT_LEFT_THIGH */ {3 , 1, 0, 21.0, 3, 0, 43.0, death_left_thigh, 0, flinch_left_thigh, 0}, /* HIT_RIGHT_FOOT */ {4 , 1, 0, 17.0, 3, 0, 34.0, death_right_foot, 0, flinch_right_foot, 0}, /* HIT_RIGHT_LEG */ {5 , 1, 0, 17.0, 3, 0, 39.0, death_right_leg, 0, flinch_right_leg, 0}, /* HIT_RIGHT_THIGH */ {6 , 1, 0, 21.0, 3, 0, 43.0, death_right_thigh, 0, flinch_right_thigh, 0}, /* HIT_PELVIS */ {7 , 1, 0, 21.0, 3, 0, 52.0, death_pelvis, 0, flinch_pelvis, 0}, /* HIT_HEAD */ {8 , 1, 0, 21.0, 3, 0, 43.0, death_head, 0, flinch_head, 0}, /* HIT_LEFT_HAND */ {9 , 1, 0, 17.0, 3, 0, 34.0, death_left_hand, 0, flinch_left_hand, 0}, /* HIT_LEFT_ARM */ {0xA , 1, 0, 17.0, 3, 0, 43.0, death_left_arm, 0, flinch_left_arm, 0}, /* HIT_LEFT_SHOULDER */ {0xB , 1, 0, 21.0, 3, 0, 52.0, death_left_shoulder, 0, flinch_left_shoulder, 0}, /* HIT_RIGHT_HAND */ {0xC , 1, 0, 17.0, 3, 0, 34.0, death_right_hand, 0, flinch_right_hand, 0}, /* HIT_RIGHT_ARM */ {0xD , 1, 0, 17.0, 3, 0, 43.0, death_right_arm, 0, flinch_right_arm, 0}, /* HIT_RIGHT_SHOULDER */ {0xE , 1, 0, 21.0, 3, 0, 52.0, death_right_shoulder, 0, flinch_right_shoulder, 0}, /* HIT_CHEST */ {0xF , 1, 0, 26.0, 3, 0, 60.0, death_chest, 0, flinch_chest, 0}, /* HIT_GUN */ {0x64 , 1, 0, 26.0, 0, 0, 0.0, death_gun, 0, flinch_gun, 0}, /* HIT_HAT */ {0x6E , 1, 0, 21.0, 0, 0, 0.0, NULL, 0, NULL, 0}, /* terminator */ {0xFFFFFFFF , 0, 0, 0.0, 0, 0, 0.0, NULL, 0, NULL, 0}, }; s32 D_8002CC58 = 0; // Set to 0 but otherwise never used. s32 show_patrols_flag = FALSE; s32 player1_guardID = 5000; ChrRecord *g_ChrSlots = 0; s32 g_NumChrSlots = 0; ModelRenderData D_8002CC6C = {NULL, TRUE, 0x00000003, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, CULLMODE_BOTH}; coord3d D_8002CCAC = {0, 0, 0}; rgba_u8 gBloodColour = { 0x5a, 0, 0, 0}; /** * Address 0x8002CCBC. */ ModelRenderData D_8002CCBC = {NULL, TRUE, 0x00000003, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, CULLMODE_BOTH}; s32 D_8002CCFC = 0; // Unused. u32 num_bodies = 0; u32 num_male_heads = 0; u32 num_female_heads = 0; s32 list_of_bodies[] = { BODY_Jungle_Commando,BODY_St_Petersburg_Guard,BODY_Russian_Soldier,BODY_Russian_Infantry, BODY_Janus_Special_Forces,BODY_Brosnan_Tuxedo,BODY_Boris,BODY_Ourumov, BODY_Trevelyan_Janus,BODY_Valentin_,BODY_Xenia,BODY_Baron_Samedi, BODY_Jaws,BODY_Mayday,BODY_Oddjob,BODY_Natalya_Skirt, BODY_Janus_Marine,BODY_Russian_Commandant,BODY_Siberian_Guard_1_Mishkin,BODY_Naval_Officer, BODY_Siberian_Special_Forces,BODY_Special_Operations_Uniform,BODY_Formal_Wear,BODY_Jungle_Fatigues, BODY_Unused_Female,BODY_Rosika,BODY_Scientist_2_Female,BODY_Civilian_1_Female, BODY_Unused_Male_1,BODY_Unused_Male_2,BODY_Civilian_4,BODY_Civilian_2, BODY_Civilian_3,BODY_Scientist_1_Male,BODY_Brosnan_Tuxedo,BODY_Brosnan_Tuxedo, BODY_Brosnan_Tuxedo,BODY_Helicopter_Pilot,BODY_Siberian_Guard_2,BODY_Arctic_Commando, BODY_Moonraker_Elite_1_Male,BODY_Moonraker_Elite_2_Female,-1, }; s32 random_male_heads[] = { HEAD_Male_Jim,HEAD_Male_Chris,HEAD_Male_Lee,HEAD_Male_Graeme,HEAD_Male_Steve_H, HEAD_Male_Neil,HEAD_Male_Robin,HEAD_Male_Des,HEAD_Male_Grant,HEAD_Male_Dave_Dr_Doak, HEAD_Male_Karl,HEAD_Male_Alan,HEAD_Male_Pete,HEAD_Male_Martin,HEAD_Male_Mark, HEAD_Male_Duncan,HEAD_Male_Shaun,HEAD_Male_Dwayne,HEAD_Male_B,HEAD_Male_Steve_Ellis, HEAD_Male_Joel,HEAD_Male_Scott,HEAD_Male_Joe_Altered,HEAD_Male_Ken,HEAD_Male_Joe, -1 }; s32 random_female_heads[] = { HEAD_Female_Sally,HEAD_Female_Marion_Rosika,HEAD_Female_Mandy,HEAD_Female_Vivien, -1 }; u32 current_random_body = 0; u32 current_random_male_head = 0; u32 current_random_female_head = 0; /* * Enemy accuracy modifier. * Set on level load. * One of the values that can be set with the 007 slider. */ f32 g_AiAccuracyModifier = 1.0f; /* * Enemy damage modifier. * Set on level load. * One of the values that can be set with the 007 slider. */ f32 g_AiDamageModifier = 1.0f; f32 g_AiHealthModifier = 1.0f; /* * Enemy reaction speed modifier. * Set on level load. * One of the values that can be set with the 007 slider. */ f32 g_AiReactionSpeed = 1.0f; /** * Count of number of guards that have recently seen bond: * (guard->lastseetarget60 > 0) && (g_GlobalTimer - guard->lastseetarget60 < 120) * Updated every tick. * Address 0x8002CE50. */ s32 g_SeenBondRecentlyGuardCount = 0; struct StruckAnim death_left_foot[] = { { PTR_ANIM_death_backward_spin_face_down_left, 0, -1.0, 0.5, 0, 27.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_left, 0, -1.0, 0.5, 0, 26.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_down_right, 1, -1.0, 0.5, 0, 25.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_right, 1, -1.0, 0.5, 0, 23.0, -1.0 }, {0, 0, 0.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim death_left_leg[] = { { PTR_ANIM_death_backward_spin_face_down_left, 0, -1.0, 0.5, 0, 27.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_left, 0, -1.0, 0.5, 0, 26.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_down_right, 1, -1.0, 0.5, 0, 25.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_right, 1, -1.0, 0.5, 0, 23.0, -1.0 }, {0, 0, 0.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim death_left_thigh[] = { { PTR_ANIM_death_backward_spin_face_down_left, 0, -1.0, 0.5, 1, 27.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_left, 0, -1.0, 0.5, 1, 26.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_down_right, 1, -1.0, 0.5, 1, 25.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_right, 1, -1.0, 0.5, 1, 23.0, -1.0 }, { PTR_ANIM_death_left_leg, 1, -1.0, 0.5, 0, -1.0, -1.0 }, {0, 0, 0.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim death_right_foot[] = { { PTR_ANIM_death_backward_spin_face_down_right, 0, -1.0, 0.5, 0, 25.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_right, 0, -1.0, 0.5, 0, 23.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_down_left, 1, -1.0, 0.5, 0, 27.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_left, 1, -1.0, 0.5, 0, 26.0, -1.0 }, {0, 0, 0.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim death_right_leg[] = { { PTR_ANIM_death_backward_spin_face_down_right, 0, -1.0, 0.5, 0, 25.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_right, 0, -1.0, 0.5, 0, 23.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_down_left, 1, -1.0, 0.5, 0, 27.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_left, 1, -1.0, 0.5, 0, 26.0, -1.0 }, {0, 0, 0.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim death_right_thigh[] = { { PTR_ANIM_death_backward_spin_face_down_right, 0, -1.0, 0.5, 1, 25.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_right, 0, -1.0, 0.5, 1, 23.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_down_left, 1, -1.0, 0.5, 1, 27.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_left, 1, -1.0, 0.5, 1, 26.0, -1.0 }, { PTR_ANIM_death_left_leg, 0, -1.0, 0.5, 0, -1.0, -1.0 }, {0, 0, 0.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim death_pelvis[] = { { PTR_ANIM_death_forward_face_down, 0, -1.0, 0.5, 0, 55.0, 39.0 }, { PTR_ANIM_death_forward_face_down, 1, -1.0, 0.5, 0, 55.0, 39.0 }, { PTR_ANIM_death_forward_spin_face_up, 0, -1.0, 0.5, 0, 36.0, -1.0 }, { PTR_ANIM_death_forward_spin_face_up, 1, -1.0, 0.5, 0, 36.0, -1.0 }, { PTR_ANIM_death_backward_fall_face_up1, 0, -1.0, 0.5, 1, 29.0, -1.0 }, { PTR_ANIM_death_backward_fall_face_up1, 1, -1.0, 0.5, 1, 29.0, -1.0 }, { PTR_ANIM_death_forward_face_down_hard, 0, -1.0, 0.5, 0, 97.0, 64.0 }, { PTR_ANIM_death_forward_face_down_hard, 1, -1.0, 0.5, 0, 97.0, 64.0 }, { PTR_ANIM_death_fetal_position_right, 0, -1.0, 0.5, 0, 31.0, -1.0 }, { PTR_ANIM_death_fetal_position_right, 1, -1.0, 0.5, 0, 31.0, -1.0 }, { PTR_ANIM_death_fetal_position_left, 0, -1.0, 0.5, 0, 36.0, -1.0 }, { PTR_ANIM_death_fetal_position_left, 1, -1.0, 0.5, 0, 36.0, -1.0 }, { PTR_ANIM_death_backward_fall_face_up2, 0, -1.0, 0.5, 0, 28.0, -1.0 }, { PTR_ANIM_death_backward_fall_face_up2, 1, -1.0, 0.5, 0, 28.0, -1.0 }, { PTR_ANIM_death_genitalia, 0, -1.0, 0.5, 0, 79.0, 415.0 }, { PTR_ANIM_death_genitalia, 1, -1.0, 0.5, 0, 79.0, 415.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim death_head[] = { { PTR_ANIM_death_forward_face_down, 0, -1.0, 0.5, 0, 55.0, 39.0 }, { PTR_ANIM_death_forward_face_down, 1, -1.0, 0.5, 0, 55.0, 39.0 }, { PTR_ANIM_death_forward_spin_face_up, 0, -1.0, 0.5, 0, 36.0, -1.0 }, { PTR_ANIM_death_forward_spin_face_up, 1, -1.0, 0.5, 0, 36.0, -1.0 }, { PTR_ANIM_death_backward_fall_face_up1, 0, -1.0, 0.5, 1, 29.0, -1.0 }, { PTR_ANIM_death_backward_fall_face_up1, 1, -1.0, 0.5, 1, 29.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_down_right, 0, -1.0, 0.5, 1, 25.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_down_right, 1, -1.0, 0.5, 1, 25.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_right, 0, -1.0, 0.5, 1, 23.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_right, 1, -1.0, 0.5, 1, 23.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_down_left, 0, -1.0, 0.5, 1, 27.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_down_left, 1, -1.0, 0.5, 1, 27.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_left, 0, -1.0, 0.5, 1, 26.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_left, 1, -1.0, 0.5, 1, 26.0, -1.0 }, { PTR_ANIM_death_forward_face_down_hard, 0, -1.0, 0.5, 0, 97.0, 64.0 }, { PTR_ANIM_death_forward_face_down_hard, 1, -1.0, 0.5, 0, 97.0, 64.0 }, { PTR_ANIM_death_forward_face_down_soft, 0, -1.0, 0.5, 0, 94.0, 66.0 }, { PTR_ANIM_death_forward_face_down_soft, 1, -1.0, 0.5, 0, 94.0, 66.0 }, { PTR_ANIM_death_fetal_position_right, 0, -1.0, 0.5, 0, 31.0, -1.0 }, { PTR_ANIM_death_fetal_position_right, 1, -1.0, 0.5, 0, 31.0, -1.0 }, { PTR_ANIM_death_fetal_position_left, 0, -1.0, 0.5, 0, 36.0, -1.0 }, { PTR_ANIM_death_fetal_position_left, 1, -1.0, 0.5, 0, 36.0, -1.0 }, { PTR_ANIM_death_backward_fall_face_up2, 0, -1.0, 0.5, 0, 28.0, -1.0 }, { PTR_ANIM_death_backward_fall_face_up2, 1, -1.0, 0.5, 0, 28.0, -1.0 }, { PTR_ANIM_death_neck, 0, -1.0, 0.5, 0, 87.0, 203.0 }, { PTR_ANIM_death_neck, 1, -1.0, 0.5, 0, 87.0, 203.0 }, { PTR_ANIM_death_head, 0, -1.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_death_head, 1, -1.0, 0.5, 0, -1.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim death_left_hand[] = { { PTR_ANIM_death_backward_spin_face_down_left, 0, -1.0, 0.5, 0, 27.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_left, 0, -1.0, 0.5, 0, 26.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_down_right, 1, -1.0, 0.5, 0, 25.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_right, 1, -1.0, 0.5, 0, 23.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim death_left_arm[] = { { PTR_ANIM_death_backward_spin_face_down_left, 0, -1.0, 0.5, 0, 27.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_left, 0, -1.0, 0.5, 0, 26.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_down_right, 1, -1.0, 0.5, 0, 25.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_right, 1, -1.0, 0.5, 0, 23.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim death_left_shoulder[] = { { PTR_ANIM_death_backward_spin_face_down_left, 0, -1.0, 0.5, 1, 27.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_left, 0, -1.0, 0.5, 1, 26.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_down_right, 1, -1.0, 0.5, 1, 25.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_right, 1, -1.0, 0.5, 1, 23.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim death_right_hand[] = { { PTR_ANIM_death_backward_spin_face_down_right, 0, -1.0, 0.5, 0, 25.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_right, 0, -1.0, 0.5, 0, 23.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_down_left, 1, -1.0, 0.5, 0, 27.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_left, 1, -1.0, 0.5, 0, 26.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim death_right_arm[] = { { PTR_ANIM_death_backward_spin_face_down_right, 0, -1.0, 0.5, 0, 25.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_right, 0, -1.0, 0.5, 0, 23.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_down_left, 1, -1.0, 0.5, 0, 27.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_left, 1, -1.0, 0.5, 0, 26.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim death_right_shoulder[] = { { PTR_ANIM_death_backward_spin_face_down_right, 0, -1.0, 0.5, 1, 25.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_right, 0, -1.0, 0.5, 1, 23.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_down_left, 1, -1.0, 0.5, 1, 27.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_left, 1, -1.0, 0.5, 1, 26.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim death_chest[] = { { PTR_ANIM_death_forward_face_down, 0, -1.0, 0.5, 0, 55.0, 39.0 }, { PTR_ANIM_death_forward_face_down, 1, -1.0, 0.5, 0, 55.0, 39.0 }, { PTR_ANIM_death_forward_spin_face_up, 0, -1.0, 0.5, 0, 36.0, -1.0 }, { PTR_ANIM_death_forward_spin_face_up, 1, -1.0, 0.5, 0, 36.0, -1.0 }, { PTR_ANIM_death_backward_fall_face_up1, 0, -1.0, 0.5, 1, 29.0, -1.0 }, { PTR_ANIM_death_backward_fall_face_up1, 1, -1.0, 0.5, 1, 29.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_down_right, 0, -1.0, 0.5, 1, 25.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_down_right, 1, -1.0, 0.5, 1, 25.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_right, 0, -1.0, 0.5, 1, 23.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_right, 1, -1.0, 0.5, 1, 23.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_down_left, 0, -1.0, 0.5, 1, 27.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_down_left, 1, -1.0, 0.5, 1, 27.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_left, 0, -1.0, 0.5, 1, 26.0, -1.0 }, { PTR_ANIM_death_backward_spin_face_up_left, 1, -1.0, 0.5, 1, 26.0, -1.0 }, { PTR_ANIM_death_forward_face_down_hard, 0, -1.0, 0.5, 0, 97.0, 64.0 }, { PTR_ANIM_death_forward_face_down_hard, 1, -1.0, 0.5, 0, 97.0, 64.0 }, { PTR_ANIM_death_forward_face_down_soft, 0, -1.0, 0.5, 0, 94.0, 66.0 }, { PTR_ANIM_death_forward_face_down_soft, 1, -1.0, 0.5, 0, 94.0, 66.0 }, { PTR_ANIM_death_fetal_position_right, 0, -1.0, 0.5, 0, 31.0, -1.0 }, { PTR_ANIM_death_fetal_position_right, 1, -1.0, 0.5, 0, 31.0, -1.0 }, { PTR_ANIM_death_fetal_position_left, 0, -1.0, 0.5, 0, 36.0, -1.0 }, { PTR_ANIM_death_fetal_position_left, 1, -1.0, 0.5, 0, 36.0, -1.0 }, { PTR_ANIM_death_backward_fall_face_up2, 0, -1.0, 0.5, 0, 28.0, -1.0 }, { PTR_ANIM_death_backward_fall_face_up2, 1, -1.0, 0.5, 0, 28.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim death_gun[] = { { PTR_ANIM_death_forward_face_down, 0, -1.0, 0.5, 0, 55.0, 39.0 }, { PTR_ANIM_death_forward_face_down, 1, -1.0, 0.5, 0, 55.0, 39.0 }, { PTR_ANIM_death_forward_spin_face_up, 0, -1.0, 0.5, 0, 36.0, -1.0 }, { PTR_ANIM_death_forward_spin_face_up, 1, -1.0, 0.5, 0, 36.0, -1.0 }, { PTR_ANIM_death_backward_fall_face_up1, 0, -1.0, 0.5, 1, 29.0, -1.0 }, { PTR_ANIM_death_backward_fall_face_up1, 1, -1.0, 0.5, 1, 29.0, -1.0 }, { PTR_ANIM_death_forward_face_down_hard, 0, -1.0, 0.5, 0, 97.0, 64.0 }, { PTR_ANIM_death_forward_face_down_hard, 1, -1.0, 0.5, 0, 97.0, 64.0 }, { PTR_ANIM_death_forward_face_down_soft, 0, -1.0, 0.5, 0, 94.0, 66.0 }, { PTR_ANIM_death_forward_face_down_soft, 1, -1.0, 0.5, 0, 94.0, 66.0 }, { PTR_ANIM_death_fetal_position_right, 0, -1.0, 0.5, 0, 31.0, -1.0 }, { PTR_ANIM_death_fetal_position_right, 1, -1.0, 0.5, 0, 31.0, -1.0 }, { PTR_ANIM_death_fetal_position_left, 0, -1.0, 0.5, 0, 36.0, -1.0 }, { PTR_ANIM_death_fetal_position_left, 1, -1.0, 0.5, 0, 36.0, -1.0 }, { PTR_ANIM_death_backward_fall_face_up2, 0, -1.0, 0.5, 0, 28.0, -1.0 }, { PTR_ANIM_death_backward_fall_face_up2, 1, -1.0, 0.5, 0, 28.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim death_stagger[] = { { PTR_ANIM_death_stagger_back_to_wall, 0, -1.0, 0.5, 0, 67.0, 54.0 }, { PTR_ANIM_death_stagger_back_to_wall, 1, -1.0, 0.5, 0, 67.0, 54.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim flinch_left_foot[] = { { PTR_ANIM_hit_left_leg, 0, -1.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_hit_right_leg, 1, -1.0, 0.5, 0, -1.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim flinch_left_leg[] = { { PTR_ANIM_hit_left_leg, 0, -1.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_hit_right_leg, 1, -1.0, 0.5, 0, -1.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim flinch_left_thigh[] = { { PTR_ANIM_hit_left_leg, 0, -1.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_hit_right_leg, 1, -1.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_death_left_leg, 1, 20.0, 0.40000001, 0, -1.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim flinch_right_foot[] = { { PTR_ANIM_hit_right_leg, 0, -1.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_hit_left_leg, 1, -1.0, 0.5, 0, -1.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim flinch_right_leg[] = { { PTR_ANIM_hit_right_leg, 0, -1.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_hit_left_leg, 1, -1.0, 0.5, 0, -1.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim flinch_right_thigh[] = { { PTR_ANIM_hit_right_leg, 0, -1.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_hit_left_leg, 1, -1.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_death_left_leg, 0, 20.0, 0.40000001, 0, -1.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim flinch_pelvis[] = { { PTR_ANIM_death_genitalia, 0, 20.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_death_genitalia, 1, 30.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_death_forward_face_down_soft, 0, 20.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_death_forward_face_down_soft, 1, 20.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_death_forward_face_down, 0, 15.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_death_forward_face_down, 1, 15.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_death_fetal_position_right, 0, 10.0, 0.25, 0, -1.0, -1.0 }, { PTR_ANIM_death_fetal_position_right, 1, 10.0, 0.25, 0, -1.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim flinch_head[] = { { PTR_ANIM_death_neck, 0, 15.0, 0.5, 0, 87.0, 203.0 }, { PTR_ANIM_death_neck, 1, 15.0, 0.5, 0, 87.0, 203.0 }, { PTR_ANIM_death_forward_face_down_soft, 0, 20.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_death_forward_face_down_soft, 1, 20.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_death_forward_face_down, 0, 15.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_death_forward_face_down, 1, 15.0, 0.5, 0, -1.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim flinch_left_hand[] = { { PTR_ANIM_hit_left_hand, 0, -1.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_hit_right_hand, 1, -1.0, 0.5, 0, -1.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim flinch_left_arm[] = { { PTR_ANIM_hit_left_arm, 0, -1.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_hit_right_arm, 1, -1.0, 0.5, 0, -1.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim flinch_left_shoulder[] = { { PTR_ANIM_hit_left_shoulder, 0, -1.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_hit_right_shoulder, 1, -1.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_death_forward_face_down_soft, 0, 20.0, 0.5, 0, -1.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim flinch_right_hand[] = { { PTR_ANIM_hit_right_hand, 0, -1.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_hit_left_hand, 1, -1.0, 0.5, 0, -1.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim flinch_right_arm[] = { { PTR_ANIM_hit_right_arm, 0, -1.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_hit_left_arm, 1, -1.0, 0.5, 0, -1.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim flinch_right_shoulder[] = { { PTR_ANIM_hit_right_shoulder, 0, -1.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_hit_left_shoulder, 1, -1.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_death_forward_face_down_soft, 1, 20.0, 0.5, 0, -1.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim flinch_chest[] = { { PTR_ANIM_death_forward_face_down_soft, 0, 20.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_death_forward_face_down_soft, 1, 20.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_death_forward_face_down, 0, 15.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_death_forward_face_down, 1, 15.0, 0.5, 0, -1.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct StruckAnim flinch_gun[] = { { PTR_ANIM_death_forward_face_down_soft, 0, 20.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_death_forward_face_down_soft, 1, 20.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_death_forward_face_down, 0, 15.0, 0.5, 0, -1.0, -1.0 }, { PTR_ANIM_death_forward_face_down, 1, 15.0, 0.5, 0, -1.0, -1.0 }, {0, 0, -1.0, 0.5, 0, -1.0, -1.0} }; struct explosion_death_animation D_8002E648[] = { { PTR_ANIM_death_explosion_forward, 0, 0.5, 9.0, 18.0, 29.0, -1.0 }, { PTR_ANIM_death_explosion_forward, 1, 0.5, 9.0, 18.0, 29.0, -1.0 }, { PTR_ANIM_death_explosion_forward_face_down, 0, 0.5, 11.0, 19.0, 31.0, -1.0 }, { PTR_ANIM_death_explosion_forward_face_down, 1, 0.5, 11.0, 19.0, 31.0, -1.0 }, { PTR_ANIM_death_explosion_forward_roll, 0, 0.5, 6.0, 20.0, 27.0, -1.0 }, { PTR_ANIM_death_explosion_forward_roll, 1, 0.5, 6.0, 20.0, 27.0, -1.0 }, { PTR_ANIM_death_explosion_forward_right2, 0, 0.5, 29.0, 36.0, 48.0, -1.0 }, { PTR_ANIM_death_explosion_forward_right2, 1, 0.5, 29.0, 36.0, 48.0, -1.0 }, { PTR_ANIM_death_explosion_forward_right2_alt, 0, 0.5, 29.0, 38.0, 49.0, -1.0 }, { PTR_ANIM_death_explosion_forward_right2_alt, 1, 0.5, 29.0, 38.0, 49.0, -1.0 }, { PTR_ANIM_death_explosion_forward_right3, 0, 0.5, 19.0, 30.0, 42.0, -1.0 }, { PTR_ANIM_death_explosion_forward_right3, 1, 0.5, 19.0, 30.0, 42.0, -1.0 }, { PTR_ANIM_death_explosion_left1, 0, 0.5, 9.0, 21.0, 29.0, 55.0 }, { PTR_ANIM_death_explosion_left1, 1, 0.5, 9.0, 21.0, 29.0, 55.0 }, { PTR_ANIM_death_explosion_right, 0, 0.5, 6.0, 18.0, 27.0, -1.0 }, { PTR_ANIM_death_explosion_right, 1, 0.5, 6.0, 18.0, 27.0, -1.0 }, { PTR_ANIM_death_explosion_forward_right1, 0, 0.5, 6.0, 19.0, 29.0, -1.0 }, { PTR_ANIM_death_explosion_forward_right1, 1, 0.5, 6.0, 19.0, 29.0, -1.0 }, { PTR_ANIM_death_explosion_back_left, 0, 0.5, 8.0, 14.0, 25.0, -1.0 }, { PTR_ANIM_death_explosion_back_left, 1, 0.5, 8.0, 14.0, 25.0, -1.0 }, { PTR_ANIM_death_explosion_back1, 0, 0.5, 8.0, 19.0, 25.0, -1.0 }, { PTR_ANIM_death_explosion_back1, 1, 0.5, 8.0, 19.0, 25.0, -1.0 }, { PTR_ANIM_death_explosion_back2, 0, 0.5, 12.0, 21.0, 29.0, -1.0 }, { PTR_ANIM_death_explosion_back2, 1, 0.5, 12.0, 21.0, 29.0, -1.0 }, { PTR_ANIM_death_explosion_left2, 0, 0.5, 22.0, 30.0, 41.0, -1.0 }, { PTR_ANIM_death_explosion_left2, 1, 0.5, 22.0, 30.0, 41.0, -1.0 }, {0, 0, 0.5, 0.0, 0.0, 0.0, -1.0}, }; s8 expl_forward[] = {0x0, 0x01, 0x02, 0x03, 0x4, 0x05, 0x00, 0x00}; s8 expl_f_left[] = {0x7, 0x09, 0x0B, 0x00}; s8 expl_f_right[] = {0x06, 0x08, 0x0A, 0x00}; s8 expl_left[] = {0x0C, 0x0F, 0x11, 0x00}; s8 expl_right[] = {0x0D, 0x0E, 0x10, 0x00}; s8 expl_back[] = {0x14, 0x15, 0x16, 0x17}; s8 expl_b_right[] = {0x12, 0x18, 0x00, 0x00}; s8 expl_b_left[] = {0x13, 0x19, 0x00, 0x00}; struct explosion_anim_group_info explosion_animation_table[EXPLOSION_ANIMATION_TABLE_LEN] = { {expl_forward, 6}, {expl_f_left, 3}, {expl_left, 3}, {expl_b_right, 2}, {expl_back, 4}, {expl_b_left, 2}, {expl_right, 3}, {expl_f_right, 3} }; struct weapon_firing_animation_table rifle_firing_animation_group1[] = { { PTR_ANIM_fire_standing_fast, 28.0, 0, 0, 0, -1.0, 23.0, 54.0, -1.0, -1.0, 18.0, 54.0, 0.87266463, -0.52359879, 1.0471976, -0.34906587, 1.6, 1.8 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_rifle_firing_animation_group1 = { &rifle_firing_animation_group1, -1 }; struct weapon_firing_animation_table rifle_firing_animation_group2[] = { { PTR_ANIM_fire_standing, 37.0, 0, 0, 0, -1.0, 30.0, 81.0, -1.0, -1.0, 25.0, 81.0, 0.87266463, -0.69813174, 0.69813174, -0.69813174, 1.6, 1.75 }, { PTR_ANIM_fire_hip, 27.0, 0, 0, 0, -1.0, 22.0, 61.0, -1.0, -1.0, 17.0, 61.0, 0.87266463, -0.2617994, 0.69813174, -0.69813174, 2.0, 1.0 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_rifle_firing_animation_group2 = { &rifle_firing_animation_group2, -1 }; struct weapon_firing_animation_table rifle_firing_animation_group5[] = { { PTR_ANIM_fire_standing, 37.0, 0, 0, 0, -1.0, 30.0, 81.0, -1.0, -1.0, 25.0, 81.0, 0.87266463, -0.69813174, 0.69813174, -0.69813174, 1.6, 1.75 }, { PTR_ANIM_fire_hip, 27.0, 0, 0, 0, -1.0, 22.0, 61.0, -1.0, -1.0, 17.0, 61.0, 0.87266463, -0.2617994, 0.69813174, -0.69813174, 2.0, 1.0 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_rifle_firing_animation_group5 = { &rifle_firing_animation_group5, -1 }; struct weapon_firing_animation_table rifle_firing_animation_group3[] = { { PTR_ANIM_fire_shoulder_left, 19.0, 0, 1.5707964, 0, -1.0, 19.0, 61.0, -1.0, -1.0, 14.0, 61.0, 0.87266463, -0.34906587, 0.43633232, -1.0471976, 2.5, 2.5 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_rifle_firing_animation_group3 = { &rifle_firing_animation_group3, -1 }; struct weapon_firing_animation_table rifle_firing_animation_group4[] = { { PTR_ANIM_fire_turn_right2, 27.0, 0, 0, 0, -1.0, 39.0, 74.0, -1.0, -1.0, 34.0, 74.0, 0.87266463, -0.69813174, 0.78539819, -0.69813174, 1.5, 1.5 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_rifle_firing_animation_group4 = { &rifle_firing_animation_group4, -1 }; struct anim_group_info *ptr_rifle_firing_animation_groups[] = { &ptr_rifle_firing_animation_group1, &ptr_rifle_firing_animation_group2, &ptr_rifle_firing_animation_group2, &ptr_rifle_firing_animation_group2, &ptr_rifle_firing_animation_group2, &ptr_rifle_firing_animation_group2, &ptr_rifle_firing_animation_group2, &ptr_rifle_firing_animation_group2, &ptr_rifle_firing_animation_group2, &ptr_rifle_firing_animation_group2, &ptr_rifle_firing_animation_group3, &ptr_rifle_firing_animation_group3, &ptr_rifle_firing_animation_group3, &ptr_rifle_firing_animation_group3, &ptr_rifle_firing_animation_group3, &ptr_rifle_firing_animation_group3, &ptr_rifle_firing_animation_group4, &ptr_rifle_firing_animation_group4, &ptr_rifle_firing_animation_group4, &ptr_rifle_firing_animation_group4, &ptr_rifle_firing_animation_group4, &ptr_rifle_firing_animation_group4, &ptr_rifle_firing_animation_group5, &ptr_rifle_firing_animation_group5, &ptr_rifle_firing_animation_group5, &ptr_rifle_firing_animation_group5, &ptr_rifle_firing_animation_group5, &ptr_rifle_firing_animation_group5, &ptr_rifle_firing_animation_group5, &ptr_rifle_firing_animation_group5, &ptr_rifle_firing_animation_group5, &ptr_rifle_firing_animation_group1 }; struct weapon_firing_animation_table pistol_firing_animation_group1[] = { { PTR_ANIM_fire_standing_one_handed_weapon, 26.0, 0, 0, 12.0, 140.0, 58.0, 92.0, 60.0, 79.0, 20.0, 120.0, 0.87266463, -0.69813174, 0.69813174, -0.69813174, 0.0, 0.0 }, { PTR_ANIM_fire_hip_one_handed_weapon_fast, 0.0, 0, 0, 17.0, 100.0, 25.0, 87.0, 30.0, 55.0, 20.0, 93.0, 0.87266463, -0.69813174, 0.69813174, -1.0471976, 0.0, 0.0 }, { PTR_ANIM_fire_hip_one_handed_weapon_slow, 0.0, 0, 0, 12.0, 64.0, 19.0, 51.0, 24.0, 46.0, 14.0, 58.0, 0.87266463, -0.69813174, 0.52359879, -0.78539819, 0.0, 0.0 }, { PTR_ANIM_fire_hip_forward_one_handed_weapon, 22.0, 0, 0, 4.0, 69.0, 22.0, 49.0, 22.0, 33.0, 8.0, 58.0, 0.87266463, -0.69813174, 0.43633232, -0.78539819, 0.0, 0.0 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_pistol_firing_animation_group1 = { &pistol_firing_animation_group1, -1 }; struct weapon_firing_animation_table pistol_firing_animation_group2[] = { { PTR_ANIM_fire_standing_one_handed_weapon, 26.0, 0, 0, 12.0, 140.0, 58.0, 92.0, 60.0, 79.0, 20.0, 120.0, 0.87266463, -0.69813174, 0.69813174, -0.69813174, 0.0, 0.0 }, { PTR_ANIM_fire_hip_forward_one_handed_weapon, 22.0, 0, 0, 4.0, 69.0, 22.0, 49.0, 22.0, 33.0, 8.0, 58.0, 0.87266463, -0.69813174, 0.43633232, -0.78539819, 0.0, 0.0 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_pistol_firing_animation_group2 = { &pistol_firing_animation_group2, -1 }; struct weapon_firing_animation_table pistol_firing_animation_group3[] = { { PTR_ANIM_fire_standing_one_handed_weapon, 26.0, 0, 0, 12.0, 140.0, 58.0, 92.0, 60.0, 79.0, 20.0, 120.0, 0.87266463, -0.69813174, 0.69813174, -0.69813174, 0.0, 0.0 }, { PTR_ANIM_fire_hip_forward_one_handed_weapon, 22.0, 0, 0, 4.0, 69.0, 22.0, 49.0, 22.0, 33.0, 8.0, 58.0, 0.87266463, -0.69813174, 0.43633232, -0.78539819, 0.0, 0.0 }, { PTR_ANIM_fire_standing_left_one_handed_weapon_slow, 0.0, 0, 1.5707964, 7.0, 130.0, 45.0, 93.0, 56.0, 73.0, 26.0, 107.0, 0.87266463, -0.69813174, 0.34906587, -0.52359879, 0.0, 0.0 }, { PTR_ANIM_fire_standing_left_one_handed_weapon_fast, 15.0, 0, 1.5707964, 5.0, 76.0, 20.0, 31.0, 31.0, 38.0, 15.0, 49.0, 0.87266463, -0.69813174, 0.52359879, -1.0471976, 0.0, 0.0 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_pistol_firing_animation_group3 = { &pistol_firing_animation_group3, -1 }; struct weapon_firing_animation_table pistol_firing_animation_group6[] = { { PTR_ANIM_fire_standing_one_handed_weapon, 26.0, 0, 0, 12.0, 140.0, 58.0, 92.0, 60.0, 79.0, 20.0, 120.0, 0.87266463, -0.69813174, 0.69813174, -0.69813174, 0.0, 0.0 }, { PTR_ANIM_fire_hip_forward_one_handed_weapon, 22.0, 0, 0, 4.0, 69.0, 22.0, 49.0, 22.0, 33.0, 8.0, 58.0, 0.87266463, -0.69813174, 0.43633232, -0.78539819, 0.0, 0.0 }, { PTR_ANIM_fire_standing_right_one_handed_weapon, 0.0, 0, 4.712389, 7.0, 139.0, 54.0, 105.0, 61.0, 88.0, 26.0, 120.0, 0.87266463, -0.69813174, 0.69813174, -0.61086529, 0.0, 0.0 }, { PTR_ANIM_fire_step_right_one_handed_weapon, 19.0, 0, 4.712389, 4.0, 79.0, 21.0, 50.0, 26.0, 42.0, 10.0, 64.0, 0.87266463, -0.69813174, 0.69813174, -0.61086529, 0.0, 0.0 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_pistol_firing_animation_group6 = { &pistol_firing_animation_group6, -1 }; struct weapon_firing_animation_table pistol_firing_animation_group4[] = { { PTR_ANIM_fire_standing_left_one_handed_weapon_fast, 19.0, 0, 1.5707964, 5.0, 76.0, 20.0, 31.0, 31.0, 38.0, 15.0, 49.0, 0.87266463, -0.69813174, 0.52359879, -1.0471976, 0.0, 0.0 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_pistol_firing_animation_group4 = { &pistol_firing_animation_group4, -1 }; struct weapon_firing_animation_table pistol_firing_animation_group5[] = { { PTR_ANIM_fire_step_right_one_handed_weapon, 19.0, 0, 4.712389, 4.0, 79.0, 21.0, 50.0, 26.0, 42.0, 10.0, 64.0, 0.87266463, -0.69813174, 0.69813174, -0.61086529, 0.0, 0.0 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_pistol_firing_animation_group5 = { &pistol_firing_animation_group5, -1 }; struct anim_group_info *ptr_pistol_firing_animation_groups[] = { &ptr_pistol_firing_animation_group1, &ptr_pistol_firing_animation_group1, &ptr_pistol_firing_animation_group2, &ptr_pistol_firing_animation_group2, &ptr_pistol_firing_animation_group2, &ptr_pistol_firing_animation_group3, &ptr_pistol_firing_animation_group3, &ptr_pistol_firing_animation_group3, &ptr_pistol_firing_animation_group3, &ptr_pistol_firing_animation_group3, &ptr_pistol_firing_animation_group4, &ptr_pistol_firing_animation_group4, &ptr_pistol_firing_animation_group4, &ptr_pistol_firing_animation_group4, &ptr_pistol_firing_animation_group4, &ptr_pistol_firing_animation_group4, &ptr_pistol_firing_animation_group5, &ptr_pistol_firing_animation_group5, &ptr_pistol_firing_animation_group5, &ptr_pistol_firing_animation_group5, &ptr_pistol_firing_animation_group5, &ptr_pistol_firing_animation_group5, &ptr_pistol_firing_animation_group6, &ptr_pistol_firing_animation_group6, &ptr_pistol_firing_animation_group6, &ptr_pistol_firing_animation_group6, &ptr_pistol_firing_animation_group6, &ptr_pistol_firing_animation_group2, &ptr_pistol_firing_animation_group2, &ptr_pistol_firing_animation_group2, &ptr_pistol_firing_animation_group1, &ptr_pistol_firing_animation_group1 }; struct weapon_firing_animation_table doubles_firing_animation_group1[] = { { PTR_ANIM_fire_standing_dual_wield, 26.0, 0, 0, 7.0, 92.0, 28.0, 68.0, -1.0, -1.0, 11.0, 73.0, 0.87266463, -0.69813174, 0.69813174, -0.69813174, 0.0, 0.0 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_doubles_firing_animation_group1 = { &doubles_firing_animation_group1, -1 }; struct weapon_firing_animation_table doubles_firing_animation_group2[] = { { PTR_ANIM_fire_standing_dual_wield_left, 26.0, 0, 1.5707964, 9.0, 112.0, 38.0, 87.0, -1.0, -1.0, 19.0, 98.0, 0.87266463, -0.69813174, 0.43633232, -0.43633232, 0.0, 0.0 }, { PTR_ANIM_fire_standing_dual_wield_hands_crossed_left, 25.0, 0, 1.5707964, 10.0, 112.0, 32.0, 86.0, -1.0, -1.0, 19.0, 97.0, 0.87266463, -0.69813174, 0.43633232, -0.43633232, 0.0, 0.0 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_doubles_firing_animation_group2 = { &doubles_firing_animation_group2, -1 }; struct weapon_firing_animation_table doubles_firing_animation_group3[] = { { PTR_ANIM_fire_standing_dual_wield_right, 39.0, 0, 4.712389, 22.0, 127.0, 44.0, 102.0, -1.0, -1.0, 28.0, 112.0, 0.87266463, -0.69813174, 0.43633232, -0.43633232, 0.0, 0.0 }, { PTR_ANIM_fire_standing_dual_wield_hands_crossed_right, 39.0, 0, 4.712389, 23.0, 130.0, 46.0, 100.0, -1.0, -1.0, 30.0, 110.0, 0.87266463, -0.69813174, 0.43633232, -0.43633232, 0.0, 0.0 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_doubles_firing_animation_group3 = { &doubles_firing_animation_group3, -1 }; struct anim_group_info *ptr_doubles_firing_animation_groups[] = { &ptr_doubles_firing_animation_group1, &ptr_doubles_firing_animation_group1, &ptr_doubles_firing_animation_group1, &ptr_doubles_firing_animation_group1, &ptr_doubles_firing_animation_group1, &ptr_doubles_firing_animation_group2, &ptr_doubles_firing_animation_group2, &ptr_doubles_firing_animation_group2, &ptr_doubles_firing_animation_group2, &ptr_doubles_firing_animation_group2, &ptr_doubles_firing_animation_group2, &ptr_doubles_firing_animation_group2, &ptr_doubles_firing_animation_group2, &ptr_doubles_firing_animation_group2, &ptr_doubles_firing_animation_group2, &ptr_doubles_firing_animation_group2, &ptr_doubles_firing_animation_group3, &ptr_doubles_firing_animation_group3, &ptr_doubles_firing_animation_group3, &ptr_doubles_firing_animation_group3, &ptr_doubles_firing_animation_group3, &ptr_doubles_firing_animation_group3, &ptr_doubles_firing_animation_group3, &ptr_doubles_firing_animation_group3, &ptr_doubles_firing_animation_group3, &ptr_doubles_firing_animation_group3, &ptr_doubles_firing_animation_group3, &ptr_doubles_firing_animation_group1, &ptr_doubles_firing_animation_group1, &ptr_doubles_firing_animation_group1, &ptr_doubles_firing_animation_group1, &ptr_doubles_firing_animation_group1 }; #ifdef PORT /* D445 (ABI/layout, porting-notes §D5 linker adjacency): on the N64, * crouched_rifle_firing_animation_group1 has NO terminator and the linker * places crouched_rifle_firing_animation_groupA right after it, so the one * resolver pass over group1 (initResolveAnimGroupTable, via * ptr_crouched_rifle_firing_animation_groups) walks into groupA and turns its * anim offset into a pointer too; the table len is 2. GCC does not keep the * two arrays adjacent (x86-64: groupA BELOW group1), so groupA[0] kept the raw * offset 0xB84 (PTR_ANIM_fire_kneel_left_leg) and playerTick handed it to * modelSetAnimation as a ModelAnimation* (SIGSEGV, crouched rifle fire), and * crouching rifle guards saw len 1 instead of 2. One array restores the N64 * layout; groupA is its second entry (chr.h). Same data, same order. */ struct weapon_firing_animation_table crouched_rifle_firing_animation_group1[] = { { PTR_ANIM_fire_kneel_right_leg, 27.0, 0, 0, 0, -1.0, 35.0, 75.0, -1.0, -1.0, 31.0, 75.0, 0.87266463, -0.69813174, 0.90757126, -0.69813174, 1.5, 1.5 }, /* = crouched_rifle_firing_animation_groupA[0] */ { PTR_ANIM_fire_kneel_left_leg, 24.0, 0, 0, 0, -1.0, 46.0, 98.0, -1.0, -1.0, 41.0, 98.0, 0.87266463, -0.52359879, 1.134464, -0.69813174, 1.6, 1.6 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; #else struct weapon_firing_animation_table crouched_rifle_firing_animation_group1[] = { { PTR_ANIM_fire_kneel_right_leg, 27.0, 0, 0, 0, -1.0, 35.0, 75.0, -1.0, -1.0, 31.0, 75.0, 0.87266463, -0.69813174, 0.90757126, -0.69813174, 1.5, 1.5 }, }; struct weapon_firing_animation_table crouched_rifle_firing_animation_groupA[] = { { PTR_ANIM_fire_kneel_left_leg, 24.0, 0, 0, 0, -1.0, 46.0, 98.0, -1.0, -1.0, 41.0, 98.0, 0.87266463, -0.52359879, 1.134464, -0.69813174, 1.6, 1.6 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; #endif struct anim_group_info ptr_crouched_rifle_firing_animation_group1 = { &crouched_rifle_firing_animation_group1, -1 }; struct weapon_firing_animation_table crouched_rifle_firing_animation_group2[] = { { PTR_ANIM_fire_kneel_left, 26.0, 0, 0, 0, -1.0, 34.0, 87.0, -1.0, -1.0, 29.0, 87.0, 0.87266463, -0.52359879, 0.69813174, -0.95993108, 1.6, 2.0 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_crouched_rifle_firing_animation_group2 = { &crouched_rifle_firing_animation_group2, -1 }; struct weapon_firing_animation_table crouched_rifle_firing_animation_group3[] = { { PTR_ANIM_fire_kneel_right, 28.0, 0, 0, 0, -1.0, 36.0, 88.0, -1.0, -1.0, 31.0, 88.0, 0.87266463, -0.69813174, 0.87266463, -0.43633232, 1.6, 1.5 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_crouched_rifle_firing_animation_group3 = { &crouched_rifle_firing_animation_group3, -1 }; struct anim_group_info *ptr_crouched_rifle_firing_animation_groups[] = { &ptr_crouched_rifle_firing_animation_group1, &ptr_crouched_rifle_firing_animation_group1, &ptr_crouched_rifle_firing_animation_group1, &ptr_crouched_rifle_firing_animation_group1, &ptr_crouched_rifle_firing_animation_group1, &ptr_crouched_rifle_firing_animation_group1, &ptr_crouched_rifle_firing_animation_group1, &ptr_crouched_rifle_firing_animation_group1, &ptr_crouched_rifle_firing_animation_group1, &ptr_crouched_rifle_firing_animation_group1, &ptr_crouched_rifle_firing_animation_group2, &ptr_crouched_rifle_firing_animation_group2, &ptr_crouched_rifle_firing_animation_group2, &ptr_crouched_rifle_firing_animation_group2, &ptr_crouched_rifle_firing_animation_group2, &ptr_crouched_rifle_firing_animation_group2, &ptr_crouched_rifle_firing_animation_group3, &ptr_crouched_rifle_firing_animation_group3, &ptr_crouched_rifle_firing_animation_group3, &ptr_crouched_rifle_firing_animation_group3, &ptr_crouched_rifle_firing_animation_group3, &ptr_crouched_rifle_firing_animation_group3, &ptr_crouched_rifle_firing_animation_group1, &ptr_crouched_rifle_firing_animation_group1, &ptr_crouched_rifle_firing_animation_group1, &ptr_crouched_rifle_firing_animation_group1, &ptr_crouched_rifle_firing_animation_group1, &ptr_crouched_rifle_firing_animation_group1, &ptr_crouched_rifle_firing_animation_group1, &ptr_crouched_rifle_firing_animation_group1, &ptr_crouched_rifle_firing_animation_group1, &ptr_crouched_rifle_firing_animation_group1 }; struct weapon_firing_animation_table crouched_pistol_firing_animation_group1[] = { { PTR_ANIM_fire_kneel_forward_one_handed_weapon_slow, 25.0, 0, 0, 12.0, 132.0, 55.0, 87.0, 67.0, 87.0, 26.0, 111.0, 0.87266463, -0.69813174, 0.61086529, -0.78539819, 0.0, 0.0 }, { PTR_ANIM_fire_kneel_forward_one_handed_weapon_fast, 26.0, 0, 0, 8.0, 89.0, 31.0, 63.0, 41.0, 51.0, 21.0, 80.0, 0.87266463, -0.69813174, 0.34906587, -1.134464, 0.0, 0.0 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_crouched_pistol_firing_animation_group1 = { &crouched_pistol_firing_animation_group1, -1 }; struct weapon_firing_animation_table crouched_pistol_firing_animation_group2[] = { { PTR_ANIM_fire_kneel_left_one_handed_weapon_slow, 47.0, 0, 1.5707964, 7.0, 128.0, 33.0, 86.0,47.0, 74.0, 23.0, 106.0, 0.87266463, -0.52359879, 0.52359879, -0.78539819, 0.0, 0.0 }, { PTR_ANIM_fire_kneel_left_one_handed_weapon_fast, 18.0, 0, 1.5707964, 7.0, 78.0, 28.0, 52.0, 35.0, 45.0, 15.0, 66.0, 0.87266463, -0.087266468, 0.69813174, -0.78539819, 1.5, 1.0 }, { PTR_ANIM_fire_kneel_left_one_handed_weapon, 20.0, 0, 1.5707964, 13.0, 92.0, 37.0, 67.0, 42.0, 55.0, 25.0, 84.0, 0.87266463, -0.52359879, 0.34906587, -0.69813174, 0.0, 0.0 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_crouched_pistol_firing_animation_group2 = { &crouched_pistol_firing_animation_group2, -1 }; struct weapon_firing_animation_table crouched_pistol_firing_animation_group3[] = { { PTR_ANIM_fire_kneel_right_one_handed_weapon_slow, 28.0, 0, 4.712389, 15.0, 124.0, 38.0, 97.0, 60.0, 84.0, 20.0, 106.0, 0.87266463, -0.69813174, 0.52359879, -0.87266463, 0.0, 0.0 }, { PTR_ANIM_fire_kneel_right_one_handed_weapon_fast, 23.0, 0, 4.712389, 0, 85.0, 32.0, 38.0, 38.0, 60.0, 14.0, 71.0, 0.87266463, -0.69813174, 0.61086529, -0.95993108, 0.0, 0.0 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_crouched_pistol_firing_animation_group3 = { &crouched_pistol_firing_animation_group3, -1 }; struct anim_group_info *ptr_crouched_pistol_firing_animation_groups[] = { &ptr_crouched_pistol_firing_animation_group1, &ptr_crouched_pistol_firing_animation_group1, &ptr_crouched_pistol_firing_animation_group1, &ptr_crouched_pistol_firing_animation_group1, &ptr_crouched_pistol_firing_animation_group1, &ptr_crouched_pistol_firing_animation_group1, &ptr_crouched_pistol_firing_animation_group1, &ptr_crouched_pistol_firing_animation_group1, &ptr_crouched_pistol_firing_animation_group1, &ptr_crouched_pistol_firing_animation_group1, &ptr_crouched_pistol_firing_animation_group2, &ptr_crouched_pistol_firing_animation_group2, &ptr_crouched_pistol_firing_animation_group2, &ptr_crouched_pistol_firing_animation_group2, &ptr_crouched_pistol_firing_animation_group2, &ptr_crouched_pistol_firing_animation_group2, &ptr_crouched_pistol_firing_animation_group3, &ptr_crouched_pistol_firing_animation_group3, &ptr_crouched_pistol_firing_animation_group3, &ptr_crouched_pistol_firing_animation_group3, &ptr_crouched_pistol_firing_animation_group3, &ptr_crouched_pistol_firing_animation_group3, &ptr_crouched_pistol_firing_animation_group1, &ptr_crouched_pistol_firing_animation_group1, &ptr_crouched_pistol_firing_animation_group1, &ptr_crouched_pistol_firing_animation_group1, &ptr_crouched_pistol_firing_animation_group1, &ptr_crouched_pistol_firing_animation_group1, &ptr_crouched_pistol_firing_animation_group1, &ptr_crouched_pistol_firing_animation_group1, &ptr_crouched_pistol_firing_animation_group1, &ptr_crouched_pistol_firing_animation_group1 }; struct weapon_firing_animation_table crouched_doubles_firing_animation_group1[] = { { PTR_ANIM_fire_kneel_dual_wield, 22.0, 0, 0, 10.0, 111.0, 34.0, 87.0, -1.0, -1.0, 17.0, 104.0, 0.87266463, -0.69813174, 0.61086529, -0.78539819, 0.0, 0.0 }, { PTR_ANIM_fire_kneel_dual_wield_hands_crossed, 25.0, 0, 0, 9.0, 92.0, 33.0, 62.0, -1.0, -1.0, 18.0, 69.0, 0.87266463, -0.69813174, 0.61086529, -0.78539819, 0.0, 0.0 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_crouched_doubles_firing_animation_group1 = { &crouched_doubles_firing_animation_group1, -1 }; struct weapon_firing_animation_table crouched_doubles_firing_animation_group2[] = { { PTR_ANIM_fire_kneel_dual_wield_left, 28.0, 0, 1.5707964, 15.0, 108.0, 34.0, 73.0, -1.0, -1.0, 17.0, 93.0, 0.87266463, -0.69813174, 0.52359879, -0.78539819, 0.0, 0.0 }, { PTR_ANIM_fire_kneel_dual_wield_hands_crossed_left, 19.0, 0, 1.5707964, 3.0, 95.0, 30.0, 64.0, -1.0, -1.0, 14.0, 71.0, 0.87266463, -0.69813174, 0.52359879, -0.78539819, 1.5, 1.0 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_crouched_doubles_firing_animation_group2 = { &crouched_doubles_firing_animation_group2, -1 }; struct weapon_firing_animation_table crouched_doubles_firing_animation_group3[] = { { PTR_ANIM_fire_kneel_dual_wield_right, 31.0, 0, 4.712389, 14.0, 111.0, 40.0, 83.0,-1.0, -1.0, 21.0, 94.0, 0.87266463, -0.69813174, 0.52359879, -0.78539819, 0.0, 0.0 }, { PTR_ANIM_fire_kneel_dual_wield_hands_crossed_right, 26.0, 0, 4.712389, 7.0, 89.0, 34.0, 60.0, -1.0, -1.0, 20.0, 68.0, 0.87266463, -0.69813174, 0.52359879, -0.78539819, 0.0, 0.0 }, {0, 0.0, 0, 0, 0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct anim_group_info ptr_crouched_doubles_firing_animation_group3 = { &crouched_doubles_firing_animation_group3, -1 }; struct anim_group_info* ptr_crouched_doubles_firing_animation_groups[] = { &ptr_crouched_doubles_firing_animation_group1, &ptr_crouched_doubles_firing_animation_group1, &ptr_crouched_doubles_firing_animation_group1, &ptr_crouched_doubles_firing_animation_group1, &ptr_crouched_doubles_firing_animation_group1, &ptr_crouched_doubles_firing_animation_group1, &ptr_crouched_doubles_firing_animation_group1, &ptr_crouched_doubles_firing_animation_group1, &ptr_crouched_doubles_firing_animation_group1, &ptr_crouched_doubles_firing_animation_group1, &ptr_crouched_doubles_firing_animation_group2, &ptr_crouched_doubles_firing_animation_group2, &ptr_crouched_doubles_firing_animation_group2, &ptr_crouched_doubles_firing_animation_group2, &ptr_crouched_doubles_firing_animation_group2, &ptr_crouched_doubles_firing_animation_group2, &ptr_crouched_doubles_firing_animation_group3, &ptr_crouched_doubles_firing_animation_group3, &ptr_crouched_doubles_firing_animation_group3, &ptr_crouched_doubles_firing_animation_group3, &ptr_crouched_doubles_firing_animation_group3, &ptr_crouched_doubles_firing_animation_group3, &ptr_crouched_doubles_firing_animation_group1, &ptr_crouched_doubles_firing_animation_group1, &ptr_crouched_doubles_firing_animation_group1, &ptr_crouched_doubles_firing_animation_group1, &ptr_crouched_doubles_firing_animation_group1, &ptr_crouched_doubles_firing_animation_group1, &ptr_crouched_doubles_firing_animation_group1, &ptr_crouched_doubles_firing_animation_group1, &ptr_crouched_doubles_firing_animation_group1, &ptr_crouched_doubles_firing_animation_group1 }; struct weapon_firing_animation_table D_80030078[] = { // sizeof(struct weapon_firing_animation_table) = 0x48 = 72. // address 0xD_80030078. Index 0, = D_80030078 + 0. { PTR_ANIM_fire_roll_left, 76.0, 0.0, 0.0, 20.0, -1.0, 98.0, 161.0, -1.0, -1.0, 93.0, 161.0, 0.87266463, -0.52359879, 0.69813174, -0.69813174, 1.7, 2.0 }, // address 0x800300C0. Index 1, = D_80030078 + 72. { PTR_ANIM_fire_roll_right1, 58.0, 0.0, 0.0, 10.0, -1.0, 77.0, 104.0, -1.0, -1.0, 72.0, 104.0, 0.87266463, -0.34906587, 0.61086529, -0.69813174, 1.55, 1.5 }, // address 0x80030108. Index 2, = D_80030078 + 144. { PTR_ANIM_fire_roll_left_fast, 61.0, 0.0, 0.0, 10.0, -1.0, 83.0, 128.0, -1.0, -1.0, 78.0, 128.0, 0.87266463, -0.52359879, 0.87266463, -0.52359879, 1.2, 1.3 }, // address 0x80030150. Index 3, = D_80030078 + 216. { PTR_ANIM_fire_roll_right2, 63.0, 0.0, 0.0, 10.0, -1.0, 73.0, 114.0, -1.0, -1.0, 68.0, 114.0, 0.87266463, -0.52359879, 0.61086529, -0.61086529, 1.65, 1.5 }, // address 0x80030198. Index 4, = D_80030078 + 288. { PTR_ANIM_fire_roll_left, 76.0, 0.0, 0.0, 20.0, 76.0, 98.0, 161.0, -1.0, -1.0, 93.0, 161.0, 0.87266463, -0.52359879, 0.69813174, -0.69813174, 1.7, 2.0 }, // address 0x800301E0. Index 5, = D_80030078 + 360. { PTR_ANIM_fire_roll_right1, 58.0, 0.0, 0.0, 10.0, 63.0, 77.0, 104.0, -1.0, -1.0, 72.0, 104.0, 0.87266463, -0.34906587, 0.61086529, -0.69813174, 1.55, 1.5 }, // address 0x80030228. Index 6, = D_80030078 + 432. { PTR_ANIM_fire_roll_left_fast, 61.0, 0.0, 0.0, 10.0, 56.0, 83.0, 128.0, -1.0, -1.0, 78.0, 128.0, 0.87266463, -0.52359879, 0.87266463, -0.52359879, 1.2, 1.3 }, // address 0x80030270. Index 7, = D_80030078 + 504. { PTR_ANIM_fire_roll_right2, 63.0, 0.0, 0.0, 10.0, 50.0, 73.0, 114.0, -1.0, -1.0, 68.0, 114.0, 0.87266463, -0.52359879, 0.61086529, -0.61086529, 1.65, 1.5 }, // address 0x800302B8. Index 8, = D_80030078 + 576. { PTR_ANIM_fire_hip_one_handed_weapon_slow, 0.0, 0.0, 0.0, 7.0, 64.0, 19.0, 51.0, 24.0, 46.0, 14.0, 58.0, 0.87266463, -0.69813174, 0.52359879, -0.78539819, 0.0, 0.0 }, // address 0x80030300. Index 9, = D_80030078 + 648. { PTR_ANIM_fire_standing_left_one_handed_weapon_fast, 0.0, 0.0, 1.5707964, 14.0, 76.0, 26.0, 31.0, 31.0, 38.0, 15.0, 49.0, 0.87266463, -0.69813174, 0.52359879, -1.0471976, 0.0, 0.0 }, // address 0x80030348. Index 10, = D_80030078 + 720. { PTR_ANIM_fire_kneel_forward_one_handed_weapon_fast, 26.0, 0.0, 0.0, 25.0, 89.0, 41.0, 63.0, 41.0, 51.0, 21.0, 80.0, 0.87266463, -0.69813174, 0.34906587, -1.134464, 0.0, 0.0 }, // address 0x80030390. Index 11, = D_80030078 + 792. { PTR_ANIM_fire_kneel_left_one_handed_weapon_fast, 18.0, 0.0, 1.5707964, 11.0, 78.0, 33.0, 52.0, 35.0, 45.0, 15.0, 66.0, 0.87266463, -0.087266468, 0.69813174, -0.78539819, 1.5, 1.0 }, // address 0x800303D8. Index 12, = D_80030078 + 864. { PTR_ANIM_fire_standing_dual_wield, 26.0, 0.0, 0.0, 7.0, 92.0, 28.0, 68.0, -1.0, -1.0, 11.0, 73.0, 0.87266463, -0.69813174, 0.69813174, -0.69813174, 0.0, 0.0 }, // address 0x80030420. Index 13, = D_80030078 + 936. { PTR_ANIM_fire_standing_dual_wield_left, 26.0, 0.0, 1.5707964, 9.0, 112.0, 38.0, 87.0, -1.0, -1.0, 19.0, 98.0, 0.87266463, -0.69813174, 0.43633232, -0.43633232, 0.0, 0.0 }, // address 0x80030468. Index 14, = D_80030078 + 1008. { PTR_ANIM_fire_kneel_dual_wield, 22.0, 0.0, 0.0, 10.0, 11.0, 34.0, 87.0, -1.0, -1.0, 17.0, 104.0, 0.87266463, -0.69813174, 0.61086529, -0.78539819, 0.0, 0.0 }, // address 0x800304B0. Index 15, = D_80030078 + 1080. { PTR_ANIM_fire_kneel_dual_wield_left, 28.0, 0.0, 1.5707964, 15.0, 108.0, 34.0, 73.0, -1.0, -1.0, 17.0, 93.0, 0.87266463, -0.69813174, 0.52359879, -0.78539819, 0.0, 0.0 }, // address 0x800304F8. Index 16, = D_80030078 + 1152. { PTR_ANIM_fire_standing_dual_wield, 26.0, 0.0, 0.0, 7.0, 92.0, 28.0, 68.0, -1.0, -1.0, 11.0, 73.0, 0.87266463, -0.69813174, 0.69813174, -0.69813174, 0.0, 0.0 }, // address 0x80030540. Index 17, = D_80030078 + 1224. { PTR_ANIM_fire_standing_dual_wield_hands_crossed_left, 25.0, 0.0, 1.5707964, 10.0, 112.0, 32.0, 86.0, -1.0, -1.0, 19.0, 97.0, 0.87266463, -0.69813174, 0.43633232, -0.43633232, 0.0, 0.0 }, // address 0x80030588. Index 18, = D_80030078 + 1296. { PTR_ANIM_fire_kneel_dual_wield_hands_crossed, 25.0, 0.0, 0.0, 9.0, 92.0, 33.0, 62.0, -1.0, -1.0, 18.0, 69.0, 0.87266463, -0.69813174, 0.61086529, -0.78539819, 0.0, 0.0 }, // address 0x800305D0. Index 19, = D_80030078 + 1368. { PTR_ANIM_fire_kneel_dual_wield_hands_crossed_left, 19.0, 0.0, 1.5707964, 3.0, 95.0, 30.0, 64.0, -1.0, -1.0, 14.0, 71.0, 0.87266463, -0.69813174, 0.52359879, -0.78539819, 1.5, 1.0 }, // address 0x80030618. Index 20, = D_80030078 + 1440. {0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; struct weapon_firing_animation_table D_80030660[] = { // address 0x80030660. Index 0, = D_80030660 + 0. { PTR_ANIM_fire_walking, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, -1.0, 0.0, 0.0, 0.87266463, -0.52359879, 0.52359879, -0.52359879, 1.4, 1.3 }, // address 0x800306A8. Index 1, = D_80030660 + 72. { PTR_ANIM_fire_running, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, -1.0, 0.0, 0.0, 0.87266463, -0.52359879, 0.52359879, -0.52359879, 1.1, 1.2 }, // address 0x800306F0. Index 2, = D_80030660 + 144. { PTR_ANIM_aim_walking_one_handed_weapon, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, -1.0, 0.0, 0.0, 0.87266463, -0.52359879, 0.52359879, -0.52359879, 0.0, 0.0 }, // address 0x80030738. Index 3, = D_80030660 + 216. { PTR_ANIM_aim_running_one_handed_weapon, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, -1.0, 0.0, 0.0, 0.87266463, -0.52359879, 0.52359879, -0.52359879, 0.0, 0.0 }, // address 0x80030780. Index 4, = D_80030660 + 288. { PTR_ANIM_fire_walking_dual_wield, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, -1.0, 0.0, 0.0, 0.87266463, -0.52359879, 0.52359879, -0.52359879, 0.0, 0.0 }, // address 0x800307C8. Index 5, = D_80030660 + 360. { PTR_ANIM_fire_running_dual_wield, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, -1.0, 0.0, 0.0, 0.87266463, -0.52359879, 0.52359879, -0.52359879, 0.0, 0.0 }, // address 0x80030810. Index 6, = D_80030660 + 432. { PTR_ANIM_fire_walking_dual_wield_hands_crossed, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, -1.0, 0.0, 0.0, 0.87266463, -0.52359879, 0.52359879, -0.52359879, 0.0, 0.0 }, // address 0x80030858. Index 7, = D_80030660 + 504. { PTR_ANIM_fire_running_dual_wield_hands_crossed, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, -1.0, 0.0, 0.0, 0.87266463, -0.52359879, 0.52359879, -0.52359879, 0.0, 0.0 }, // address 0x800308A0. Index 8, = D_80030660 + 576. { PTR_ANIM_aim_running_left_one_handed_weapon, 0.0, 0.0, 1.5707964, 0.0, -1.0, 0.0, 0.0, -1.0, -1.0, 0.0, 0.0, 0.87266463, -0.52359879, 0.52359879, -0.52359879, 0.0, 0.0 }, // address 0x800308E8. Index 9, = D_80030660 + 648. { PTR_ANIM_aim_running_right_one_handed_weapon, 0.0, 0.0, 4.712389, 0.0, -1.0, 0.0, 0.0, -1.0, -1.0, 0.0, 0.0, 0.87266463, -0.52359879, 0.52359879, -0.52359879, 0.0, 0.0 }, // address 0x80030930. Index 10, = D_80030660 + 720. {0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0} }; s32 objectiveregisters1 = 0; /** * List of characters updated every tick. * * Address 0x8003097C. */ ChrRecord* g_ActiveChrs = 0; /** * Number of items in g_ActiveChrs. * * Adress 0x0x80030980. */ s32 g_ActiveChrsCount = 0; /** * Default factor in chrlvModelScaleAnimationRelated. * Address 0x80030984. */ f32 D_80030984 = 0; /** * Scale factor in chrlvModelScaleAnimationRelated, used by ANIM_DATA_running. * Address 0x80030988. */ f32 D_80030988 = 0; /** * Scale factor in chrlvModelScaleAnimationRelated, used by ANIM_DATA_sprinting. * Address 0x8003098C. */ f32 D_8003098C = 0; /** * Scale factor in chrlvModelScaleAnimationRelated, used by ANIM_DATA_walking_unarmed. * Address 0x80030990. */ f32 D_80030990 = 0; /** * Scale factor in chrlvModelScaleAnimationRelated, used by ANIM_DATA_running_one_handed_weapon. * Address 0x80030994. */ f32 D_80030994 = 0; /** * Scale factor in chrlvModelScaleAnimationRelated, used by first ANIM_DATA_sprinting_one_handed_weapon. * Address 0x80030998. */ f32 D_80030998 = 0; /** * Scale factor in chrlvModelScaleAnimationRelated, used by ANIM_DATA_walking_female. * Address 0x8003099C. */ f32 D_8003099C = 0; /** * Scale factor in chrlvModelScaleAnimationRelated, used by ANIM_DATA_running_female. * Address 0x800309A0. */ f32 D_800309A0 = 0; /** * Scale factor in chrlvModelScaleAnimationRelated, used by duplicate ANIM_DATA_sprinting_one_handed_weapon. * Address 0x800309A4. */ f32 D_800309A4 = 0; point2d D_800309A8 = {0, 0}; //s32 D_800309AC = 0; point2d D_800309B0 = {0, 0}; //s32 D_800309B4 = 0; /** * Default firing state, left and right hand. * Address 0x800309B8. */ point2d D_800309B8 = {0, 0}; /** * Default firing state when crouched, left and right hand. * Address 0x800309C0. */ point2d D_800309C0 = {0, 0}; point2d D_800309C8 = {0, 0}; point2d D_800309D0 = {0, 0}; point2d D_800309D8 = {0, 0}; point2d D_800309E0 = {0, 0}; point2d D_800309E8 = {0, 0}; s32 get_numguards(void) { return g_NumChrSlots; } void get_ptr_allocated_block_for_vertices(int param_1) { dynAllocate(param_1 << 4); } void set_show_patrols_flag(s32 flag) { show_patrols_flag = flag; } s32 get_show_patrols_flag(void) { return show_patrols_flag; } /** * Unreferenced. * * Address 0x7F01F574. */ f32 chrUnusedYPositionRelated(PropRecord *arg0) { if (arg0->stan != 0) { if (sub_GAME_7F0B20D0(&arg0->stan, arg0->pos.x, arg0->pos.z, 1.0f) < 0) { return stanGetPositionYValue(arg0->stan, arg0->pos.x, arg0->pos.z); } return 0.0f; } return 0.0f; } void chrSetMoving(ChrRecord *self, bool unset) { if (unset) { self->hidden &= ~CHRHIDDEN_MOVING; } else { self->hidden |= CHRHIDDEN_MOVING; } return; } StandTile *sub_GAME_7F01F614(ChrRecord *guard, StandTile *stan, coord3d *src, coord3d *dst, s32 updateLastMoveOk) { StandTile *ret; StandTile *tile; f32 height; f32 always_20; f32 width; coord3d edgeA; coord3d edgeB; coord3d delta; coord3d dir; f32 tmp; s32 hasprojection; coord3d newpos; ret = NULL; tile = stan; chrGetChrWidthHeight(guard->prop, &width, &height, &always_20); chrSetMoving(guard, 0); stanResetHits(); if (stanTestLineUnobstructed(&tile, src->x, src->z, dst->x, dst->z, 0x1f, height, always_20, 0.0f, 1.0f)) { if (stanTestVolume(&tile, dst->x, dst->z, width, 0x1f, height, always_20) < 0) { if (updateLastMoveOk) { if (&newpos); guard->invalidmove = 0; guard->lastmoveok60 = g_GlobalTimer; } ret = tile; goto done; } } hasprojection = 0; if (getCollisionEdge_maybe(&edgeA, &edgeB)) { delta.x = dst->x - src->x; delta.z = dst->z - src->z; if ((edgeA.x != edgeB.x) || (edgeA.z != edgeB.z)) { hasprojection = 1; dir.x = edgeB.x - edgeA.x; dir.z = edgeB.z - edgeA.z; tmp = 1.0f / sqrtf((dir.z * dir.z) + (dir.x * dir.x)); dir.x *= tmp; dir.z *= tmp; tmp = (dir.z * delta.z) + (delta.x * dir.x); newpos.x = (dir.x * tmp) + src->x; newpos.z = (dir.z * tmp) + src->z; if (&dir); tile = stan; } if (hasprojection) { if (stanTestLineUnobstructed(&tile, src->x, src->z, newpos.x, newpos.z, 0x1f, height, always_20, 0.0f, 1.0f)) { if (stanTestVolume(&tile, newpos.x, newpos.z, width, 0x1f, height, always_20) < 0) { dst->x = newpos.x; dst->z = newpos.z; guard->invalidmove = 2; ret = tile; goto done; } } } tmp = width * width; dir.x = edgeA.x - dst->x; dir.z = edgeA.z - dst->z; if (((dir.z * dir.z) + (dir.x * dir.x)) <= tmp) { if ((edgeA.x == src->x) && (edgeA.z == src->z)) { goto done; } dir.x = -(edgeA.z - src->z); dir.z = edgeA.x - src->x; tmp = 1.0f / sqrtf((dir.z * dir.z) + (dir.x * dir.x)); dir.x *= tmp; dir.z *= tmp; tmp = (dir.z * delta.z) + (delta.x * dir.x); newpos.x = (dir.x * tmp) + src->x; newpos.z = (dir.z * tmp) + src->z; tile = stan; if (stanTestLineUnobstructed(&tile, src->x, src->z, newpos.x, newpos.z, 0x1f, height, always_20, 0.0f, 1.0f)) { if (stanTestVolume(&tile, newpos.x, newpos.z, width, 0x1f, height, always_20) < 0) { dst->x = newpos.x; dst->z = newpos.z; guard->invalidmove = 2; ret = tile; goto done; } } } else { dir.x = edgeB.x - dst->x; dir.z = edgeB.z - dst->z; if (((dir.z * dir.z) + (dir.x * dir.x)) <= tmp) { if ((edgeB.x == src->x) && (edgeB.z == src->z)) { goto done; } dir.x = -(edgeB.z - src->z); dir.z = edgeB.x - src->x; tmp = 1.0f / sqrtf((dir.z * dir.z) + (dir.x * dir.x)); dir.x *= tmp; dir.z *= tmp; tmp = (dir.z * delta.z) + (delta.x * dir.x); newpos.x = (dir.x * tmp) + src->x; newpos.z = (dir.z * tmp) + src->z; tile = stan; if (stanTestLineUnobstructed(&tile, src->x, src->z, newpos.x, newpos.z, 0x1f, height, always_20, 0.0f, 1.0f)) { if (stanTestVolume(&tile, newpos.x, newpos.z, width, 0x1f, height, always_20) < 0) { dst->x = newpos.x; dst->z = newpos.z; guard->invalidmove = 2; ret = tile; } } } } } done: chrSetMoving(guard, 1); if (ret == NULL) { guard->invalidmove = 1; } return ret; } s32 sub_GAME_7F01FC10(Model *model, coord3d *src, coord3d *dst, f32 *ground_y) { ChrRecord *chr; s32 moved; f32 ground; coord3d *groundpos; f32 tmp; s32 i; StandTile *tile; union ModelRwData *rwdata; chr = model->chr; moved = 0; ground = 0.0f; groundpos = src; if (chr->prop->stan != NULL) { if ((chr->actiontype == ACT_DIE) && (chr->act_die.timeextra > ground)) { #ifdef BUGFIX_R1 tmp = ((model->playspeed * g_JP_GlobalTimerDelta) * (chr->act_die.timeextra - chr->act_die.elapseextra)) / chr->act_die.timeextra; #else tmp = ((model->playspeed * g_GlobalTimerDelta) * (chr->act_die.timeextra - chr->act_die.elapseextra)) / chr->act_die.timeextra; #endif dst->x += chr->act_die.extraspeed.x * tmp; dst->y += chr->act_die.extraspeed.y * tmp; dst->z += chr->act_die.extraspeed.z * tmp; #ifdef BUGFIX_R1 chr->act_die.elapseextra += g_JP_GlobalTimerDelta * model->playspeed; #else chr->act_die.elapseextra += g_GlobalTimerDelta * model->playspeed; #endif if (chr->act_die.timeextra < chr->act_die.elapseextra) { chr->act_die.timeextra = 0.0f; } } dst->x += chr->fallspeed.x * g_GlobalTimerDelta; dst->z += chr->fallspeed.z * g_GlobalTimerDelta; tile = sub_GAME_7F01F614(chr, chr->prop->stan, src, dst, 1); if (tile != NULL) { chr->prop->stan = tile; groundpos = dst; moved = 1; } if (!(chr->chrflags & CHRFLAG_LOCK_Y_POS)) { ground = stanGetPositionYValue(chr->prop->stan, groundpos->x, groundpos->z); chr->ground = ground; if (chr->chrflags & CHRFLAG_INIT) { rwdata = modelGetNodeRwData(model, model->obj->RootNode); chr->chrflags &= ~1; chr->manground = chr->ground; chr->sumground = chr->ground / GROUND_SMOOTH_FACTOR; rwdata->Header.unk34.y = rwdata->Header.unk24.y; } else { if ((chr->fallspeed.y != 0.0f) || (chr->manground > chr->ground)) { sub_GAME_7F057D44(&chr->manground, &chr->fallspeed.y, g_GlobalTimerDelta); if (chr->manground <= chr->ground) { chr->manground = chr->ground; chr->sumground = chr->ground / GROUND_SMOOTH_FACTOR; chr->fallspeed.y = 0.0f; } } if (chr->manground <= chr->ground) { i = 0; if (g_ClockTimer > 0) { tmp = FALLSPEED_DECAY; do { chr->sumground = (chr->sumground * tmp) + chr->ground; chr->fallspeed.x *= tmp; chr->fallspeed.z *= tmp; i++; } while (i < g_ClockTimer); } tmp = 0.1f; chr->manground = chr->sumground * GROUND_SMOOTH_FACTOR; if (chr->fallspeed.x < tmp) { if (-0.1f < chr->fallspeed.x) { if (chr->fallspeed.z < tmp) { if (-0.1f < chr->fallspeed.z) { chr->fallspeed.z = 0.0f; chr->fallspeed.x = 0.0f; } } } } } } dst->y += chr->manground - ground; } else { ground = chr->ground; } } *ground_y = ground; if (!moved) { dst->x = src->x; dst->z = src->z; } return 1; } #undef GROUND_SMOOTH_FACTOR #undef FALLSPEED_DECAY s32 chrGetNumFree(void) { s32 count = 0; s32 i; for (i = 0; i < g_NumChrSlots; i++) { if (g_ChrSlots[i].model == 0) { count++; } } return count; } void chrSetMaxDamage(ChrRecord *chr, f32 maxdamage) { chr->maxdamage = (get_007_health_mod() * maxdamage); } f32 chrGetMaxDamage(ChrRecord *chr) { return chr->maxdamage; } void chrAddHealth(ChrRecord *chr, f32 health) { chr->damage -= (health * get_007_health_mod()); } f32 chrGetArmor(ChrRecord *chr) { if (chr->damage < 0) { return -chr->damage; } return 0; } PropRecord *init_GUARDdata_with_set_values(PropRecord *arg0, Model *arg1, struct coord3d *arg2, f32 arg3, StandTile *arg4, struct AIListRecord *arg5) { ChrRecord *var_s0; s32 var_v0; var_s0 = NULL; var_v0 = 0; for (var_v0 = 0; var_v0 < g_NumChrSlots; var_v0++) { if (g_ChrSlots[var_v0].model == NULL) { var_s0 = &g_ChrSlots[var_v0]; break; } } arg0->type = PROP_TYPE_CHR; arg0->chr = var_s0; arg0->pos.f[0] = arg2->f[0]; arg0->pos.f[1] = arg2->f[1]; arg0->pos.f[2] = arg2->f[2]; arg0->stan = arg4; #ifdef PORT sub_GAME_7F06FF5C(arg1, 1); /* D92: flag only; model.c subcalcpos calls sub_GAME_7F01FC10 directly */ #else sub_GAME_7F06FF5C(arg1, (s32) sub_GAME_7F01FC10); #endif arg1->unk00 = 0xA; arg1->chr = var_s0; setsuboffset(arg1, arg2); setsubroty(arg1, arg3); #if defined(VERSION_EU) modelSetAnimPlaySpeed(arg1, animation_rate * 1.2f, 0.0f); #else modelSetAnimPlaySpeed(arg1, animation_rate, 0.0f); #endif var_s0->chrnum = (s16) player1_guardID; player1_guardID += 1; var_s0->headnum = 0; var_s0->bodynum = 0; var_s0->prop = arg0; var_s0->model = arg1; var_s0->field_20 = NULL; var_s0->numarghs = 0; var_s0->lastwalk60 = 0; var_s0->invalidmove = 0; var_s0->lastmoveok60 = g_GlobalTimer; var_s0->lastseetarget60 = 0; var_s0->lastknowntargetpos.f[0] = 0.0f; var_s0->lastknowntargetpos.f[1] = 0.0f; var_s0->lastknowntargetpos.f[2] = 0.0f; var_s0->targetTile = NULL; var_s0->seen_bond_time = 0; var_s0->lastheartarget60 = 0; var_s0->numclosearghs = 0; var_s0->shotbondsum = 0.0f; var_s0->damage = 0.0f; var_s0->visionrange = 250.0f; var_s0->hearingscale = 1.0f; var_s0->maxdamage = get_007_health_mod() * 4.0f; set_color_shading_from_tile(arg0, &var_s0->nextcol); var_s0->shadecol.rgba[0] = var_s0->nextcol.rgba[0]; var_s0->shadecol.rgba[1] = var_s0->nextcol.rgba[1]; var_s0->shadecol.rgba[2] = var_s0->nextcol.rgba[2]; var_s0->shadecol.rgba[3] = var_s0->nextcol.rgba[3]; var_s0->fadealpha = 0xFF; var_s0->field_160[0].ptr_SEbuffer1 = NULL; var_s0->field_160[0].ptr_SEbuffer2 = NULL; var_s0->field_160[1].ptr_SEbuffer1 = NULL; var_s0->field_160[1].ptr_SEbuffer2 = NULL; var_s0->field_178[0] = 0; var_s0->field_178[1] = 0; var_s0->chrflags = CHRFLAG_INIT; var_s0->hidden = CHRHIDDEN_NONE; var_s0->sumground = 0.0f; var_s0->manground = 0.0f; var_s0->ground = 0.0f; var_s0->fallspeed.f[0] = 0.0f; var_s0->fallspeed.f[1] = 0.0f; var_s0->fallspeed.f[2] = 0.0f; var_s0->prevpos.f[0] = arg2->f[0]; var_s0->prevpos.f[1] = arg2->f[1]; var_s0->prevpos.f[2] = arg2->f[2]; var_s0->actiontype = 0; var_s0->sleep = 0; var_s0->ailist = (AIRecord *) arg5; var_s0->aioffset = 0; var_s0->aireturnlist = -1; var_s0->morale = 0; var_s0->alertness = 0; var_s0->flags2 = 0; var_s0->random = 0; var_s0->timer60 = 0; var_s0->padpreset1 = -1; var_s0->chrseeshot = -1; var_s0->chrseedie = -1; var_s0->chrpreset1 = -1; var_s0->beams[0].unk00 = -1; var_s0->beams[1].unk00 = -1; var_s0->firecount[0] = 0; var_s0->firecount[1] = 0; var_s0->grenadeprob = 0; var_s0->accuracyrating = 0; var_s0->speedrating = 0; var_s0->arghrating = 0; var_s0->flinchcnt = -1; var_s0->aimuplshoulder = 0.0f; var_s0->aimuprshoulder = 0.0f; var_s0->aimupback = 0.0f; var_s0->aimsideback = 0.0f; var_s0->aimendlshoulder = 0.0f; var_s0->aimendrshoulder = 0.0f; var_s0->aimendback = 0.0f; var_s0->aimendsideback = 0.0f; var_s0->aimendcount = 0; var_s0->weapons_held[0] = NULL; var_s0->weapons_held[1] = NULL; var_s0->handle_positiondata_hat = NULL; var_s0->chrwidth = 20.0f; var_s0->chrheight = 185.0f; sub_GAME_7F01FC10(arg1, &arg0->pos, &arg0->pos, &var_s0->ground); chrDetectRooms(var_s0); return arg0; } /** * Address 0x7F0203B8. */ #ifdef PORT /* D92: see chr.h -- arg4 must stay a pointer or the ailist is truncated. */ PropRecord * chrAllocate( Model * arg0, coord3d * arg1, f32 arg2, StandTile * arg3, struct AIListRecord *arg4) #else PropRecord * chrAllocate( Model * arg0, coord3d * arg1, f32 arg2, StandTile * arg3, s32 arg4) #endif { PropRecord * ret; s32 phi_a0; ret = chrpropAllocate(); if (ret != 0) { ret = init_GUARDdata_with_set_values(ret, arg0, arg1, arg2, arg3, arg4); } return ret; } /** * Address: 7F020414. */ void chrpropCleanupForRemoval(PropRecord *prop) { ChrRecord *chr; Model *model; PropRecord *child; PropRecord *prev; ObjectRecord *obj; chr = prop->chr; model = chr->model; if (chr->field_160[0].ptr_SEbuffer1 != NULL && sndGetPlayingState(chr->field_160[0].ptr_SEbuffer1) != 0) { sndDeactivate(chr->field_160[0].ptr_SEbuffer1); } if (chr->field_160[0].ptr_SEbuffer2 != NULL && sndGetPlayingState(chr->field_160[0].ptr_SEbuffer2) != 0) { sndDeactivate(chr->field_160[0].ptr_SEbuffer2); } if (chr->field_160[1].ptr_SEbuffer1 != NULL && sndGetPlayingState(chr->field_160[1].ptr_SEbuffer1) != 0) { sndDeactivate(chr->field_160[1].ptr_SEbuffer1); } if (chr->field_160[1].ptr_SEbuffer2 != NULL && sndGetPlayingState(chr->field_160[1].ptr_SEbuffer2) != 0) { sndDeactivate(chr->field_160[1].ptr_SEbuffer2); } sub_GAME_7F050DE8(model); chrpropDeregisterRooms(prop); child = prop->child; if (child != NULL) { do { obj = (ObjectRecord *)child->obj; prev = child->prev; objDetach(child); objFreePermanently(obj, TRUE); child = prev; } while (child != NULL); } clear_aircraft_model_obj(model); chr->model = NULL; chr->chrnum = -1; if (chr->field_20 != NULL) { sub_GAME_7F06B248(chr->field_20); } } /** * Address 0x7F020540 (VERSION_US, VERSION_JP). * Address 0x7F0203B4 (VERSION_EU). */ void setAnimationRate(f32 arg0) { s32 i; animation_rate = arg0; for (i=0; iaimendcount >= 2) { #if defined(BUGFIX_R1) mult = g_JP_GlobalTimerDelta / (f32) self->aimendcount; #else mult = g_GlobalTimerDelta / (f32) self->aimendcount; #endif if (mult > 1.0f) { mult = 1.0f; } self->aimuplshoulder += ((self->aimendlshoulder - self->aimuplshoulder) * mult); self->aimuprshoulder += ((self->aimendrshoulder - self->aimuprshoulder) * mult); self->aimupback += ((self->aimendback - self->aimupback) * mult); self->aimsideback += ((self->aimendsideback - self->aimsideback) * mult); self->aimendcount -= g_ClockTimer; return; } self->aimuplshoulder = self->aimendlshoulder; self->aimuprshoulder = self->aimendrshoulder; self->aimupback = self->aimendback; self->aimsideback = self->aimendsideback; } /** * Address 0x7F0206D4. */ void chrSetHiddenToRandom(ChrRecord *self) { ChrRecord *temp_a0; u32 rand; if ((s32) self->flinchcnt < 0) { self->flinchcnt = 1; self->hidden &= ~CHRHIDDEN_RAND_FLINCH_MASK; // roll for bits 12,13. // rand -> value // 2 => nothing // 0 => set bit 12 // 1 => set bit 13 rand = randomGetNext() % 3U; if (rand == 0) { self->hidden |= CHRHIDDEN_RAND_FLINCH_1; } else if (rand == 1) { self->hidden |= CHRHIDDEN_RAND_FLINCH_2; } // roll for bits 14,15. // rand -> value // 2 => nothing // 0 => set bit 14 // 1 => set bit 15 rand = randomGetNext() % 3U; if (rand == 0) { self->hidden |= CHRHIDDEN_RAND_FLINCH_4; } else if (rand == 1) { self->hidden |= CHRHIDDEN_RAND_FLINCH_8; } } } /** * Address: 7F020794 * * Flinch animation envelope. Maps a character's flinchcnt timer to a normalized * intensity that goes 0->1 then falls 1->0, used to drive the flinch animation. * * Flinches happen when a character has body armor or has the CHRFLAG_INVINCIBLE flag and is shot in the arm or torso. * * Rise and fall are measured in VI retraces: 1/60 s on NTSC and 1/50 s on PAL. * */ f32 chrGetFlinchAmount(ChrRecord *chr) { f32 temp_f2; f32 phi_f2; #if defined(LEFTOVERDEBUG) f32 rise = 10.0f; f32 fall = 20.0f; #else f32 rise = 8.0f; f32 fall = 16.0f; #endif phi_f2 = chr->flinchcnt; temp_f2 = (f32) phi_f2; if (temp_f2 < rise) { phi_f2 = sinf(((temp_f2 * M_TAU_F) * 0.25f) / rise); } else { phi_f2 = 1.0f - sinf((((temp_f2 - rise) * M_TAU_F) * 0.25f) / fall); } return phi_f2; } #ifdef BUGFIX_R1 bool chrCanUseDKModeScaling(s32 bodynum, s32 headnum) { if (j_text_trigger == FALSE) { return TRUE; } if ((bodynum != BODY_Boris) && (bodynum != BODY_Ourumov) && (bodynum != BODY_Trevelyan_Janus) && (bodynum != BODY_Trevelyan_006) && (bodynum != BODY_Valentin_) && (bodynum != BODY_Xenia) && (bodynum != BODY_Baron_Samedi) && (bodynum != BODY_Jaws) && (bodynum != BODY_Mayday) && (bodynum != BODY_Oddjob) && (bodynum != BODY_Natalya_Skirt) && (bodynum != BODY_Natalya_Jungle_Fatigues) && (headnum != BODY_Male_Pierce_Bond_1) && (headnum != BODY_Male_Pierce_Bond_2) && (headnum != BODY_Male_Pierce_Bond_3) && (headnum != BODY_Male_Pierce_Bond_Parka) && (headnum != BODY_Male_Pierce_Bond_Tuxedo) && (headnum != BODY_Male_Mishkin)) { return TRUE; } return FALSE; } #endif #define PI_OVER_3 1.0471976f #define FIVEPI_OVER_18 0.87266463f /** * Address: 7F02083C */ void chrHandleJointPositioned(enum CHR_RENDER_PART bodypart, Mtxf *matrix) { f32 scale; f32 xrot; f32 yrot; f32 zrot; f32 tmp; f32 amount; f32 savedposz; f32 savedposy; f32 savedposx; f32 sideback; Mtxf rotmtx; u16 hidden; ChrRecord *chr; scale = 1.0f; #ifdef BUGFIX_R1 if (cheatIsActive(CHEAT_DK_MODE)) { chr = g_CurModelChr; if (chrCanUseDKModeScaling(chr->bodynum, chr->headnum)) { if (bodypart == CHR_RENDERPART_HEAD) { scale = 4.0f; } else if ((bodypart == CHR_RENDERPART_LEFT_ARM) || (bodypart == CHR_RENDERPART_RIGHT_ARM)) { if (!(g_CurModelChr->chrflags & CHRFLAG_08000000)) { scale = 2.5f; } } } } #else if (cheatIsActive(CHEAT_DK_MODE)) { if (bodypart == CHR_RENDERPART_HEAD) { scale = 4.0f; } else if ((bodypart == CHR_RENDERPART_LEFT_ARM) || (bodypart == CHR_RENDERPART_RIGHT_ARM)) { scale = 2.5f; } } #endif if ((((bodypart != CHR_RENDERPART_LEFT_ARM) && (bodypart != CHR_RENDERPART_RIGHT_ARM)) && (bodypart != CHR_RENDERPART_TORSO)) && (bodypart != CHR_RENDERPART_HEAD)) { return; } zrot = (yrot = (xrot = 0.0f)); #ifdef BUGFIX_R1 chr = g_CurModelChr; #endif if (bodypart == CHR_RENDERPART_RIGHT_ARM) { #ifdef BUGFIX_R1 xrot = chr->aimuprshoulder; #else xrot = g_CurModelChr->aimuprshoulder; #endif } else if (bodypart == CHR_RENDERPART_LEFT_ARM) { #ifdef BUGFIX_R1 xrot = chr->aimuplshoulder; #else xrot = g_CurModelChr->aimuplshoulder; #endif } else if (bodypart == CHR_RENDERPART_TORSO) { #ifndef BUGFIX_R1 chr = g_CurModelChr; #endif xrot = chr->aimupback; if (chr->hidden & CHRHIDDEN_0400) { if (PI_OVER_3 < xrot) { xrot -= PI_OVER_3; } else if (-FIVEPI_OVER_18 > xrot) { xrot += FIVEPI_OVER_18; } else { xrot = 0.0f; } } yrot = chr->aimsideback; } else if (bodypart == CHR_RENDERPART_HEAD) { #ifndef BUGFIX_R1 chr = g_CurModelChr; #endif if (chr->hidden & CHRHIDDEN_0400) { xrot = chr->aimupback; if (chr->hidden & CHRHIDDEN_0400) { if (PI_OVER_3 < xrot) { xrot = PI_OVER_3; } else if (xrot < -FIVEPI_OVER_18) { xrot = -FIVEPI_OVER_18; } } } else if (chr->model->gunhand != GUNRIGHT) { xrot = chr->aimuplshoulder; } else { xrot = chr->aimuprshoulder; } } chr = g_CurModelChr; if (chr->flinchcnt >= 0) { if (0); if ((bodypart == CHR_RENDERPART_RIGHT_ARM) || (bodypart == CHR_RENDERPART_LEFT_ARM)) { amount = chrGetFlinchAmount(chr) * M_TAU_F * 15.0f / 360.0f; chr = g_CurModelChr; hidden = chr->hidden; xrot -= amount; if (hidden & CHRHIDDEN_RAND_FLINCH_1) { yrot -= amount; } else if (hidden & CHRHIDDEN_RAND_FLINCH_2) { yrot += amount; } } else if (bodypart == CHR_RENDERPART_TORSO) { tmp = chrGetFlinchAmount(chr); tmp *= M_TAU_F; amount = tmp * 15.0f; chr = g_CurModelChr; hidden = chr->hidden; amount /= 360.0f; xrot += amount; if (hidden & CHRHIDDEN_RAND_FLINCH_1) { yrot += amount; } else if (hidden & CHRHIDDEN_RAND_FLINCH_2) { yrot -= amount; } if (hidden & CHRHIDDEN_RAND_FLINCH_4) { zrot += (tmp * 10.0f) / 360.0f; } else if (hidden & CHRHIDDEN_RAND_FLINCH_8) { zrot -= (tmp * 10.0f) / 360.0f; } } } if ((((xrot == 0.0f) && (yrot == 0.0f)) && (zrot == 0.0f)) && (scale == 1.0f)) { return; } sideback = chrlvGetSubrotySideback(chr); if (xrot < 0.0f) { xrot = -xrot; } else { xrot = M_TAU_F - xrot; } if (yrot < 0.0f) { yrot += M_TAU_F; } matrix_4x4_multiply_homogeneous_in_place(currentPlayerGetViewToWorldMtxf(), matrix); savedposx = matrix->m[3][0]; savedposy = matrix->m[3][1]; savedposz = matrix->m[3][2]; matrix->m[3][0] = 0.0f; matrix->m[3][1] = 0.0f; matrix->m[3][2] = 0.0f; if ((xrot != 0.0f) || (zrot != 0.0f)) { yrot -= sideback; if (yrot < 0.0f) { yrot += M_TAU_F; } matrix_4x4_set_rotation_around_y(yrot, &rotmtx); matrix_4x4_multiply_homogeneous_in_place(&rotmtx, matrix); if (xrot != 0.0f) { matrix_4x4_set_rotation_around_x(xrot, &rotmtx); matrix_4x4_multiply_homogeneous_in_place(&rotmtx, matrix); } if (zrot != 0.0f) { matrix_4x4_set_rotation_around_z(zrot, &rotmtx); matrix_4x4_multiply_homogeneous_in_place(&rotmtx, matrix); } matrix_4x4_set_rotation_around_y(sideback, &rotmtx); matrix_4x4_multiply_homogeneous_in_place(&rotmtx, matrix); } else { matrix_4x4_set_rotation_around_y(yrot, &rotmtx); matrix_4x4_multiply_homogeneous_in_place(&rotmtx, matrix); } if (scale != 1.0f) { matrix_scalar_multiply(scale, (f32 *) matrix); } matrix->m[3][0] = savedposx; matrix->m[3][1] = savedposy; matrix->m[3][2] = savedposz; matrix_4x4_multiply_homogeneous_in_place(camGetWorldToScreenMtxf(), matrix); } #undef PI_OVER_3 #undef FIVEPI_OVER_18 /** * Address 0x7F020D94. * * For visibility, player collision, tank collision, bullet collision, and explosion damage * tests the game needs to know which room(s) a character is in. This allows the game to perform * tests on only characters in loaded rooms, not the entire stage. */ void chrDetectRooms(ChrRecord *self) { PropRecord *myprop; coord3d lowerbounds; coord3d upperbounds; // Create a roughly character sized bounding box. myprop = self->prop; lowerbounds.x = myprop->pos.x - 50.0f; lowerbounds.y = self->ground - 1.0f; lowerbounds.z = myprop->pos.z - 50.0f; upperbounds.x = myprop->pos.x + 50.0f; upperbounds.y = myprop->pos.y + 100.0f; upperbounds.z = myprop->pos.z + 50.0f; // Delist the character prop from its previous room(s) chrpropDeregisterRooms(myprop); // Detect rooms overlapped by the bounding box chrpropUpdateRoomList(myprop, &lowerbounds, &upperbounds, 50.0f); // Re-register the character prop in those rooms chrpropRegisterRooms(myprop); } /** * Address 0x7F020E40. */ void chrUpdateAnim(ChrRecord *chr, s32 tickamount) { Model *model; PropRecord* prop; model = chr->model; prop = chr->prop; #ifdef PORT d193aMoved(chr, (chr->hidden & CHRHIDDEN_FREEZE) != 0); #endif if (!(chr->hidden & CHRHIDDEN_FREEZE)) { getsuboffset(model, &chr->prevpos); modelTickAnim(model, tickamount, 1); subcalcpos(model); set_color_shading_from_tile(prop, &chr->nextcol); getsuboffset(model, &prop->pos); chrDetectRooms(chr); return; } subcalcpos(model); getsuboffset(model, &prop->pos); } /** * Address: * US: 0x7F020EF0 * JP: 0x7F021188 * EU: 0x7F020E68 * * This function does the following: * - Drive character animations * - Remove characters if needed * - Held weapon garbage collection * - Character visibility tests * - Render characters/hats/held weapons * - Drop held items * - Fire held weapons */ s32 chrTick(PropRecord *prop) { ModelRenderData renderdata; ChrRecord *chr; Model *model; s32 headSwitchVisible; #ifdef PORT s32 gpVisible = 0; /* D466: headSwitchVisible at the authored draw distance */ #endif s32 headVisible; s32 tickamount; renderdata = D_8002CC6C; chr = prop->chr; model = chr->model; headVisible = 1; tickamount = g_ClockTimer; #ifdef PORT d193aSample(chr, model); #endif if ((!(chr->chrflags & CHRFLAG_HIDDEN)) || (chr->chrflags & CHRFLAG_00040000)) { if (D_8002C904) { #ifdef PORT if (((ModelAnimation *)(uintptr_t)(u32)(animation_table_ptrs1[g_AnimationTablePointerCountRelated])) != ((ModelAnimation *)1)) /* D441: zero-extend s32-held DRAM ptr */ #else if (((ModelAnimation *)animation_table_ptrs1[g_AnimationTablePointerCountRelated]) != ((ModelAnimation *)1)) #endif { #ifdef PORT if (objecthandlerGetModelAnim(model) != ((ModelAnimation *)(uintptr_t)(u32)(animation_table_ptrs1[g_AnimationTablePointerCountRelated]))) /* D441: zero-extend s32-held DRAM ptr */ #else if (objecthandlerGetModelAnim(model) != ((ModelAnimation *)animation_table_ptrs1[g_AnimationTablePointerCountRelated])) #endif { #ifdef PORT modelSetAnimation(model, (ModelAnimation *)(uintptr_t)(u32)(animation_table_ptrs1[g_AnimationTablePointerCountRelated]), 0, 0.0f, 0.5f, 0.0f); /* D441: zero-extend s32-held DRAM ptr */ #else modelSetAnimation(model, (ModelAnimation *)animation_table_ptrs1[g_AnimationTablePointerCountRelated], 0, 0.0f, 0.5f, 0.0f); #endif } } } else { chrlvActionTick(chr); if (chr->model == NULL) { return TICKOP_FREE; } } if (D_8002C90C) { tickamount = 0; if (D_8002C910) { tickamount = 1; } #ifdef DEBUG osSyncPrintf("anim=%d frame=%f backy=%f\n", g_AnimationTablePointerCountRelated, chr->model->animframe1, (chr->aimendlshoulder * 360.0) / 6.283185); #endif } } if (chr->hidden & CHRHIDDEN_REMOVE) { chrpropCleanupForRemoval(prop); return TICKOP_FREE; } if (chr->weapons_held[GUNRIGHT] != NULL) { if (chr->weapons_held[GUNRIGHT]->obj->runtime_bitflags & RUNTIMEBITFLAG_REMOVE) { objFreePermanently(chr->weapons_held[GUNRIGHT]->obj, 1); } } if (chr->weapons_held[GUNLEFT] != NULL) { if (chr->weapons_held[GUNLEFT]->obj->runtime_bitflags & RUNTIMEBITFLAG_REMOVE) { objFreePermanently(chr->weapons_held[GUNLEFT]->obj, 1); } } if (chr->chrflags & CHRFLAG_HIDDEN) { headSwitchVisible = 0; #ifdef PORT gpVisible = 0; #endif } else { if (((prop->type == PROP_TYPE_VIEWER) && (g_playerPointers[getPlayerPointerIndex(prop)]->cameramode == 1)) || (chr->chrflags & CHRFLAG_CULL_USING_HITBOX)) { headSwitchVisible = 1; #ifdef PORT gpVisible = 1; #endif if (((chr->actiontype == ACT_ANIM) && (chr->act_anim.unk02c == 0)) && (chr->act_anim.noTranslate != 0)) { modelTickAnim(model, tickamount, 0); } else { chrUpdateAnim(chr, tickamount); } goto after_position_update; } if ((chr->actiontype == ACT_PATROL) || (chr->actiontype == ACT_GOPOS)) { if (((chr->actiontype == ACT_PATROL) && (chr->act_patrol.waydata.mode == WAYMODE_MAGIC)) || ((chr->actiontype == ACT_GOPOS) && (chr->act_gopos.waydata.mode == WAYMODE_MAGIC))) { headSwitchVisible = posIsOnScreen(prop, &prop->pos, getinstsize(model), 1); #ifdef PORT gpVisible = portD466LastPosVerdict(); /* D466 */ #endif if (headSwitchVisible) { #ifdef DEBUG osSyncPrintf("\nVISIBLE MAGIC MODE!!!!\n\n"); #endif getsuboffset(model, &chr->prevpos); subcalcpos(model); set_color_shading_from_tile(prop, &chr->nextcol); getsuboffset(model, &prop->pos); chrDetectRooms(chr); } } else { chrUpdateAnim(chr, tickamount); headSwitchVisible = posIsOnScreen(prop, &prop->pos, getinstsize(model), 1); #ifdef PORT gpVisible = portD466LastPosVerdict(); /* D466 */ #endif if (headSwitchVisible) { if (chr->actiontype == ACT_PATROL) { chr->act_patrol.lastvisible60 = g_GlobalTimer; } else if (chr->actiontype == ACT_GOPOS) { chr->act_gopos.unk9c = g_GlobalTimer; } } } } else if ((chr->actiontype == ACT_ANIM) && (chr->act_anim.unk02c == 0)) { headSwitchVisible = posIsOnScreen(prop, &prop->pos, getinstsize(model), 1); #ifdef PORT gpVisible = portD466LastPosVerdict(); /* D466 */ #endif if (headSwitchVisible && (chr->act_anim.noTranslate == 0)) { chrUpdateAnim(chr, tickamount); } else { modelTickAnim(model, tickamount, 0); } } else if (chr->actiontype == ACT_STAND) { headSwitchVisible = posIsOnScreen(prop, &prop->pos, getinstsize(model), 1); #ifdef PORT gpVisible = portD466LastPosVerdict(); /* D466 */ #endif if (headSwitchVisible || (chr->chrflags & CHRFLAG_INIT)) { chrUpdateAnim(chr, tickamount); } else if (model->anim2 != NULL) { modelTickAnim(model, tickamount, 0); } } else { if (chr->chrflags & CHRFLAG_IGNORE_ANIM_TRANSLATION) { modelTickAnim(model, tickamount, 0); } else { chrUpdateAnim(chr, tickamount); } headSwitchVisible = posIsOnScreen(prop, &prop->pos, getinstsize(model), 1); #ifdef PORT gpVisible = portD466LastPosVerdict(); /* D466 */ #endif } } after_position_update: if (((chr->actiontype != ACT_STAND) || (model->anim2 != NULL)) || (prop->type == PROP_TYPE_VIEWER)) { chr->hidden |= CHRHIDDEN_BACKGROUND_AI; } chrUpdateAimProperties(chr); if (chr->field_20 != NULL) { sub_GAME_7F06B248(chr->field_20); chr->field_20 = NULL; } if (headSwitchVisible) { if (get_debug_chrnum_flag()) {} prop->flags |= PROPFLAG_ONSCREEN; #ifdef PORT /* D466 (#125): ONSCREEN stays the (extended) render gate; the * gameplay-only "has been seen" flag and the gameplay on-screen bit * follow the authored-draw-distance verdict. Identity at mult 1. */ portPropSetGameplayOnScreen(prop, gpVisible); if (gpVisible) { chr->chrflags |= CHRFLAG_HAS_BEEN_ON_SCREEN; } #else chr->chrflags |= CHRFLAG_HAS_BEEN_ON_SCREEN; #endif #ifdef BUGFIX_R1 if (cheatIsActive(12)) { if (chrCanUseDKModeScaling(chr->bodynum, chr->headnum)) { modelSetDistanceScale(0.3125f); if (chr->chrflags & CHRFLAG_10000000) { chr->chrflags &= ~CHRFLAG_10000000; modelSetScale(chr->model, chr->model->scale / 0.8f); } } } #else if (cheatIsActive(CHEAT_DK_MODE)) { modelSetDistanceScale(0.3125f); } #endif g_ModelJointPositionedFunc = chrHandleJointPositioned; g_CurModelChr = chr; renderdata.basemtx = camGetWorldToScreenMtxf(); renderdata.mtxlist = dynAllocate(model->obj->numMatrices * (sizeof(Mtxf))); if (g_CurModelChr->flinchcnt >= 0) { g_CurModelChr->flinchcnt += g_ClockTimer; #ifdef VERSION_EU if (g_CurModelChr->flinchcnt >= 24) #else if (g_CurModelChr->flinchcnt >= 30) #endif { g_CurModelChr->flinchcnt = -1; } } subcalcmatrices(&renderdata, model); g_ModelJointPositionedFunc = NULL; modelSetDistanceScale(1.0f); update_color_shading(&chr->shadecol, &chr->nextcol); prop->zDepth = sub_GAME_7F06C768(model); chr->field_20 = sub_GAME_7F06B120(NULL, model); chrRenderHeldWeapon(prop, GUNRIGHT, (Gfx **)(&chr->field_20)); chrRenderHeldWeapon(prop, GUNLEFT, (Gfx **)(&chr->field_20)); if (chr->handle_positiondata_hat != NULL) { ObjectRecord *hatobj; Model *hatmodel; hatobj = chr->handle_positiondata_hat->obj; hatmodel = hatobj->model; chr->handle_positiondata_hat->flags |= PROPFLAG_ONSCREEN; #ifdef PORT portPropSetGameplayOnScreen(chr->handle_positiondata_hat, gpVisible); /* D466 */ #endif renderdata.basemtx = modelFindNodeMtx(model, hatmodel->attachedto_objinst, 0); renderdata.mtxlist = dynAllocate(hatmodel->obj->numMatrices * (sizeof(Mtxf))); instcalcmatrices(&renderdata, hatmodel); if ((chr->headnum >= HEAD_START) && (chr->headnum < BODY_Female_Sally)) { coord3d pos; f32 xscale; f32 yscale; f32 zscale; Mtxf mtx; Mtxf tmp; HATTYPE hat; s32 unusedv; struct headHat *entry; volatile s32 changed; s32 headindex; pos = D_8002CCAC; hat = get_hat_model(chr->handle_positiondata_hat); headindex = chr->headnum - HEAD_START; entry = &((struct headHat (*)[6]) headHat_array_8003E464)[headindex][hat]; if (!get_debug_render_raster()) { changed = 0; if (joyGetButtons(PLAYER_1, L_TRIG)) { if (joyGetButtons(PLAYER_1, A_BUTTON)) { /* The differing spellings of 0.02 (and 0.995/1.005 below) are intentional and load-bearing: IDO interns float literals by lexical spelling, and the ROM's rodata pool contains six separate 0.02 words (formerly hosted as D_80051D58..D_80051D6C). */ entry->zoffset -= 0.02f; changed = 1; } if (joyGetButtons(PLAYER_1, B_BUTTON)) { entry->zoffset += 0.020f; changed = 1; } if (joyGetButtons(PLAYER_1, D_CBUTTONS)) { entry->yoffset -= 0.0200f; changed = 1; } if (joyGetButtons(PLAYER_1, U_CBUTTONS)) { entry->yoffset += 0.02000f; changed = 1; } if (joyGetButtons(PLAYER_1, L_CBUTTONS)) { entry->xoffset -= 0.020000f; changed = 1; } if (joyGetButtons(PLAYER_1, R_CBUTTONS)) { entry->xoffset += 0.0200000f; changed = 1; } } if (joyGetButtons(PLAYER_1, R_TRIG)) { if (joyGetButtons(PLAYER_1, A_BUTTON)) { entry->zsize *= 0.995f; changed = 1; } if (joyGetButtons(PLAYER_1, B_BUTTON)) { entry->zsize *= 1.005f; changed = 1; } if (joyGetButtons(PLAYER_1, D_CBUTTONS)) { entry->ysize *= 0.9950f; changed = 1; } if (joyGetButtons(PLAYER_1, U_CBUTTONS)) { entry->ysize *= 1.0050f; changed = 1; } if (joyGetButtons(PLAYER_1, L_CBUTTONS)) { entry->xsize *= 0.99500f; changed = 1; } if (joyGetButtons(PLAYER_1, R_CBUTTONS)) { entry->xsize *= 1.00500f; changed = 1; } } } pos.x = entry->xoffset * 21.3f; pos.y = entry->yoffset * 21.3f; pos.z = entry->zoffset * 21.3f; xscale = entry->xsize; yscale = entry->ysize; zscale = entry->zsize; matrix_4x4_set_identity_and_position(&pos, &mtx); matrix_column_1_scalar_multiply(xscale, (f32 *)(&mtx)); matrix_column_2_scalar_multiply(yscale, (f32 *)(&mtx)); matrix_column_3_scalar_multiply_2(zscale, (f32 *)(&mtx)); matrix_4x4_multiply_homogeneous((Mtxf *)hatmodel->render_pos, &mtx, &tmp); matrix_4x4_copy(&tmp, (Mtxf *)hatmodel->render_pos); if (hat == HATTYPE_PEAKED) { headVisible = 0; } } if ((!(chr->hidden & CHRHIDDEN_DROP_HELD_ITEMS)) || (!(hatobj->runtime_bitflags & RUNTIMEBITFLAG_00000080))) { chr->field_20 = sub_GAME_7F06B120(chr->field_20, hatmodel); } } if (model->obj->Switches[4] != NULL) { union ModelRwData *rwdata; ModelFileHeader *headfile; rwdata = modelGetNodeRwData(model, model->obj->Switches[4]); headfile = rwdata->HeadPlaceholder.ModelFileHeader; if ((headfile != NULL) && (headfile->Switches[1] != NULL)) { modelGetNodeRwData(model, headfile->Switches[1])->Switch.visible = headVisible; } } sub_GAME_7F06B29C(chr->field_20); chr->field_20 = sub_GAME_7F06BB28(chr->field_20); } else { if (chr->weapons_held[GUNRIGHT] != NULL) { chr->weapons_held[GUNRIGHT]->flags &= ~PROPFLAG_ONSCREEN; } if (chr->weapons_held[GUNLEFT] != NULL) { chr->weapons_held[GUNLEFT]->flags &= ~PROPFLAG_ONSCREEN; } if (chr->handle_positiondata_hat != NULL) { chr->handle_positiondata_hat->flags &= ~PROPFLAG_ONSCREEN; } prop->flags &= ~PROPFLAG_ONSCREEN; chr->shadecol.r = chr->nextcol.r; chr->shadecol.g = chr->nextcol.g; chr->shadecol.b = chr->nextcol.b; chr->shadecol.a = chr->nextcol.a; } if (!(chr->chrflags & CHRFLAG_HIDDEN)) { if (chr->hidden & CHRHIDDEN_DROP_HELD_ITEMS) { PropRecord *dropprop = prop->child; PropRecord *unusedprop; while (dropprop != NULL) { PropRecord *nextprop = dropprop->prev; objDrop(dropprop); dropprop = nextprop; } chr->hidden &= ~CHRHIDDEN_DROP_HELD_ITEMS; } chrlvTriggerFireWeapon(chr); } return TICKOP_NONE; } /** * Address 0x7F021B20. */ void chrDropItems(ChrRecord *self) { PropRecord *childprop = self->prop->child; while (childprop) { if ((childprop != self->handle_positiondata_hat) && (childprop != self->weapons_held[GUNLEFT]) && (childprop != self->weapons_held[GUNRIGHT])) { WeaponObjRecord *wep = childprop->weapon; if (!(wep->flags & 0x2000)) { propobjSetDropped(childprop, 1); } } childprop = childprop->prev; }; self->hidden |= 1; } /** * Unreferenced. * * Sets gBloodColour 3 bytes from paramter. * * @param colour: rgba_u8. * * Address 0x7F021BB4. */ void chrSetgBloodColour(rgba_u8 *colour) { gBloodColour.r = colour->r; gBloodColour.g = colour->g; gBloodColour.b = colour->b; } /** * Unreferenced. * * Gets gBloodColour 3 bytes and sets them into parameter. * * @param colour: rgba_u8. * * Address 0x7F021BD8. */ void chrGetgBloodColour(rgba_u8 *colour) { colour->r = gBloodColour.r; colour->g = gBloodColour.g; colour->b = gBloodColour.b; } /** * Address 0x7F021BFC. */ Gfx *chrRenderProp(PropRecord *prop, Gfx *gdl, s32 withalpha) { ChrRecord *chr; Model *chrmodel; struct rgba_f32 spC0; // 192 s32 spBC; // 188 s32 spB8; // 184 s32 chrfadealpha; // 180 rgba_u8 temp_v1_2; ModelRenderData mrData; // 112 struct view4f sp60; // -?? 96 struct rgba_s32 chrShade; s32 sp4C; // 76 PropRecord *prop_held_right; // 72 PropRecord *prop_held_left; // 68 PropRecord *prop_held_hat; // 64 ObjectRecord *held_right_obj; // 60 ObjectRecord *held_left_obj; // 56 ObjectRecord *held_hat_obj; // 52 // chr = prop->chr; chrmodel = chr->model; chrfadealpha = (s32) chr->fadealpha; if (!(chr->chrflags & CHRFLAG_04000000)) { f32 f = chrobjFogVisRangeRelated(prop, getinstsize(chrmodel)); //0-1 chrfadealpha = (s32) (f * (f32) chrfadealpha); } if ((chrfadealpha < 0xFF) || (chr->chrflags & CHRFLAG_00020000)) { if (withalpha == 0) { // nothing to do return gdl; } else { spB8 = 3; } } else { if (withalpha == 0) { spB8 = 1; } else { spB8 = 2; } } spBC = fogGetPropDistColor(prop, &spC0); if (spBC != 0) { if (chrfadealpha > 0) { mrData = D_8002CCBC; sp4C = 0x50; prop_held_right = chr->weapons_held[GUNRIGHT]; prop_held_left = chr->weapons_held[GUNLEFT]; prop_held_hat = chr->handle_positiondata_hat; held_right_obj = NULL; held_left_obj = NULL; held_hat_obj = NULL; if (prop_held_right != NULL) { held_right_obj = prop_held_right->obj; } if (prop_held_left != NULL) { held_left_obj = prop_held_left->obj; } if (prop_held_hat != NULL) { held_hat_obj = prop_held_hat->obj; } if ((getPropCombinedRoomsBBox2D(prop, &sp60) > 0) && !(chr->chrflags & CHRFLAG_CULL_USING_HITBOX)) { gdl = bgScissorCurrentPlayerViewF(gdl, sp60.left, sp60.top, sp60.width, sp60.height); } else { gdl = bgScissorCurrentPlayerViewDefault(gdl); } mrData.flags = spB8; mrData.zbufferenabled = TRUE; mrData.gdl = gdl; if ((chr->chrflags & CHRFLAG_NO_SHADOW) != 0) { sp4C = 0; } else if (spBC == 1) { sp4C = ((1.0f - spC0.a) * (f32)(sp4C)); } sub_GAME_7F073FC8(sp4C); chrShade.r = chr->shadecol.r; chrShade.g = chr->shadecol.g; chrShade.b = chr->shadecol.b; chrShade.a = chr->shadecol.a; lerp_rgba_s32_with_rgba_f32(&chrShade, spBC, &spC0); mrData.envcolour.word = ((gBloodColour.rgba[0] << 0x18) | (gBloodColour.rgba[1] << 0x10)) | (gBloodColour.rgba[2] << 0x08); mrData.fogcolour.word = (chrShade.rgba[0] << 0x18) | (chrShade.rgba[1] << 0x10) | (chrShade.rgba[2] << 0x08) | (chrShade.rgba[3] << 0x00); if (chrfadealpha < 0xFF) { mrData.PropType = 8; mrData.envcolour.word |= (u8)chrfadealpha; } else { mrData.PropType = 7; } g_playerPerm->time_other_players_on_screen += 1; drawjointlist(&mrData, chr->field_20); gdl = mrData.gdl; if ((held_right_obj != NULL) && (( held_right_obj->state & ((u8)(1 << withalpha) )) )) { gdl = explosionRenderBulletImpactOnProp(gdl, prop_held_right, withalpha); } if ((held_left_obj != NULL) && (( held_left_obj->state & ((u8)(1 << withalpha) )) )) { gdl = explosionRenderBulletImpactOnProp(gdl, prop_held_left, withalpha); } if ((held_hat_obj != NULL) && (( held_hat_obj->state & ((u8)(1 << withalpha) )) )) { gdl = explosionRenderBulletImpactOnProp(gdl, prop_held_hat, withalpha); } if (withalpha != 0) { bondviewTransformManyPosToViewMatrix(chr->model->render_pos, chr->model->obj->numMatrices); if ((held_right_obj != NULL) && ((held_right_obj->runtime_bitflags & 0x800) == 0)) { bondviewTransformManyPosToViewMatrix(held_right_obj->model->render_pos, held_right_obj->model->obj->numMatrices); } if ((held_left_obj != NULL) && ((held_left_obj->runtime_bitflags & 0x800) == 0)) { bondviewTransformManyPosToViewMatrix(held_left_obj->model->render_pos, held_left_obj->model->obj->numMatrices); } if (held_hat_obj != NULL) { bondviewTransformManyPosToViewMatrix(held_hat_obj->model->render_pos, held_hat_obj->model->obj->numMatrices); } } } } if (withalpha != 0) { sub_GAME_7F06B248(chr->field_20); chr->field_20 = NULL; } return gdl; } /** * Creates a smoke puff at the front of the character when the character is shot, * and also has a ~50% chance of creating a second smoke puff just behind the character. */ void chrCreateHitPuffs(PropRecord *prop, s32 anim_id, coord3d *vec, coord3d *pos) { s32 i; f32 scale; coord3d sp3c; s32 index; struct ChrHitReaction *entry; index = 0; i = 0; if (g_HitReactionTable[0].hitpart != -1) { do { if (anim_id == g_HitReactionTable[i].hitpart) { index = i; break; } i++; } while (g_HitReactionTable[i].hitpart != -1); } entry = &g_HitReactionTable[index]; if (entry->backImpactPuffCount) { // True when randomGetNext() bit 2 is 0, so roughly 50% chance. if ((randomGetNext() & 4) == 0) { scale = (42.0f / sqrtf(vec->z * vec->z + (vec->x * vec->x + vec->y * vec->y))) + 1.0f; sp3c.x = vec->x * scale; sp3c.y = vec->y * scale; sp3c.z = vec->z * scale; mtx4TransformVecInPlace(currentPlayerGetViewToWorldMtxf(), &sp3c); bullet_spark_create(&sp3c, entry->backImpactPuffCount, entry->backImpactPuffSize, prop->stan->room); } } if (entry->impactPuffCount) { bullet_spark_create(pos, entry->impactPuffCount, entry->impactPuffSize, prop->stan->room); } } void chrCreateBloodStain(Model *model, s32 arg1, ModelNode *root, struct coord3d *pos) { s32 sp_pos[3]; s32 unused_stack_pad[1]; s32 bestdist; ModelNode *bestnode; s32 bestindex; ModelNode *node; s32 opcode; ModelRoData_DisplayList_CollisionRecord *rodata; ModelRoData_DisplayList_CollisionRecord *relatedrodata; ModelRwData_DisplayList_CollisionRecord *relatedrwdata; ModelNode *relatednode; ModelNode *rwdata; Vertex *vtx; Vertex *newvertices; s32 i; s32 n; s32 paintval; s32 relatedindex; sp_pos[0] = pos->x; sp_pos[1] = pos->y; sp_pos[2] = pos->z; bestnode = NULL; bestindex = 0; bestdist = 0x7fffffff; node = root; while (node != NULL) { opcode = node->Opcode & 0xff; if (opcode == MODELNODE_OPCODE_LOD) { goto apply_distance; } if (opcode == MODELNODE_OPCODE_SWITCH) { goto apply_toggle; } if (opcode == MODELNODE_OPCODE_HEAD) { goto apply_head; } if (opcode != MODELNODE_OPCODE_DLCOLLISION) { goto after_opcode; } rodata = &node->Data->DisplayListCollisions; n = 0; if (rodata->numCollisionVertices > 0) { vtx = rodata->CollisionVertices; do { s32 dx; s32 dy; s32 dz; s32 dist; dx = sp_pos[0] - vtx->coord.x; dy = sp_pos[1] - vtx->coord.y; dz = sp_pos[2] - vtx->coord.z; dist = ((((u32) dx) * ((u32) dx)) + (((u32) dy) * ((u32) dy))) + (((u32) dz) * ((u32) dz)); if (dist < bestdist) { bestdist = dist; bestnode = node; bestindex = n; } n++; vtx++; } while (n < rodata->numCollisionVertices); } goto after_opcode; apply_distance: modelApplyDistanceRelations(model, node); goto after_opcode; apply_toggle: modelApplyToggleRelations(model, node); goto after_opcode; apply_head: modelApplyHeadRelations(model, node); after_opcode: if ((node->Child != NULL) && ((node == root) || ((opcode != MODELNODE_OPCODE_BBOX) && (opcode != MODELNODE_OPCODE_OP17)))) { node = node->Child; } else { while (node != NULL) { if (node == root) { node = NULL; break; } if (node->Next != NULL) { node = node->Next; break; } node = node->Parent; } } } if (bestnode == NULL) { return; } node = (ModelNode *) bestnode->Data; rwdata = (ModelNode *) modelGetNodeRwData(model, bestnode); relatedrodata = NULL; relatedrwdata = NULL; relatedindex = 0; paintval = (randomGetNext() % 50) + 20; if (arg1 == 8) { paintval += 100; } if (arg1 == 0x0f) { paintval += 50; } #ifdef PORT /* PC port (D43/D45): CollisionRelatedNode is a raw vma (u32), not a pointer. */ relatednode = (ModelNode *)(uintptr_t)((ModelRoData_DisplayList_CollisionRecord *) node)->CollisionVertices[bestindex].CollisionRelatedNode; if (((ModelRoData_DisplayList_CollisionRecord *) node)->CollisionVertices[bestindex].CollisionRelatedNode != 0) #else relatednode = (ModelNode *) ((ModelRoData_DisplayList_CollisionRecord *) node)->CollisionVertices[bestindex].CollisionRelatedNode; if (((ModelRoData_DisplayList_CollisionRecord *) node)->CollisionVertices[bestindex].CollisionRelatedNode != NULL) #endif { relatedrodata = &relatednode->Data->DisplayListCollisions; relatedrwdata = (ModelRwData_DisplayList_CollisionRecord *) modelGetNodeRwData(model, relatednode); relatedindex = ((ModelRoData_DisplayList_CollisionRecord *) node)->CollisionVertices[bestindex].CollisionRelatedIndex; } if (((ModelRwData_DisplayList_CollisionRecord *) rwdata)->Vertices == ((ModelRoData_DisplayList_CollisionRecord *) node)->Vertices) { newvertices = (Vertex *) vtxstore_allocate(((ModelRoData_DisplayList_CollisionRecord *) node)->numVertices, 0xcccc, 0, 0); if (newvertices != NULL) { s32 j; ((ModelRwData_DisplayList_CollisionRecord *) rwdata)->Vertices = newvertices; for (j = 0; j < ((ModelRoData_DisplayList_CollisionRecord *) node)->numVertices; j++) { newvertices[j] = ((ModelRoData_DisplayList_CollisionRecord *) node)->Vertices[j]; } } } if ((relatedrwdata != NULL) && (relatedrwdata->Vertices == relatedrodata->Vertices)) { newvertices = (Vertex *) vtxstore_allocate(relatedrodata->numVertices, 0xcccc, 0, 0); if (newvertices != NULL) { s32 j; relatedrwdata->Vertices = newvertices; for (j = 0; j < relatedrodata->numVertices; j++) { newvertices[j] = relatedrodata->Vertices[j]; } } } if (((ModelRwData_DisplayList_CollisionRecord *) rwdata)->Vertices != ((ModelRoData_DisplayList_CollisionRecord *) node)->Vertices) { s32 index; #ifdef PORT /* D120: PointUsage[] is a negative-terminated "next" chain. On PC the * opcode-0x18 collision record / PointUsage conversion in d43_emit is * incomplete (endianness/stride), so `index` can cycle -> hang after * the first guard bullet-hit. Cap the walk until the converter is * fixed; blood decals may be missing/wrong but the game keeps running. */ s32 guard = ((ModelRoData_DisplayList_CollisionRecord *) node)->numVertices + 8; index = ((ModelRoData_DisplayList_CollisionRecord *) node)->CollisionVertices[bestindex].index; while (index >= 0 && index < ((ModelRoData_DisplayList_CollisionRecord *) node)->numVertices && guard-- > 0) #else index = ((ModelRoData_DisplayList_CollisionRecord *) node)->CollisionVertices[bestindex].index; while (index >= 0) #endif { ((ModelRwData_DisplayList_CollisionRecord *) rwdata)->Vertices[index].a = paintval; index = ((ModelRoData_DisplayList_CollisionRecord *) node)->PointUsage[index]; } } if ((relatedrwdata != NULL) && (relatedrwdata->Vertices != relatedrodata->Vertices)) { s32 index; #ifdef PORT s32 guard = relatedrodata->numVertices + 8; index = relatedrodata->CollisionVertices[relatedindex].index; while (index >= 0 && index < relatedrodata->numVertices && guard-- > 0) #else index = relatedrodata->CollisionVertices[relatedindex].index; while (index >= 0) #endif { relatedrwdata->Vertices[index].a = paintval; index = relatedrodata->PointUsage[index]; } } } /** * * Address: 7F022648 * * Tests a shot's ray against a character. * * First tests the shot against the chr's bounding sphere expanded by the * largest held weapon's model size. On a bounds hit, the model hit list is * walked for a body part. A confirmed body hit is registered via chrpropAddBulletHit; * a near miss inside max range flags CHRFLAG_NEAR_MISS and bumps numclosearghs. * * PD: chr_test_hit */ /** * This assert is from the former NONMATCHING block and belongs somewhere in chrTestHit. * * #ifdef DEBUG * assert(hits && hits->HasHits()); * #endif */ void chrTestHit(PropRecord *prop, ShotData *shotdata) { ChrRecord *chr; Model *model; f32 modelsize; s32 hitpart; Model *hitmodel; ModelNode *hitnode; s32 hitbounds; struct HitThing hitthing; s32 mtxindex; ModelNode *dlnode; Mtxf *submatrix; f32 heldmodelsize; Mtxf *nodemtx; f32 len; struct WeaponObjRecord *weapon; f32 dist; ModelHitEntry *entry; coord3d viewdir; f32 size; s32 i; coord3d diff; f64 pad; chr = prop->chr; if (chr->actiontype == ACT_DEAD) { return; } model = chr->model; modelsize = getinstsize(model); if ((prop->flags & PROPFLAG_ONSCREEN) == FALSE) { return; } hitpart = HIT_NULL_PART; if (!((prop->zDepth - modelsize) < shotdata->maxdist)) { return; } hitmodel = NULL; hitnode = NULL; hitbounds = FALSE; dlnode = NULL; submatrix = getsubmatrix(model); heldmodelsize = 0.0f; for (i = 0; i < 2; i++) { if (chr->weapons_held[i] != NULL) { weapon = chr->weapons_held[i]->weapon; size = model->scale * getinstsize(weapon->model); if (heldmodelsize < size) { heldmodelsize = size; } } } modelsize += heldmodelsize; if (projectileTestPropBoundingSphere(&shotdata->viewOrigin, &shotdata->viewDir, (coord3d *) &submatrix->m[3][0], modelsize)) { hitbounds = TRUE; hitpart = HIT_LEFT_FOOT; } if (hitpart != HIT_NULL_PART) { entry = chr->field_20; hitpart = sub_GAME_7F06C010(&entry, &shotdata->viewOrigin, &shotdata->viewDir, &hitmodel, &hitnode); while ((hitpart == HIT_GUN) || (hitpart == HIT_HAT)) { if (propobjFindHit(hitmodel, hitnode, &shotdata->viewOrigin, &shotdata->viewDir, &hitthing, &mtxindex, &dlnode)) { break; } // Leave if (1) for matching. if (1) { hitpart = probably_damage_detail_blood_effect_related(&entry, &shotdata->viewOrigin, &shotdata->viewDir, &hitmodel, &hitnode); } } } if (hitpart > HIT_NULL_PART) { viewdir.x = shotdata->viewDir.x; viewdir.y = shotdata->viewDir.y; viewdir.z = shotdata->viewDir.z; submatrix = currentPlayerGetViewToWorldMtxf(); mtx4RotateVecInPlace(submatrix, &viewdir); nodemtx = modelFindNodeMtx(hitmodel, hitnode, 0); // Leave for matching if (&diff); diff.x = nodemtx->m[3][0] - shotdata->viewOrigin.x; diff.y = nodemtx->m[3][1] - shotdata->viewOrigin.y; diff.z = nodemtx->m[3][2] - shotdata->viewOrigin.z; len = sqrtf((diff.z * diff.z) + ((diff.x * diff.x) + (diff.y * diff.y))); dist = -((shotdata->viewDir.z * len) + shotdata->viewOrigin.z); if (dist < shotdata->maxdist) { chrpropAddBulletHit(shotdata, prop, dist, hitpart, hitnode, &hitthing, mtxindex, dlnode, hitmodel, TRUE, FALSE); } } if (hitbounds && (prop->zDepth <= shotdata->maxdist)) { chr->chrflags |= CHRFLAG_NEAR_MISS; chr->numclosearghs++; } } /** * Address: 7F022980 * * Resolves a known hit against a character. */ void chrHandleBulletHit(struct ShotData *shot, struct BulletHit *bhit) { f32 scale; Mtxf invmtx; coord3d nearhitpos; s32 temp; coord3d hitpos; Mtxf *mtx; ChrRecord *chr; PropRecord *prop; struct image_sound *sound; WeaponObjRecord *weaponobj; s32 i; s32 temp2; coord3d jointpos; struct image_sound *sound2; chr = bhit->prop->chr; // Calculate the view space hit position for impact effects. hitpos.f[0] = shot->viewOrigin.x - ((bhit->dist * shot->viewDir.x) / shot->viewDir.z); hitpos.f[1] = shot->viewOrigin.y - ((bhit->dist * shot->viewDir.y) / shot->viewDir.z); hitpos.f[2] = shot->viewOrigin.z - bhit->dist; scale = 1.0f - (42.0f / sqrtf(SQ(hitpos.f[0]) + SQ(hitpos.f[1]) + SQ(hitpos.f[2]))); /** Use scale to create a near hit position closer to the camera. * Probably to prevent the tracer effect and smoke puffs from landing inside the character model. */ nearhitpos.x = hitpos.f[0] * scale; nearhitpos.y = hitpos.f[1] * scale; nearhitpos.z = hitpos.f[2] * scale; mtx4TransformVecInPlace(currentPlayerGetViewToWorldMtxf(), &nearhitpos); // Point the tracer effect towards the impact position. gunSetTracerTarget(&nearhitpos); // Make a fleshy impact sound. recall_joy2_hits_edit_detail_edit_flag(shot->weapon, bhit->prop, -1); chrCreateHitPuffs(bhit->prop, bhit->hitpart, &hitpos, &nearhitpos); // Apply damage to the character. if (!handles_shot_actors(chr, bhit->hitpart, &shot->dir, shot->weapon, TRUE)) { return; } if (bhit->hitpart == HIT_GUN) { for (i = 0; i != 2; i++) { prop = chr->weapons_held[i]; if (prop != NULL) { weaponobj = (WeaponObjRecord *)prop->obj; /** * If a character is holding an explosive such as a grenade, and the explosive is shot, detonate it. */ if (weaponobj->model == bhit->model) { if ( ((WeaponObjRecord *)weaponobj)->weaponnum == ITEM_GRENADE || ((WeaponObjRecord *)weaponobj)->weaponnum == ITEM_GRENADEROUND || ((WeaponObjRecord *)weaponobj)->weaponnum == ITEM_ROCKETROUND || ((WeaponObjRecord *)weaponobj)->weaponnum == ITEM_TIMEDMINE || ((WeaponObjRecord *)weaponobj)->weaponnum == ITEM_BOMBCASE || ((WeaponObjRecord *)weaponobj)->weaponnum == ITEM_REMOTEMINE || ((WeaponObjRecord *)weaponobj)->weaponnum == ITEM_PROXIMITYMINE ) { propobjSetDropped(prop, 1); chr->hidden |= 1; objApplyDamage(prop->obj, gunItemGetDestructionAmount(shot->weapon), &hitpos, shot->weapon, get_cur_playernum()); // Create a bullet hole on the character's held weapon. } else { if (bhit->hit.texturenum < 0) { sound = g_HitTypeSounds[0]; } else { sound = g_HitTypeSounds[g_Textures[bhit->hit.texturenum].hitTexture]; } temp = randomGetNext() % (s16)sound->thing2_len; explosionCreateBulletImpact(&bhit->hit.hitpos, &bhit->hit.normal, sound->thing2[temp], 1, prop, bhit->room, 0); } } } } return; } // Create a bullet on hole on a hat or helmet attached to a character's head. if (bhit->hitpart == HIT_HAT) { if (bhit->hit.texturenum < 0) { sound2 = g_HitTypeSounds[0]; } else { sound2 = g_HitTypeSounds[g_Textures[bhit->hit.texturenum].hitTexture]; } temp2 = randomGetNext() % (s16)sound2->thing2_len; explosionCreateBulletImpact(&bhit->hit.hitpos, &bhit->hit.normal, sound2->thing2[temp2], 1, chr->handle_positiondata_hat, bhit->room, 0); return; } mtx = modelFindNodeMtx(bhit->model, bhit->node, 0); jointpos.x = hitpos.f[0]; jointpos.y = hitpos.f[1]; jointpos.z = hitpos.f[2]; jointpos.x += (jointpos.x - mtx->m[3][0]) * 0.5f; jointpos.y += (jointpos.y - mtx->m[3][1]) * 0.5f; jointpos.z += (jointpos.z - mtx->m[3][2]) * 0.5f; jointpos.x -= getjointsize(bhit->model, bhit->node) * 0.5f * shot->viewDir.x; jointpos.y -= getjointsize(bhit->model, bhit->node) * 0.5f * shot->viewDir.y; jointpos.z -= getjointsize(bhit->model, bhit->node) * 0.5f * shot->viewDir.z; matrix_4x4_set_inverse_rotation_and_translation(mtx, &invmtx); mtx4TransformVecInPlace(&invmtx, &jointpos); // Create a blood stain at the impact point. chrCreateBloodStain(bhit->model, bhit->hitpart, bhit->node, &jointpos); } /** * Removed. * * Address 0x7F022E1C. */ void chrRemoved7F022E1C(f32 arg0) { // removed } void setanimationdebugflag(s32 param_1) { D_8002C904 = param_1; return; } /** * Decrements g_AnimationTablePointerCountRelated. * If less than zero, the variable will then be set to the * number of non-zero entries in animation_table_ptrs1. * * Address 0x7F022E30. */ void chrDecrementAnimationTablePointerCount(void) { g_AnimationTablePointerCountRelated--; if (g_AnimationTablePointerCountRelated < 0) { for ( g_AnimationTablePointerCountRelated = 0; animation_table_ptrs1[g_AnimationTablePointerCountRelated+1] != 0; g_AnimationTablePointerCountRelated++) { // nothing to do. } } } /** * Decrements g_AnimationTablePointerCountRelated. * If the entry in animation_table_ptrs1 at that index is zero * then the global variable will be set to zero. * * Address 0x7F022E90. */ void chrIncrementAnimationTablePointerCount(void) { g_AnimationTablePointerCountRelated++; if (animation_table_ptrs1[g_AnimationTablePointerCountRelated] == 0) { g_AnimationTablePointerCountRelated = 0; } } /** * Address 0x7F022EC8. */ void chrToggleD_8002C90C(void) { D_8002C90C = !D_8002C90C; } void sub_GAME_7F022EE0(s32 param_1){ D_8002C910 = param_1; } /** * Iterates all guards and checks if the noise is within the hearing scale distance. * * @param noise: noise amount to check. * * Address 0x7F022EEC. */ void chrCheckGuardsHeardSound(f32 noise) { s32 i; for (i=0; iweapons_held[hand]; //0x160 } /** * Address 0x7F02303C. */ PropRecord *chrGetEquippedWeaponPropWithCheck(ChrRecord *self, GUNHAND hand) { PropRecord *gunprop = self->weapons_held[hand]; if (gunprop) { WeaponObjRecord *wep = gunprop->weapon; if (bondwalkItemCheckBitflags(wep->weaponnum, WEAPONSTATBITFLAG_HOLD_AS_GUN) == 0) { gunprop = NULL; } } return gunprop; } /** * Updates character collision bounds based on chracter width. * * @param arg0: prop * @param arg1: out parameter, will contain character collision_bounds. * @param arg2: out parameter, will contain 0 or 4 * @param y_out: out parameter, will be character ground + character height * @param ground: out parameter, will contain character ground * * Address 0x7F02308C. */ void chrUpdateCollisionBounds(PropRecord *prop, rect4f **polygon, s32 *edges, f32 *y_out, f32 *ground) { ChrRecord *chr; chr = prop->chr; if ( (chr->actiontype != ACT_DIE) && (chr->actiontype != ACT_DEAD) && ((chr->chrflags & (CHRFLAG_00010000 | CHRFLAG_HIDDEN)) == 0) && ((chr->hidden & CHRHIDDEN_MOVING) == 0) ) { *edges = 4; *polygon = &chr->collision_bounds; //collision box is a diamond around chr chr->collision_bounds.f[0] = prop->pos.x + chr->chrwidth; chr->collision_bounds.f[1] = prop->pos.z; chr->collision_bounds.f[2] = prop->pos.x; chr->collision_bounds.f[3] = prop->pos.z + chr->chrwidth; chr->collision_bounds.f[4] = prop->pos.x - chr->chrwidth; chr->collision_bounds.f[5] = prop->pos.z; chr->collision_bounds.f[6] = prop->pos.x; chr->collision_bounds.f[7] = prop->pos.z - chr->chrwidth; *ground = chr->ground; *y_out = *ground + chr->chrheight; return; } *edges = 0; } /** * @param arg0: prop * @param width: out parameter, will be set to character width * @param height: out parameter, will be set to character height - 20 * @param always_20: out parameter, will be set to 20 * * Address 0x7F023160. */ void chrGetChrWidthHeight(PropRecord *arg0, f32 *width, f32 *height, f32 *always_20) { void *temp_v0; ChrRecord *c = arg0->chr; *width = c->chrwidth; *height = c->chrheight - 20.0f; *always_20 = 20.0f; } /** * Address 0x7F023188. */ f32 chrGetChrGround(PropRecord *arg0) { ChrRecord *c = arg0->chr; return c->ground; } /** * Calculate auto aim position coordinates. * * US address 7F023194. */ s32 chrGetOnscreenRenderBounds(PropRecord *arg0, struct coord3d *arg1, struct coord2d *arg2, struct coord2d *arg3) { struct ChrRecord *temp_v1; temp_v1 = arg0->chr; if (arg0->flags & PROPFLAG_ONSCREEN) { if ((temp_v1->actiontype != ACT_DIE) && (temp_v1->actiontype != ACT_DEAD) && !(temp_v1->chrflags & CHRFLAG_NO_AUTOAIM)) { struct Model *model; RenderPosView *model_render_pos_1; RenderPosView *model_render_pos_2; model = temp_v1->model; model_render_pos_1 = &model->render_pos[0]; model_render_pos_2 = &model->render_pos[1]; arg1->f[2] = model_render_pos_2->pos.m[3][2] + ((model_render_pos_1->pos.m[3][2] - model_render_pos_2->pos.m[3][2]) * 0.25f); if (arg1->f[2] < 0.0f) { arg1->f[0] = model_render_pos_2->pos.m[3][0] + ((model_render_pos_1->pos.m[3][0] - model_render_pos_2->pos.m[3][0]) * 0.25f); arg1->f[1] = model_render_pos_2->pos.m[3][1] + ((model_render_pos_1->pos.m[3][1] - model_render_pos_2->pos.m[3][1]) * 0.25f); arg3->y = 0.0f; arg3->x = 0.0f; arg2->x = 0.0f; arg2->y = 0.0f; modelGetXYExtents(model, &arg2->y, &arg2->x, &arg3->y, &arg3->x); return 1; } } } return 0; }