diff --git a/src/game/bg.c b/src/game/bg.c index 0b2c0b03b..3eaf35fc9 100644 --- a/src/game/bg.c +++ b/src/game/bg.c @@ -984,7 +984,9 @@ Gfx *bgRenderScene(Gfx *gdl) s16 roomorder[60]; RoomNum roomnums[60]; +#ifdef PLATFORM_N64 g_NumRoomsWithGlares = 0; +#endif if (g_Vars.currentplayer->visionmode == VISIONMODE_XRAY) { gdl = bgRenderSceneInXray(gdl); @@ -1206,6 +1208,7 @@ Gfx *bgRenderScene(Gfx *gdl) gdl = propsRender(gdl, thing->roomnum, RENDERPASS_XLU, roomnumsbyprop); } +#ifdef PLATFORM_N64 // on PC we do this earlier, before prop matrices turn into garbage if (!g_Vars.mplayerisrunning) { artifactsCalculateGlaresForRoom(thing->roomnum); @@ -1213,6 +1216,7 @@ Gfx *bgRenderScene(Gfx *gdl) g_GlareRooms[g_NumRoomsWithGlares++] = thing->roomnum; } } +#endif } #if VERSION < VERSION_NTSC_1_0 @@ -6397,3 +6401,21 @@ void bgFindEnteredRooms(struct coord *bbmin, struct coord *bbmax, RoomNum *rooms end: rooms[len] = -1; } + +#ifndef PLATFORM_N64 + +void bgCalculateGlaresForVisibleRooms(void) +{ + s32 i; + g_NumRoomsWithGlares = 0; + for (i = 1; i < g_Vars.roomcount; i++) { + if (g_Rooms[i].flags & ROOMFLAG_ONSCREEN) { + artifactsCalculateGlaresForRoom(i); + if (g_NumRoomsWithGlares < 100) { + g_GlareRooms[g_NumRoomsWithGlares++] = i; + } + } + } +} + +#endif diff --git a/src/game/game_13c510.c b/src/game/game_13c510.c index 6258fff51..8ac5f0515 100644 --- a/src/game/game_13c510.c +++ b/src/game/game_13c510.c @@ -20,7 +20,7 @@ #include "lib/collision.h" #include "lib/lib_17ce0.h" #include "game/player.h" -f32 fabsf(f32 value); +#include "game/prop.h" #endif u8 *var800a41a0; @@ -104,8 +104,10 @@ s32 func0f13c710(f32 arg0) #ifndef PLATFORM_N64 -bool artifactTestLos(struct coord *spec, struct coord *roompos) +bool artifactTestLos(struct coord *spec, struct coord *roompos, s32 xi, s32 yi) { + s32 i = 0; + if (!g_Vars.currentplayer) { return false; } @@ -115,35 +117,15 @@ bool artifactTestLos(struct coord *spec, struct coord *roompos) endpos.y = roompos->y + spec->y; endpos.z = roompos->z + spec->z; - // get what rooms the LOS goes through - RoomNum outrooms[17], tmprooms[8], srcrooms[2]; - srcrooms[0] = g_Vars.currentplayer->cam_room; - srcrooms[1] = -1; - outrooms[16] = -1; - portal00018148(&g_Vars.currentplayer->cam_pos, &endpos, srcrooms, tmprooms, outrooms, 16); - - // cheaper LOS test against props first - const u32 cdtype = CDTYPE_OBJS | CDTYPE_DOORS | CDTYPE_PLAYERS | CDTYPE_CHRS; - const u16 geoflags = GEOFLAG_BLOCK_SIGHT | GEOFLAG_BLOCK_SHOOT; - if (!cdTestAToB(&g_Vars.currentplayer->cam_pos, &endpos, outrooms, cdtype, geoflags, true, 1, 0, 0)) { - return false; - } - - // no prop was hit; check for bg hits - struct hitthing hit; - for (s32 i = 0; outrooms[i] != -1; ++i) { - if (bgTestHitInRoom(&g_Vars.currentplayer->cam_pos, &endpos, outrooms[i], &hit)) { - // check if it's far enough away from the end point - if (fabsf(hit.pos.x - endpos.x) >= 0.1f || - fabsf(hit.pos.y - endpos.y) >= 0.1f || - fabsf(hit.pos.z - endpos.z) >= 0.1f) { - return false; - } - } - } + struct coord gundir2d; + struct coord gunpos2d = {{ 0.f, 0.f, 0.f }}; + struct coord gundir3d; + struct coord gunpos3d = g_Vars.currentplayer->cam_pos; + f32 crosspos[2] = { (f32)xi, (f32)yi }; + cam0f0b4c3c(crosspos, &gundir2d, 1.f); + mtx4RotateVec(camGetProjectionMtxF(), &gundir2d, &gundir3d); - // nothing hit - return true; + return shotTestLos(&gunpos2d, &gundir2d, &gunpos3d, &gundir3d, &endpos); } #endif @@ -380,7 +362,7 @@ void artifactsCalculateGlaresForRoom(s32 roomnum) if (index < MAX_ARTIFACTS) { #ifndef PLATFORM_N64 - artifact->unk02 = artifactTestLos(&spec, &g_BgRooms[roomnum].pos); + artifact->unk02 = artifactTestLos(&spec, &g_BgRooms[roomnum].pos, xi, yi); #endif artifact->unk04 = func0f13c574(f0) >> 2; artifact->unk08 = &g_ZbufPtr1[viGetWidth() * yi + xi]; diff --git a/src/game/lv.c b/src/game/lv.c index 1c746b77d..c19cfbede 100644 --- a/src/game/lv.c +++ b/src/game/lv.c @@ -1194,6 +1194,11 @@ Gfx *lvRender(Gfx *gdl) autoaimTick(); handsTickAttack(); +#ifndef PLATFORM_N64 + // glares calculated earlier on PC, before prop matrices turn into garbage + bgCalculateGlaresForVisibleRooms(); +#endif + // Calculate lookingatprop if (PLAYERCOUNT() == 1 || g_Vars.coopplayernum >= 0 diff --git a/src/game/prop.c b/src/game/prop.c index 92505fa3a..4dbbba9f0 100644 --- a/src/game/prop.c +++ b/src/game/prop.c @@ -973,6 +973,117 @@ struct prop *shotCalculateHits(s32 handnum, bool isshooting, struct coord *gunpo return result; } +#ifndef PLATFORM_N64 + +/** + * Checks if the specified line of sight (gunpos3d - endpos3d) intersects any props or BG, + * using the same process as shotCalculateHits, except with no side effects and cheap = true. + * Returns true if nothing was hit. + */ +bool shotTestLos(struct coord *gunpos2d, struct coord *gundir2d, struct coord *gunpos3d, struct coord *gundir3d, struct coord *endpos3d) +{ + struct prop **propptr; + struct hitthing sp664; + struct coord delta; + struct shotdata shotdata; + s32 i; + RoomNum rooms[131]; + RoomNum spc8[8]; + RoomNum spb8[8]; + RoomNum *roomsptr; + struct prop *prop; + + shotdata.gunpos3d.x = gunpos3d->x; + shotdata.gunpos3d.y = gunpos3d->y; + shotdata.gunpos3d.z = gunpos3d->z; + + shotdata.gunpos2d.x = gunpos2d->x; + shotdata.gunpos2d.y = gunpos2d->y; + shotdata.gunpos2d.z = gunpos2d->z; + + shotdata.gundir3d.x = gundir3d->x; + shotdata.gundir3d.y = gundir3d->y; + shotdata.gundir3d.z = gundir3d->z; + + shotdata.gundir2d.x = gundir2d->x; + shotdata.gundir2d.y = gundir2d->y; + shotdata.gundir2d.z = gundir2d->z; + + // use falcon2 as a dummy weapon + shotdata.gset.weaponnum = WEAPON_FALCON2; + shotdata.gset.weaponfunc = 0; + shotdata.gset.unk063a = 0; + shotdata.gset.unk0639 = 0; + + shotdata.penetration = 1; + shotdata.distance = 999999999.f; + + for (i = 0; i < ARRAYCOUNT(shotdata.hits); i++) { + shotdata.hits[i].prop = NULL; + shotdata.hits[i].hitpart = 0; + shotdata.hits[i].bboxnode = NULL; + } + + rooms[0] = rooms[130] = -1; + spc8[0] = g_Vars.currentplayer->cam_room; + spc8[1] = -1; + portal00018148(&shotdata.gunpos3d, endpos3d, spc8, spb8, rooms, 30); + + roomsptr = rooms; + + while (*roomsptr != -1) { + roomsptr++; + } + + // Note this is being appended to rooms + bgGetForceOnscreenRooms(roomsptr, 100); + + // Check for BG hits first + for (i = 0; rooms[i] != -1; i++) { + if (bgTestHitInRoom(&shotdata.gunpos3d, endpos3d, rooms[i], &sp664)) { + // check if it's far enough away from the end point + if (fabsf(sp664.pos.x - endpos3d->x) >= 0.1f || + fabsf(sp664.pos.y - endpos3d->y) >= 0.1f || + fabsf(sp664.pos.z - endpos3d->z) >= 0.1f) { + return false; + } + } + } + + // didn't hit any bg, shrink distance to the line size + delta.x = endpos3d->x - gunpos3d->x; + delta.y = endpos3d->y - gunpos3d->y; + delta.z = endpos3d->z - gunpos3d->z; + shotdata.distance = sqrtf(delta.x * delta.x + delta.y * delta.y + delta.z * delta.z); + + // and check props + propptr = g_Vars.endonscreenprops - 1; + while (propptr >= g_Vars.onscreenprops) { + prop = *propptr; + if (prop) { + if (prop->type == PROPTYPE_CHR + || (prop->type == PROPTYPE_PLAYER && prop->chr && playermgrGetPlayerNumByProp(prop) != g_Vars.currentplayernum)) { + chrTestHit(prop, &shotdata, false, true); + } else if (prop->type == PROPTYPE_WEAPON || prop->type == PROPTYPE_DOOR + || (prop->type == PROPTYPE_OBJ && prop->obj->type != OBJTYPE_GLASS && prop->obj->type != OBJTYPE_TINTEDGLASS)) { + objTestHit(prop, &shotdata); + } + if (shotdata.hits[0].prop) { + // ignore some glass parts and shields + if (shotdata.hits[0].slowsbullet && shotdata.hits[0].hitthing.texturenum != 10000) { + return false; + } + } + } + propptr--; + } + + // did not hit anything + return true; +} + +#endif + struct prop *propFindAimingAt(s32 handnum, bool isshooting, u32 context) { struct coord gundir2d; diff --git a/src/game/sky.c b/src/game/sky.c index e46110911..e610cad83 100644 --- a/src/game/sky.c +++ b/src/game/sky.c @@ -2518,7 +2518,7 @@ void skyCreateSunArtifact(struct artifact *artifact, s32 x, s32 y) sunpos.x = env->suns[i].pos[0]; sunpos.y = env->suns[i].pos[1]; sunpos.z = env->suns[i].pos[2]; - artifact->unk02 = artifactTestLos(&sunpos, &zero) * 0xfffc; + artifact->unk02 = artifactTestLos(&sunpos, &zero, x, y) * 0xfffc; #endif artifact->unk08 = &g_ZbufPtr1[(s32)camGetScreenWidth() * y + x]; artifact->unk0c.u16_2 = x; diff --git a/src/include/game/bg.h b/src/include/game/bg.h index 0ac8645ca..89b6c7550 100644 --- a/src/include/game/bg.h +++ b/src/include/game/bg.h @@ -102,5 +102,8 @@ s32 bgFindPortalBetweenPositions(struct coord *pos1, struct coord *pos2); bool bgIsBboxOverlapping(struct coord *arg0, struct coord *arg1, struct coord *arg2, struct coord *arg3); void bgCalculatePortalBbox(s32 portalnum, struct coord *bbmin, struct coord *bbmax); void bgFindEnteredRooms(struct coord *bbmin, struct coord *upper, RoomNum *rooms, s32 maxlen, bool arg4); +#ifndef PLATFORM_N64 +void bgCalculateGlaresForVisibleRooms(void); +#endif #endif diff --git a/src/include/game/game_13c510.h b/src/include/game/game_13c510.h index 187cbc6ce..d8ee2f6dd 100644 --- a/src/include/game/game_13c510.h +++ b/src/include/game/game_13c510.h @@ -14,7 +14,7 @@ Gfx *artifactsConfigureForGlares(Gfx *gdl); Gfx *artifactsUnconfigureForGlares(Gfx *gdl); Gfx *artifactsRenderGlaresForRoom(Gfx *gdl, s32 roomnum); #ifndef PLATFORM_N64 -bool artifactTestLos(struct coord *spec, struct coord *roompos); +bool artifactTestLos(struct coord *spec, struct coord *roompos, s32 xi, s32 yi); #endif #endif diff --git a/src/include/game/prop.h b/src/include/game/prop.h index 2105cc061..cdbab1737 100644 --- a/src/include/game/prop.h +++ b/src/include/game/prop.h @@ -65,4 +65,8 @@ void propsDefragRoomProps(void); void propGetBbox(struct prop *prop, f32 *radius, f32 *ymax, f32 *ymin); bool propUpdateGeometry(struct prop *prop, u8 **start, u8 **end); +#ifndef PLATFORM_N64 +bool shotTestLos(struct coord *gunpos2d, struct coord *gundir2d, struct coord *gunpos3d, struct coord *gundir3d, struct coord *endpos3d); +#endif + #endif