diff --git a/src/game/chr.c b/src/game/chr.c index b495be3d6..e2ceeb3a0 100644 --- a/src/game/chr.c +++ b/src/game/chr.c @@ -547,7 +547,7 @@ bool chr0f01f378(struct model *model, struct coord *arg1, struct coord *arg2, f3 #define VAR(property) g_Vars.property #endif - if (g_Anims[model->anim->animnum].flags & ANIMFLAG_02) { + if (g_Anims[model->anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) { if (chr->hidden & CHRHFLAG_00020000) { func0f065e98(&prop->pos, prop->rooms, arg2, spfc); } else { @@ -1917,7 +1917,7 @@ void chr0f0220ec(struct chrdata *chr, s32 lvupdate240, bool arg2) } if (model->anim - && (g_Anims[model->anim->animnum].flags & ANIMFLAG_02) + && (g_Anims[model->anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) && lvupdate240 > 0 && g_Vars.cutsceneskip60ths > 0) { lvupdate240 += g_Vars.cutsceneskip60ths * 4; @@ -2346,7 +2346,7 @@ s32 chrTick(struct prop *prop) struct modelrenderdata sp210 = {0, 1, 3}; struct chrdata *chr = prop->chr; struct model *model = chr->model; - bool onscreen; + bool needsupdate; bool hatvisible = true; s32 lvupdate240 = g_Vars.lvupdate240; struct prop *child; @@ -2356,8 +2356,8 @@ s32 chrTick(struct prop *prop) s32 sp1e8; Mtxf sp1a8; s32 sp1a4; - bool invalidframe; - bool invalidframe2; + bool isrepeatframe; + bool isrepeatframe2; struct coord sp190; f32 angle; struct player *player; @@ -2452,26 +2452,26 @@ s32 chrTick(struct prop *prop) if (eyespy && eyespy->deployed) { if (eyespy == g_Vars.currentplayer->eyespy && eyespy->active) { - onscreen = false; + needsupdate = false; } else { - onscreen = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true); + needsupdate = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true); } if (fulltick) { chr0f0220ec(chr, lvupdate240, true); } } else { - onscreen = false; + needsupdate = false; } } else if (chr->chrflags & CHRCFLAG_HIDDEN) { - onscreen = false; + needsupdate = false; } else if ((chr->chrflags & CHRCFLAG_UNPLAYABLE) || (prop->type == PROPTYPE_PLAYER && g_Vars.currentplayer == (player = g_Vars.players[playermgrGetPlayerNumByProp(prop)]) && player->cameramode == CAMERAMODE_THIRDPERSON && player->visionmode != VISIONMODE_SLAYERROCKET)) { // Cutscene chr? - invalidframe = false; + isrepeatframe = false; if (fulltick) { model->anim->average = false; @@ -2483,25 +2483,25 @@ s32 chrTick(struct prop *prop) } } - if (chr->model && chr->model->anim && (g_Anims[chr->model->anim->animnum].flags & ANIMFLAG_HASREMAPPEDFRAMES)) { + if (chr->model && chr->model->anim && (g_Anims[chr->model->anim->animnum].flags & ANIMFLAG_HASREPEATFRAMES)) { animLoadHeader(chr->model->anim->animnum); - invalidframe = animGetRemappedFrame(chr->model->anim->animnum, chr->model->anim->framea) < 0 + isrepeatframe = animGetRemappedFrame(chr->model->anim->animnum, chr->model->anim->framea) < 0 || (animGetRemappedFrame(chr->model->anim->animnum, chr->model->anim->frameb) < 0 && chr->model->anim->frac != 0.0f); } - if (invalidframe) { - onscreen = false; + if (isrepeatframe) { + needsupdate = false; } else { - onscreen = posIsInDrawDistance(&prop->pos); + needsupdate = posIsInDrawDistance(&prop->pos); } } else 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)) { - onscreen = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true); + needsupdate = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true); - if (onscreen) { + if (needsupdate) { model->anim->average = false; modelGetRootPosition(model, &chr->prevpos); modelUpdateInfo(model); @@ -2511,9 +2511,9 @@ s32 chrTick(struct prop *prop) chr0f0220ec(chr, lvupdate240, true); } - onscreen = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true); + needsupdate = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true); - if (onscreen) { + if (needsupdate) { if (chr->actiontype == ACT_PATROL) { chr->act_patrol.waydata.lastvisible60 = g_Vars.lvframe60; } else if (chr->actiontype == ACT_GOPOS) { @@ -2521,16 +2521,16 @@ s32 chrTick(struct prop *prop) } } - model->anim->average = !onscreen + model->anim->average = !needsupdate && !((prop->flags & (PROPFLAG_ONANYSCREENTHISTICK | PROPFLAG_ONANYSCREENPREVTICK)) != 0); } } else if (chr->actiontype == ACT_ANIM && !chr->act_anim.movewheninvis) { - onscreen = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true); + needsupdate = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true); if (fulltick) { model->anim->average = false; - if (onscreen && !chr->act_anim.lockpos) { + if (needsupdate && !chr->act_anim.lockpos) { chr0f0220ec(chr, lvupdate240, true); } else { chr0f0220ec(chr, lvupdate240, false); @@ -2541,14 +2541,14 @@ s32 chrTick(struct prop *prop) if (chr->chrflags & CHRCFLAG_00000001) { chr0f0220ec(chr, lvupdate240, true); - onscreen = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true); + needsupdate = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true); } else { - onscreen = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true); + needsupdate = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true); if (g_Vars.mplayerisrunning) { if (fulltick) { if (g_Vars.coopplayernum >= 0 || g_Vars.antiplayernum >= 0) { - if (onscreen) { + if (needsupdate) { chr0f0220ec(chr, lvupdate240, true); } else if (model->anim->animnum2 != 0) { chr0f0220ec(chr, lvupdate240, false); @@ -2557,7 +2557,7 @@ s32 chrTick(struct prop *prop) chr0f0220ec(chr, lvupdate240, true); } } - } else if (onscreen) { + } else if (needsupdate) { if (chr->act_stand.playwalkanim == true) { chr0f0220ec(chr, lvupdate240, false); } else { @@ -2568,34 +2568,34 @@ s32 chrTick(struct prop *prop) } } } else if (chr->actiontype == ACT_DEAD) { - onscreen = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true); + needsupdate = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true); } else if (prop->type == PROPTYPE_PLAYER && (g_Vars.mplayerisrunning || (player = g_Vars.players[playermgrGetPlayerNumByProp(prop)], player->cameramode == CAMERAMODE_EYESPY) || (player->cameramode == CAMERAMODE_THIRDPERSON && player->visionmode == VISIONMODE_SLAYERROCKET))) { model->anim->average = false; chr0f0220ec(chr, lvupdate240, true); - onscreen = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true); + needsupdate = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true); } else { - invalidframe2 = false; + isrepeatframe2 = false; if (fulltick) { model->anim->average = false; chr0f0220ec(chr, lvupdate240, true); } - if (chr->model && chr->model->anim && (g_Anims[chr->model->anim->animnum].flags & ANIMFLAG_HASREMAPPEDFRAMES)) { + if (chr->model && chr->model->anim && (g_Anims[chr->model->anim->animnum].flags & ANIMFLAG_HASREPEATFRAMES)) { animLoadHeader(chr->model->anim->animnum); - invalidframe2 = animGetRemappedFrame(chr->model->anim->animnum, chr->model->anim->framea) < 0 + isrepeatframe2 = animGetRemappedFrame(chr->model->anim->animnum, chr->model->anim->framea) < 0 || (animGetRemappedFrame(chr->model->anim->animnum, chr->model->anim->frameb) < 0 && chr->model->anim->frac != 0.0f); } - if (invalidframe2) { - onscreen = false; + if (isrepeatframe2) { + needsupdate = false; } else { - onscreen = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true); + needsupdate = func0f08e8ac(prop, &prop->pos, modelGetEffectiveScale(model), true); } } @@ -2612,17 +2612,17 @@ s32 chrTick(struct prop *prop) } if (prop->pos.y < -65536) { - onscreen = false; + needsupdate = false; } #if VERSION >= VERSION_NTSC_1_0 - if (!g_Vars.normmplayerisrunning && onscreen) { + if (!g_Vars.normmplayerisrunning && needsupdate) { if (chr->actiontype == ACT_DEAD || (chr->actiontype == ACT_DRUGGEDKO && (chr->chrflags & CHRCFLAG_KEEPCORPSEKO) == 0)) { var8009cdac++; if (var8009cdac > 10) { - onscreen = false; + needsupdate = false; chrDropItemsForOwnerReap(chr); chr->hidden |= CHRHFLAG_REAPED; } @@ -2631,12 +2631,12 @@ s32 chrTick(struct prop *prop) } if (var8009cdb0 + var8009cdac > 30) { - onscreen = false; + needsupdate = false; } } #endif - if (onscreen) { + if (needsupdate) { #if VERSION == VERSION_NTSC_BETA || VERSION == VERSION_PAL_BETA debug0f1199f0nb(); #endif diff --git a/src/game/propobj.c b/src/game/propobj.c index e5e003818..ebbc47b14 100644 --- a/src/game/propobj.c +++ b/src/game/propobj.c @@ -11015,7 +11015,7 @@ s32 objTickPlayer(struct prop *prop) } if (model->anim) { - if (g_Anims[model->anim->animnum].flags & ANIMFLAG_02) { + if (g_Anims[model->anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) { if (g_Vars.tickmode != TICKMODE_CUTSCENE && modelGetCurAnimFrame(model) >= modelGetNumAnimFrames(model) - 1) { modelmgrFreeAnim(model->anim); @@ -11040,7 +11040,7 @@ s32 objTickPlayer(struct prop *prop) animLoadHeader(model->anim->animnum); - if ((g_Anims[model->anim->animnum].flags & ANIMFLAG_HASREMAPPEDFRAMES) + if ((g_Anims[model->anim->animnum].flags & ANIMFLAG_HASREPEATFRAMES) && animGetRemappedFrame(model->anim->animnum, model->anim->framea) < 0) { invalidframe = true; } else { diff --git a/src/include/constants.h b/src/include/constants.h index 39b07444a..15f8d0662 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -247,10 +247,10 @@ #define AMMODE_VIEW 1 #define AMMODE_EDIT 2 // unused -#define ANIMFLAG_LOOP 0x01 -#define ANIMFLAG_02 0x02 -#define ANIMFLAG_HASREMAPPEDFRAMES 0x04 -#define ANIMFLAG_HASCUTSKIPFRAMES 0x08 +#define ANIMFLAG_LOOP 0x01 +#define ANIMFLAG_ABSOLUTETRANSLATION 0x02 +#define ANIMFLAG_HASREPEATFRAMES 0x04 +#define ANIMFLAG_HASCUTSKIPFRAMES 0x08 #define ANIMFIELD_S16_ROTATE 0x01 #define ANIMFIELD_S16_TRANSLATE 0x02 diff --git a/src/include/lib/anim.h b/src/include/lib/anim.h index a6d01af3c..908d41182 100644 --- a/src/include/lib/anim.h +++ b/src/include/lib/anim.h @@ -12,7 +12,7 @@ bool animHasFrames(s16 animnum); s32 animGetNumAnimations(void); u8 *animDma(u8 *dst, u32 segoffset, u32 len); s32 animGetRemappedFrame(s16 animnum, s32 frame); -bool animRemapFrame(s16 animnum, s32 frame, s32 *frameptr); +bool animRemapFrameForLoad(s16 animnum, s32 frame, s32 *frameptr); bool animIsFrameCutSkipped(s16 animnum, s32 frame); u8 animLoadFrame(s16 animnum, s32 framenum); void animForgetFrameBirths(void); diff --git a/src/lib/anim.c b/src/lib/anim.c index 3629f3429..d28e7c3da 100644 --- a/src/lib/anim.c +++ b/src/lib/anim.c @@ -144,59 +144,81 @@ u8 *animDma(u8 *dst, u32 segoffset, u32 len) } /** - * Get a remapped frame, or return -1 if the frame is removed. + * Return -1 if the given apparent frame is a repeat frame, or if not a repeat + * frame then remap the apparent frame to a real one and return it. + * + * The end of the header can contain a sequence of shorts such as: + * -1, 55, 30 + * + * The values are iterated backwards in pairs of 2 and are terminated by -1. + * + * In each pair, the right value is the repeatfromframe and the left value is + * the repeattoframe. In the above example, apparent frames 30 to 55 are + * repeated, so the remapping looks like: + * 29 -> 29 + * 30 -> -1 + * ... + * 55 -> -1 + * 56 -> 30 + * 57 -> 31 */ -s32 animGetRemappedFrame(s16 animnum, s32 frame) +s32 animGetRemappedFrame(s16 animnum, s32 apparentframe) { u8 *ptr = (u8 *)(g_AnimHeaderBytes[g_AnimToHeaderSlot[animnum]] + g_Anims[animnum].headerlen - 2); - s32 result = frame; + s32 realframe = apparentframe; while (true) { - s16 value1 = ptr[0] << 8 | ptr[1]; - s16 value2; + s16 repeatfromframe = ptr[0] << 8 | ptr[1]; + s16 repeattoframe; - if (value1 < 0) { + if (repeatfromframe < 0) { break; } - value2 = ptr[-2] << 8 | ptr[-1]; + repeattoframe = ptr[-2] << 8 | ptr[-1]; ptr -= 4; - if (value1 <= frame) { - if (value2 < frame) { - result = result - value2 + value1 - 1; + if (repeatfromframe <= apparentframe) { + if (repeattoframe < apparentframe) { + realframe = realframe - repeattoframe + repeatfromframe - 1; } else { - result = -1; + realframe = -1; break; } } } - return result; + return realframe; } -bool animRemapFrame(s16 animnum, s32 frame, s32 *frameptr) +/** + * Similar to the above, but with the following differences: + * - Write the remapped frame to the frameptr pointer instead of returning it. + * - If the apparent frame is a repeat, write the original frame rather than -1. + * - Return true if the frame is original or false if it's a repeat. + */ +bool animRemapFrameForLoad(s16 animnum, s32 apparentframe, s32 *frameptr) { u8 *ptr = (u8 *)(g_AnimHeaderBytes[g_AnimToHeaderSlot[animnum]] + g_Anims[animnum].headerlen - 2); - s32 result = frame; + s32 result = apparentframe; bool ret = true; while (true) { - s16 value1 = ptr[0] << 8 | ptr[1]; - s16 value2; + s16 repeatfromframe = ptr[0] << 8 | ptr[1]; + s16 repeattoframe; - if (value1 < 0) { + if (repeatfromframe < 0) { break; } - value2 = ptr[-2] << 8 | ptr[-1]; + repeattoframe = ptr[-2] << 8 | ptr[-1]; ptr -= 4; - if (value1 <= frame) { - if (value2 < frame) { - result = result - value2 + value1 - 1; + if (repeatfromframe <= apparentframe) { + if (repeattoframe < apparentframe) { + result = result - repeattoframe + repeatfromframe - 1; } else { - result = result - frame + value1; + result = result - apparentframe + repeatfromframe; ret = false; break; } @@ -214,19 +236,19 @@ bool animRemapFrame(s16 animnum, s32 frame, s32 *frameptr) * Used by cutscenes. * * The skip frame numbers are stored at the tail end of the header, prior to the - * frame remapping data. The frame numbers are stored as a list of shorts. + * frame repeat data. The frame numbers are stored as a list of shorts. * The list is terminated on the left side with a negative value. */ bool animIsFrameCutSkipped(s16 animnum, s32 frame) { u8 *ptr = (u8 *)(g_AnimHeaderBytes[g_AnimToHeaderSlot[animnum]] + g_Anims[animnum].headerlen - 2); - // Iterate past the ANIMFLAG_HASREMAPPEDFRAMES stuff - if (g_Anims[animnum].flags & ANIMFLAG_HASREMAPPEDFRAMES) { + // Iterate past the repeat list + if (g_Anims[animnum].flags & ANIMFLAG_HASREPEATFRAMES) { while (true) { - s16 value1 = ptr[0] << 8 | ptr[1]; + s16 repeatfromframe = ptr[0] << 8 | ptr[1]; - if (value1 < 0) { + if (repeatfromframe < 0) { break; } @@ -237,13 +259,13 @@ bool animIsFrameCutSkipped(s16 animnum, s32 frame) } while (true) { - s16 value2 = ptr[0] << 8 | ptr[1]; + s16 skipframe = ptr[0] << 8 | ptr[1]; - if (value2 < 0) { + if (skipframe < 0) { break; } - if (value2 == frame) { + if (skipframe == frame) { return true; } @@ -277,8 +299,8 @@ u8 animLoadFrame(s16 animnum, s32 framenum) slot = (slot + 1) % ANIM_FRAME_CACHE_SIZE; } - if (g_Anims[animnum].flags & ANIMFLAG_HASREMAPPEDFRAMES) { - animRemapFrame(animnum, framenum, &loadframenum); + if (g_Anims[animnum].flags & ANIMFLAG_HASREPEATFRAMES) { + animRemapFrameForLoad(animnum, framenum, &loadframenum); } if (g_Anims[animnum].bytesperframe) { diff --git a/src/lib/model.c b/src/lib/model.c index 0ce5cd444..b2a651fc3 100644 --- a/src/lib/model.c +++ b/src/lib/model.c @@ -791,7 +791,7 @@ void modelUpdateChrNodeMtx(struct modelrenderdata *arg0, struct model *model, st modelTweenRot(&rot3, &rot4, anim->frac2); } - if ((g_Anims[anim->animnum].flags & ANIMFLAG_02) && (g_Anims[anim->animnum2].flags & ANIMFLAG_02) == 0) { + if ((g_Anims[anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) && (g_Anims[anim->animnum2].flags & ANIMFLAG_ABSOLUTETRANSLATION) == 0) { mtx4LoadYRotation(rwdata->chrinfo.yrot, &sp78); mtx4LoadRotation(&rot3, &sp38); mtx00015be0(&sp78, &sp38); @@ -808,7 +808,7 @@ void modelUpdateChrNodeMtx(struct modelrenderdata *arg0, struct model *model, st mtx4LoadRotation(&rot1, &sp1d8); } - if (g_Anims[anim->animnum].flags & ANIMFLAG_02) { + if (g_Anims[anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) { mtx4LoadTranslation(sp254, &sp198); } else { if (rwdata->chrinfo.unk18 != 0.0f) { @@ -1082,7 +1082,7 @@ void modelUpdatePositionNodeMtx(struct modelrenderdata *renderdata, struct model skel = model->definition->skel; if (anim->animnum != 0) { - sp128 = (g_Anims[anim->animnum].flags & ANIMFLAG_02) && node == model->definition->rootnode; + sp128 = (g_Anims[anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) && node == model->definition->rootnode; animGetRotTranslateScale(animpart, anim->flip, skel, anim->animnum, anim->frameslot1, &rot1, &translate1, &scale1); @@ -1825,7 +1825,7 @@ void modelSetAnimation2(struct model *model, s16 animnum, s32 flip, f32 fstartfr f32 x; f32 z; - if (g_Anims[anim->animnum].flags & ANIMFLAG_02) { + if (g_Anims[anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) { sp64 = func0f15c888(); animLoadHeader(anim->animnum); frameslot = animLoadFrame(anim->animnum, anim->framea); @@ -1951,8 +1951,8 @@ void modelSetAnimationWithMerge(struct model *model, s16 animnum, u32 flip, f32 { if (model) { if (model->anim && model->anim->animnum - && (g_Anims[model->anim->animnum].flags & ANIMFLAG_02) - && (g_Anims[animnum].flags & ANIMFLAG_02) == 0) { + && (g_Anims[model->anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) + && (g_Anims[animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) == 0) { timemerge = 0; } @@ -1968,8 +1968,8 @@ void modelSetAnimation(struct model *model, s16 animnum, s32 flip, f32 startfram { if (model) { if (model->anim && model->anim->animnum - && (g_Anims[model->anim->animnum].flags & ANIMFLAG_02) - && (g_Anims[animnum].flags & ANIMFLAG_02) == 0) { + && (g_Anims[model->anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) + && (g_Anims[animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) == 0) { merge = 0; } @@ -2232,7 +2232,7 @@ void modelSetAnimFrame2WithChrStuff(struct model *model, f32 curframe, f32 endfr floorend = ceil(endframe); } - if (g_Anims[anim->animnum].flags & ANIMFLAG_02) { + if (g_Anims[anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) { f20 = func0f15c888(); if (floorend != anim->framea) { @@ -2463,7 +2463,7 @@ void modelSetAnimFrame2WithChrStuff(struct model *model, f32 curframe, f32 endfr anim->frame = anim->frameb + (1.0f - anim->frac); } - if (anim->animnum2 && (g_Anims[anim->animnum].flags & ANIMFLAG_02) == 0) { + if (anim->animnum2 && (g_Anims[anim->animnum].flags & ANIMFLAG_ABSOLUTETRANSLATION) == 0) { s32 floorcur2 = floor(curframe2); s32 floorend2 = floor(endframe2);