From 1c12b284983a1695f4bc06b1ba81b66d9e1c29b0 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 29 Oct 2023 22:04:50 +0000 Subject: [PATCH] Blend Eye Hardcode part 2 - VS_ArenaCenterInit - setting up the boss arena centerpoint - VS_GetArena - Getting a particular arena - VS_PredictAroundArena - Predict momentum of object around arena - VS_RandomPointOnArena - Select random position around arena --- src/k_boss.h | 7 ++ src/lua_baselib.c | 46 +++++++++++ src/objects/CMakeLists.txt | 2 + src/objects/versus/CMakeLists.txt | 3 + src/objects/versus/arena.c | 129 ++++++++++++++++++++++++++++++ src/p_mobj.c | 10 +++ 6 files changed, 197 insertions(+) create mode 100644 src/objects/versus/CMakeLists.txt create mode 100644 src/objects/versus/arena.c diff --git a/src/k_boss.h b/src/k_boss.h index 8e41e0cdf..c89e7932f 100644 --- a/src/k_boss.h +++ b/src/k_boss.h @@ -129,6 +129,13 @@ void K_DeclareWeakspot(mobj_t *spot, spottype_t spottype, UINT16 color, boolean boolean K_CheckBossIntro(void); +// Arena objects + +boolean VS_ArenaCenterInit(mobj_t *mobj, mapthing_t *mthing); +mobj_t *VS_GetArena(INT32 bossindex); +fixed_t *VS_PredictAroundArena(mobj_t *arena, mobj_t *movingobject, fixed_t magnitude, angle_t mompoint, fixed_t radiussubtract, boolean forcegoaround, fixed_t radiusdeltafactor); +fixed_t *VS_RandomPointOnArena(mobj_t *arena, fixed_t radiussubtract); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/lua_baselib.c b/src/lua_baselib.c index d19e2b0c9..2395614b0 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3529,6 +3529,49 @@ static int lib_kDeclareWeakspot(lua_State *L) return 0; } +static int lib_vsGetArena(lua_State *L) +{ + INT32 bossindex = luaL_checkinteger(L, 1); + //HUDSAFE + LUA_PushUserdata(L, VS_GetArena(bossindex), META_MOBJ); + return 1; +} + +static int lib_vsPredictAroundArena(lua_State *L) +{ + mobj_t *arena = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + mobj_t *movingobject = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); + fixed_t magnitude = luaL_checkfixed(L, 3); + fixed_t mompoint = luaL_checkangle(L, 4); + fixed_t radiussubtract = luaL_checkfixed(L, 5); + boolean forcegoaround = lua_optboolean(L, 6); + fixed_t radiusdeltafactor = luaL_optinteger(L, 7, FRACUNIT); //optfixed? + NOHUD + if (!arena || !movingobject) + return LUA_ErrInvalid(L, "mobj_t"); + + fixed_t *result = VS_PredictAroundArena(arena, movingobject, magnitude, mompoint, radiussubtract, forcegoaround, radiusdeltafactor); + + lua_pushfixed(L, result[0]); + lua_pushfixed(L, result[1]); + return 2; +} + +static int lib_vsRandomPointOnArena(lua_State *L) +{ + mobj_t *arena = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + fixed_t radiussubtract = luaL_checkfixed(L, 2); + NOHUD + if (!arena) + return LUA_ErrInvalid(L, "mobj_t"); + + fixed_t *result = VS_RandomPointOnArena(arena, radiussubtract); + + lua_pushfixed(L, result[0]); + lua_pushfixed(L, result[1]); + return 2; +} + static int lib_getTimeMicros(lua_State *L) { lua_pushinteger(L, I_GetPreciseTime() / (I_GetPrecisePrecision() / 1000000)); @@ -3804,6 +3847,9 @@ static luaL_Reg lib[] = { {"K_InitBossHealthBar", lib_kInitBossHealthBar}, {"K_UpdateBossHealthBar", lib_kUpdateBossHealthBar}, {"K_DeclareWeakspot", lib_kDeclareWeakspot}, + {"VS_GetArena", lib_vsGetArena}, + {"VS_PredictAroundArena", lib_vsPredictAroundArena}, + {"VS_RandomPointOnArena", lib_vsRandomPointOnArena}, // hu_stuff technically? {"HU_DoTitlecardCEcho", lib_startTitlecardCecho}, diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index 1e99c2f0f..1e035d52d 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -40,3 +40,5 @@ target_sources(SRB2SDL2 PRIVATE shadow.cpp ball-switch.cpp ) + +add_subdirectory(versus) diff --git a/src/objects/versus/CMakeLists.txt b/src/objects/versus/CMakeLists.txt new file mode 100644 index 000000000..4addf9bfc --- /dev/null +++ b/src/objects/versus/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(SRB2SDL2 PRIVATE + arena.c +) diff --git a/src/objects/versus/arena.c b/src/objects/versus/arena.c new file mode 100644 index 000000000..2e26fd9ef --- /dev/null +++ b/src/objects/versus/arena.c @@ -0,0 +1,129 @@ +#include "../../p_local.h" +#include "../../p_setup.h" +#include "../../m_random.h" +#include "../../k_boss.h" +#include "../../r_main.h" // R_PointToAngle2, R_PointToDist2 + +boolean VS_ArenaCenterInit(mobj_t *mobj, mapthing_t *mthing) +{ + INT32 dist1 = mthing->thing_args[1]*FRACUNIT; + INT32 dist2 = mthing->thing_args[2]*FRACUNIT; + + if (dist1 || dist2) + { + if (dist1 > dist2) + { + INT32 swap = dist1; + dist1 = dist2; + dist2 = swap; + } + + mobj->extravalue1 = dist1; + mobj->extravalue2 = dist2; + return true; + } + + CONS_Alert(CONS_ERROR, "Versus arena of index %d has no max radius.", mthing->thing_args[0]); + return false; +} + +mobj_t *VS_GetArena(INT32 bossindex) +{ + size_t i; + + for (i = 0; i < nummapthings; ++i) + { + if (mapthings[i].type != mobjinfo[MT_BOSSARENACENTER].doomednum) + continue; + + if (mapthings[i].thing_args[0] != bossindex) + continue; + + if (mapthings[i].mobj == NULL) + continue; + + return mapthings[i].mobj; + } + + CONS_Alert(CONS_ERROR, "No Versus arena of index %d found.", bossindex); + return NULL; +} + +fixed_t *VS_PredictAroundArena(mobj_t *arena, mobj_t *movingobject, fixed_t magnitude, angle_t mompoint, fixed_t radiussubtract, boolean forcegoaround, fixed_t radiusdeltafactor) +{ + static fixed_t dest[2] = {0, 0}; + + if (P_MobjWasRemoved(arena) || P_MobjWasRemoved(movingobject)) + return dest; + + fixed_t radius = FixedHypot(movingobject->x - arena->x, movingobject->y - arena->y); + angle_t basedir = R_PointToAngle2(arena->x, arena->y, movingobject->x, movingobject->y); + fixed_t radiusdelta = 0; + + const fixed_t minarena = arena->extravalue1 + radiussubtract; + const fixed_t maxarena = arena->extravalue2 - radiussubtract; + + mompoint -= basedir; + + if (radiusdeltafactor > 0) // for kneecapping the prediction + { + boolean clipped = false; + + // Add radius so we can compare against the arena size. + radiusdelta = radius + P_ReturnThrustX(arena, mompoint, magnitude); + + if (radiusdelta > maxarena) + { + radiusdelta = maxarena; + clipped = true; + } + else if (radiusdelta < minarena) + { + radiusdelta = minarena; + clipped = true; + } + + if (clipped == true && forcegoaround == true) + { + mompoint = (mompoint < ANGLE_180) ? ANGLE_90 : ANGLE_270; + } + + // Subtract the radius so it's usable as a delta! + radiusdelta -= radius; + + if (radiusdelta) + radiusdelta = FixedDiv(radiusdelta, radiusdeltafactor); + } + + radius += (radiusdelta/2); // average... + if (radius > 0) + { + fixed_t sidecomponent = P_ReturnThrustY(arena, mompoint, magnitude); + // percent*(TAU/100)% of circumference = radians*r, so divide by r to reverse that + fixed_t radians = FixedDiv(sidecomponent, radius); + basedir += FixedAngle(FixedDiv(360*radians, M_TAU_FIXED)); // converting to degrees along the way. + } + radius += (radiusdelta/2); // ...and then finalise! + + dest[0] = arena->x + P_ReturnThrustX(arena, basedir, radius); + dest[1] = arena->y + P_ReturnThrustY(arena, basedir, radius); + return dest; +} + +fixed_t *VS_RandomPointOnArena(mobj_t *arena, fixed_t radiussubtract) +{ + static fixed_t dest[2] = {0, 0}; + + if (P_MobjWasRemoved(arena)) + return dest; + + const fixed_t minarena = arena->extravalue1 + radiussubtract; + const fixed_t maxarena = arena->extravalue2 - radiussubtract; + + angle_t rand1 = FixedAngle(P_RandomKey(PR_MOVINGTARGET, 360)*FRACUNIT); + fixed_t rand2 = P_RandomRange(PR_MOVINGTARGET, minarena/FRACUNIT, maxarena/FRACUNIT)*FRACUNIT; + dest[0] = arena->x + P_ReturnThrustX(arena, rand1, rand2); + dest[1] = arena->y + P_ReturnThrustY(arena, rand1, rand2); + + return dest; +} diff --git a/src/p_mobj.c b/src/p_mobj.c index a40645b48..58f393bea 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -38,6 +38,7 @@ // SRB2kart #include "k_kart.h" +#include "k_boss.h" #include "k_battle.h" #include "k_color.h" #include "k_follower.h" @@ -13417,6 +13418,15 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj) P_InitSkyboxPoint(mobj, mthing); break; } + case MT_BOSSARENACENTER: + { + if (!VS_ArenaCenterInit(mobj, mthing)) + { + P_RemoveMobj(mobj); + return false; + } + break; + } case MT_EGGSTATUE: if (mthing->thing_args[1]) {