diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 91c2158e8..22cb0f00a 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -16,6 +16,7 @@ #ifdef HAVE_BLUA #include "fastcmp.h" #include "r_things.h" +#include "r_main.h" #include "p_local.h" #include "g_game.h" #include "p_setup.h" @@ -65,6 +66,8 @@ int mobj_mobjnum_unimplemented(lua_State *L); int mobj_scale_setter(lua_State *L); int mobj_destscale_setter(lua_State *L); int mobj_standingslope_noset(lua_State *L); +int mobj_rollsum_getter(lua_State *L); +int mobj_rollsum_noset(lua_State *L); static const char *const array_opt[] ={"iterate",NULL}; @@ -78,6 +81,8 @@ static const udata_field_t mobj_fields[] = { FIELD(mobj_t, angle, udatalib_getter_angle, mobj_angle_setter), FIELD(mobj_t, rollangle, udatalib_getter_angle, udatalib_setter_angle), FIELD(mobj_t, sloperoll, udatalib_getter_angle, mobj_sloperoll_noop), + // Macro fails here + { "rollsum", 0, mobj_rollsum_getter, mobj_rollsum_noset }, FIELD(mobj_t, sprite, udatalib_getter_spritenum, udatalib_setter_spritenum), FIELD(mobj_t, frame, udatalib_getter_uint32, udatalib_setter_uint32), FIELD(mobj_t, anim_duration, udatalib_getter_uint16, udatalib_setter_uint16), @@ -174,13 +179,21 @@ int mobj_ ## field ## _noset(lua_State *L) \ return luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " should not be set directly.", #field); \ } +#define NOSET_USE(field, use) \ +int mobj_ ## field ## _noset(lua_State *L) \ +{ \ + return luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " should not be set directly. Use " LUA_QL(use) " instead.", #field); \ +} + NOSET(snext) NOSET(bnext) NOSET(info) NOSET(player) NOSET(standingslope) +NOSET_USE(rollsum, "rollangle") #undef NOSET +#undef NOSET_USE // Unimplemented fields (why would you need to set them like that explicitly? // No idea, i'm keeping it for synch reasons) @@ -539,6 +552,24 @@ int mobj_destscale_setter(lua_State *L) return 0; } +// WARNING: Not synch safe! +// Don't use this field in game logic code! +int mobj_rollsum_getter(lua_State *L) +{ + mobj_t *mo = GETMO(); + + angle_t rollsum = mo->rollangle + cv_sloperoll.value ? mo->sloperoll : 0; + + if (mo->player) + { + rollsum += R_PlayerSliptideAngle(mo->player); + } + + lua_pushangle(L, rollsum); + + return 1; +} + static int mobj_get(lua_State *L) { mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index c687921ec..8ce7840f3 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -13,6 +13,7 @@ #include "doomdef.h" #ifdef HAVE_BLUA #include "fastcmp.h" +#include "r_main.h" #include "p_mobj.h" #include "d_player.h" #include "g_game.h" @@ -44,6 +45,10 @@ int player_splitscreenindex_noset(lua_State *L); int player_ping_getter(lua_State *L); int player_ping_noset(lua_State *L); +// Non synch safe! +int player_sliproll_getter(lua_State *L); +int player_sliproll_noset(lua_State *L); + #define FIELD(type, field_name, getter, setter) { #field_name, offsetof(type, field_name), getter, setter } static const udata_field_t player_fields[] = { // Player doesn't actually have field "name" so macro fails. Need to declare field manually. @@ -150,6 +155,7 @@ static const udata_field_t player_fields[] = { FIELD(player_t, fovadd, udatalib_getter_fixed, udatalib_setter_fixed), // Mmm yeah thats definitely synch safe #endif // Same as player.name + { "sliproll", 0, player_sliproll_getter, player_sliproll_noset }, { "ping", 0, player_ping_getter, player_ping_noset }, // Hmm originally setter doesn't exist so data is written as unreachable custom field... { NULL }, }; @@ -207,6 +213,7 @@ NOSET(kartstuff) NOSET(bot) NOSET(splitscreenindex) NOSET(ping) +NOSET(sliproll) #undef NOSET @@ -331,6 +338,15 @@ int player_ping_getter(lua_State *L) return 1; } +int player_sliproll_getter(lua_State *L) +{ + player_t *plr = GETPLAYER(); + + lua_pushangle(L, R_PlayerSliptideAngle(plr)); + + return 1; +} + static int lib_iteratePlayers(lua_State *L) { INT32 i = -1; diff --git a/src/r_defs.h b/src/r_defs.h index 559e3646b..26a11a6c0 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -19,6 +19,7 @@ // We rely on the thinker data struct to handle sound origins in sectors. #include "d_think.h" + // SECTORS do store MObjs anyway. #include "p_mobj.h" diff --git a/src/r_main.c b/src/r_main.c index dc914e79a..c381c9860 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -439,6 +439,60 @@ fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1) return FixedHypot(px1 - px2, py1 - py2); } +angle_t R_PlayerSliptideAngle(player_t *player) +{ + mobj_t *mo = player->mo; + + if (!cv_sliptideroll.value || !mo || P_MobjWasRemoved(mo)) return 0; + + size_t rot = mo->frame&FF_FRAMEMASK; + boolean papersprite = (mo->frame & FF_PAPERSPRITE); + + spritedef_t *sprdef; + spriteframe_t *sprframe; + angle_t ang = 0; + + interpmobjstate_t interp = {0}; + + // Yes. + if (R_UsingFrameInterpolation() && !paused) + { + R_InterpolateMobjState(mo, rendertimefrac, &interp); + } + else + { + R_InterpolateMobjState(mo, FRACUNIT, &interp); + } + + if (mo->skin && mo->sprite == SPR_PLAY) + { + sprdef = &((skin_t *)mo->skin)->spritedef; + + if (rot >= sprdef->numframes) + sprdef = &sprites[mo->sprite]; + } + else + { + sprdef = &sprites[mo->sprite]; + } + + if (rot >= sprdef->numframes) + { + sprdef = &sprites[states[S_UNKNOWN].sprite]; + rot = states[S_UNKNOWN].frame&FF_FRAMEMASK; + } + + sprframe = &sprdef->spriteframes[rot]; + + // No sprite frame? I guess it is possible + if (!sprframe) return 0; + + if (sprframe->rotate != SRF_SINGLE || papersprite) + ang = R_PointToAngle(interp.x, interp.y) - interp.angle; + + return FixedMul(FINECOSINE((ang) >> ANGLETOFINESHIFT), mo->player->sliproll*(mo->player->sliptidemem)); +} + // Little extra utility. Works in the same way as R_PointToAngle2 fixed_t R_PointToDist(fixed_t x, fixed_t y) { diff --git a/src/r_main.h b/src/r_main.h index 70adf1bb5..d6c966857 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -73,6 +73,7 @@ angle_t R_PointToAngle2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1); angle_t R_PointToAngleEx(INT32 x2, INT32 y2, INT32 x1, INT32 y1); fixed_t R_PointToDist(fixed_t x, fixed_t y); fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1); +angle_t R_PlayerSliptideAngle(player_t *player); fixed_t R_ScaleFromGlobalAngle(angle_t visangle); subsector_t *R_PointInSubsector(fixed_t x, fixed_t y);