Added lua profiler; Added useful object functions; Bug fixes (#65)
Added a basic lua profiler If the game is compiled with LUA_PROFILER=1, displays on screen the average execution time per frame of each active lua mod, in microseconds. Added object functions For some reasons, accessing the object fields obj.o* via lua is rather slow, and can drastically increase execution time of custom behaviors. For basic stuff like setting an object's velocity or moving it, some functions, missing from the original code, have been added: s32 obj_is_valid_for_interaction(struct Object *o): returns 1 if an object is valid for interaction, i.e. active, tangible and not interacted. s32 obj_check_hitbox_overlap(struct Object *o1, struct Object *o2): returns 1 if two objects hitboxes overlap. Doesn't check tangibility, only hitbox values. void obj_set_vel(struct Object *o, f32 vx, f32 vy, f32 vz): sets an object's velocity. void obj_move_xyz(struct Object *o, f32 dx, f32 dy, f32 dz): moves an object position by (dx, dy, dz). Bug fixes: Disable collisions with walls and ceilings after Mario exits a warp pipe to prevent softlocks in narrow places. Make the koopa shell exclamation box respawn after some time. Quicksand no longer downwarps and instant-kills Mario if he's shocked while being above it.
This commit is contained in:
parent
d40a020d04
commit
ee9dbc6e80
9
Makefile
9
Makefile
|
@ -21,6 +21,9 @@ DEBUG ?= 0
|
|||
# Enable development/testing flags
|
||||
DEVELOPMENT ?= 0
|
||||
|
||||
# Enable lua profiler
|
||||
LUA_PROFILER ?= 0
|
||||
|
||||
# Build for the N64 (turn this off for ports)
|
||||
TARGET_N64 = 0
|
||||
|
||||
|
@ -972,6 +975,12 @@ ifeq ($(DEVELOPMENT),1)
|
|||
CFLAGS += -DDEVELOPMENT
|
||||
endif
|
||||
|
||||
# Check for lua profiler option
|
||||
ifeq ($(LUA_PROFILER),1)
|
||||
CC_CHECK_CFLAGS += -DLUA_PROFILER
|
||||
CFLAGS += -DLUA_PROFILER
|
||||
endif
|
||||
|
||||
# Check for texture fix option
|
||||
ifeq ($(TEXTURE_FIX),1)
|
||||
CC_CHECK_CFLAGS += -DTEXTURE_FIX
|
||||
|
|
|
@ -7176,6 +7176,13 @@ function get_trajectory(name)
|
|||
-- ...
|
||||
end
|
||||
|
||||
--- @param o1 Object
|
||||
--- @param o2 Object
|
||||
--- @return integer
|
||||
function obj_check_hitbox_overlap(o1, o2)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param objList ObjectList
|
||||
--- @return Object
|
||||
function obj_get_first(objList)
|
||||
|
@ -7252,6 +7259,21 @@ function obj_has_model_extended(o, modelId)
|
|||
-- ...
|
||||
end
|
||||
|
||||
--- @param o Object
|
||||
--- @return integer
|
||||
function obj_is_valid_for_interaction(o)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param o Object
|
||||
--- @param dx number
|
||||
--- @param dy number
|
||||
--- @param dz number
|
||||
--- @return nil
|
||||
function obj_move_xyz(o, dx, dy, dz)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param o Object
|
||||
--- @param modelId ModelExtendedId
|
||||
--- @return nil
|
||||
|
@ -7259,6 +7281,15 @@ function obj_set_model_extended(o, modelId)
|
|||
-- ...
|
||||
end
|
||||
|
||||
--- @param o Object
|
||||
--- @param vx number
|
||||
--- @param vy number
|
||||
--- @param vz number
|
||||
--- @return nil
|
||||
function obj_set_vel(o, vx, vy, vz)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param behaviorId BehaviorId
|
||||
--- @param modelId ModelExtendedId
|
||||
--- @param x number
|
||||
|
|
|
@ -1344,6 +1344,7 @@
|
|||
- smlua_obj_utils.h
|
||||
- [get_temp_object_hitbox](#get_temp_object_hitbox)
|
||||
- [get_trajectory](#get_trajectory)
|
||||
- [obj_check_hitbox_overlap](#obj_check_hitbox_overlap)
|
||||
- [obj_get_first](#obj_get_first)
|
||||
- [obj_get_first_with_behavior_id](#obj_get_first_with_behavior_id)
|
||||
- [obj_get_first_with_behavior_id_and_field_f32](#obj_get_first_with_behavior_id_and_field_f32)
|
||||
|
@ -1355,7 +1356,10 @@
|
|||
- [obj_get_temp_spawn_particles_info](#obj_get_temp_spawn_particles_info)
|
||||
- [obj_has_behavior_id](#obj_has_behavior_id)
|
||||
- [obj_has_model_extended](#obj_has_model_extended)
|
||||
- [obj_is_valid_for_interaction](#obj_is_valid_for_interaction)
|
||||
- [obj_move_xyz](#obj_move_xyz)
|
||||
- [obj_set_model_extended](#obj_set_model_extended)
|
||||
- [obj_set_vel](#obj_set_vel)
|
||||
- [spawn_non_sync_object](#spawn_non_sync_object)
|
||||
- [spawn_sync_object](#spawn_sync_object)
|
||||
|
||||
|
@ -25086,6 +25090,27 @@ The `reliable` field will ensure that the packet arrives, but should be used spa
|
|||
|
||||
<br />
|
||||
|
||||
## [obj_check_hitbox_overlap](#obj_check_hitbox_overlap)
|
||||
|
||||
### Lua Example
|
||||
`local integerValue = obj_check_hitbox_overlap(o1, o2)`
|
||||
|
||||
### Parameters
|
||||
| Field | Type |
|
||||
| ----- | ---- |
|
||||
| o1 | [Object](structs.md#Object) |
|
||||
| o2 | [Object](structs.md#Object) |
|
||||
|
||||
### Returns
|
||||
- `integer`
|
||||
|
||||
### C Prototype
|
||||
`s32 obj_check_hitbox_overlap(struct Object *o1, struct Object *o2);`
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
||||
<br />
|
||||
|
||||
## [obj_get_first](#obj_get_first)
|
||||
|
||||
### Lua Example
|
||||
|
@ -25316,6 +25341,49 @@ The `reliable` field will ensure that the packet arrives, but should be used spa
|
|||
|
||||
<br />
|
||||
|
||||
## [obj_is_valid_for_interaction](#obj_is_valid_for_interaction)
|
||||
|
||||
### Lua Example
|
||||
`local integerValue = obj_is_valid_for_interaction(o)`
|
||||
|
||||
### Parameters
|
||||
| Field | Type |
|
||||
| ----- | ---- |
|
||||
| o | [Object](structs.md#Object) |
|
||||
|
||||
### Returns
|
||||
- `integer`
|
||||
|
||||
### C Prototype
|
||||
`s32 obj_is_valid_for_interaction(struct Object *o);`
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
||||
<br />
|
||||
|
||||
## [obj_move_xyz](#obj_move_xyz)
|
||||
|
||||
### Lua Example
|
||||
`obj_move_xyz(o, dx, dy, dz)`
|
||||
|
||||
### Parameters
|
||||
| Field | Type |
|
||||
| ----- | ---- |
|
||||
| o | [Object](structs.md#Object) |
|
||||
| dx | `number` |
|
||||
| dy | `number` |
|
||||
| dz | `number` |
|
||||
|
||||
### Returns
|
||||
- None
|
||||
|
||||
### C Prototype
|
||||
`void obj_move_xyz(struct Object *o, f32 dx, f32 dy, f32 dz);`
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
||||
<br />
|
||||
|
||||
## [obj_set_model_extended](#obj_set_model_extended)
|
||||
|
||||
### Lua Example
|
||||
|
@ -25337,6 +25405,29 @@ The `reliable` field will ensure that the packet arrives, but should be used spa
|
|||
|
||||
<br />
|
||||
|
||||
## [obj_set_vel](#obj_set_vel)
|
||||
|
||||
### Lua Example
|
||||
`obj_set_vel(o, vx, vy, vz)`
|
||||
|
||||
### Parameters
|
||||
| Field | Type |
|
||||
| ----- | ---- |
|
||||
| o | [Object](structs.md#Object) |
|
||||
| vx | `number` |
|
||||
| vy | `number` |
|
||||
| vz | `number` |
|
||||
|
||||
### Returns
|
||||
- None
|
||||
|
||||
### C Prototype
|
||||
`void obj_set_vel(struct Object *o, f32 vx, f32 vy, f32 vz);`
|
||||
|
||||
[:arrow_up_small:](#)
|
||||
|
||||
<br />
|
||||
|
||||
## [spawn_non_sync_object](#spawn_non_sync_object)
|
||||
|
||||
### Lua Example
|
||||
|
|
|
@ -167,7 +167,7 @@ void exclamation_box_act_4(void) {
|
|||
spawn_mist_particles_variable(0, 0, 46.0f);
|
||||
spawn_triangle_break_particles(20, 139, 0.3f, o->oAnimState);
|
||||
create_sound_spawner(SOUND_GENERAL_BREAK_BOX);
|
||||
if (o->oBehParams2ndByte < 3) {
|
||||
if (o->oBehParams2ndByte <= 3) {
|
||||
o->oAction = 5;
|
||||
cur_obj_hide();
|
||||
} else {
|
||||
|
|
|
@ -535,5 +535,10 @@ void render_hud(void) {
|
|||
{
|
||||
print_text(10, 60, "SURFACE NODE POOL FULL");
|
||||
}
|
||||
|
||||
#if defined(LUA_PROFILER)
|
||||
extern void lua_profiler_update_counters();
|
||||
lua_profiler_update_counters();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1103,6 +1103,27 @@ s32 act_warp_door_spawn(struct MarioState *m) {
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static s32 launch_mario_until_land_no_collision(struct MarioState *m, s32 endAction, s32 animation, f32 forwardVel) {
|
||||
mario_set_forward_vel(m, forwardVel);
|
||||
set_mario_animation(m, animation);
|
||||
m->pos[0] += m->vel[0];
|
||||
m->pos[1] += m->vel[1];
|
||||
m->pos[2] += m->vel[2];
|
||||
m->vel[1] -= 4.f;
|
||||
if (m->vel[1] < -75.f) {
|
||||
m->vel[1] = -75.f;
|
||||
}
|
||||
f32 floorHeight = find_floor_height(m->pos[0], m->pos[1], m->pos[2]);
|
||||
s32 landed = floorHeight >= m->pos[1];
|
||||
if (landed) {
|
||||
m->pos[1] = floorHeight;
|
||||
set_mario_action(m, endAction, 0);
|
||||
}
|
||||
vec3f_copy(m->marioObj->header.gfx.pos, m->pos);
|
||||
vec3s_set(m->marioObj->header.gfx.angle, 0, m->faceAngle[1], 0);
|
||||
return landed;
|
||||
}
|
||||
|
||||
s32 act_emerge_from_pipe(struct MarioState *m) {
|
||||
struct Object *marioObj = m->marioObj;
|
||||
|
||||
|
@ -1123,6 +1144,16 @@ s32 act_emerge_from_pipe(struct MarioState *m) {
|
|||
}
|
||||
}
|
||||
|
||||
// After Mario has exited the pipe, disable wall and ceiling collision until Mario lands
|
||||
// Fix softlocks in narrow places
|
||||
if (m->actionTimer > 15) {
|
||||
if (launch_mario_until_land_no_collision(m, ACT_JUMP_LAND_STOP, MARIO_ANIM_SINGLE_JUMP, 8.0f)) {
|
||||
mario_set_forward_vel(m, 0.0f);
|
||||
play_mario_landing_sound(m, SOUND_ACTION_TERRAIN_LANDING);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (launch_mario_until_land(m, ACT_JUMP_LAND_STOP, MARIO_ANIM_SINGLE_JUMP, 8.0f)) {
|
||||
mario_set_forward_vel(m, 0.0f);
|
||||
play_mario_landing_sound(m, SOUND_ACTION_TERRAIN_LANDING);
|
||||
|
@ -2894,7 +2925,7 @@ static s32 check_for_instant_quicksand(struct MarioState *m) {
|
|||
if (m->action == ACT_BUBBLED) { return FALSE; }
|
||||
|
||||
if (m->floor->type == SURFACE_INSTANT_QUICKSAND && m->action & ACT_FLAG_INVULNERABLE
|
||||
&& m->action != ACT_QUICKSAND_DEATH) {
|
||||
&& m->action != ACT_QUICKSAND_DEATH && m->action != ACT_SHOCKED) {
|
||||
update_mario_sound_and_camera(m);
|
||||
return drop_and_set_mario_action(m, ACT_QUICKSAND_DEATH, 0);
|
||||
}
|
||||
|
|
|
@ -14928,6 +14928,19 @@ int smlua_func_get_trajectory(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_obj_check_hitbox_overlap(lua_State* L) {
|
||||
if(!smlua_functions_valid_param_count(L, 2)) { return 0; }
|
||||
|
||||
struct Object* o1 = (struct Object*)smlua_to_cobject(L, 1, LOT_OBJECT);
|
||||
if (!gSmLuaConvertSuccess) { return 0; }
|
||||
struct Object* o2 = (struct Object*)smlua_to_cobject(L, 2, LOT_OBJECT);
|
||||
if (!gSmLuaConvertSuccess) { return 0; }
|
||||
|
||||
lua_pushinteger(L, obj_check_hitbox_overlap(o1, o2));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_obj_get_first(lua_State* L) {
|
||||
if(!smlua_functions_valid_param_count(L, 1)) { return 0; }
|
||||
|
||||
|
@ -15069,6 +15082,34 @@ int smlua_func_obj_has_model_extended(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_obj_is_valid_for_interaction(lua_State* L) {
|
||||
if(!smlua_functions_valid_param_count(L, 1)) { return 0; }
|
||||
|
||||
struct Object* o = (struct Object*)smlua_to_cobject(L, 1, LOT_OBJECT);
|
||||
if (!gSmLuaConvertSuccess) { return 0; }
|
||||
|
||||
lua_pushinteger(L, obj_is_valid_for_interaction(o));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_obj_move_xyz(lua_State* L) {
|
||||
if(!smlua_functions_valid_param_count(L, 4)) { return 0; }
|
||||
|
||||
struct Object* o = (struct Object*)smlua_to_cobject(L, 1, LOT_OBJECT);
|
||||
if (!gSmLuaConvertSuccess) { return 0; }
|
||||
f32 dx = smlua_to_number(L, 2);
|
||||
if (!gSmLuaConvertSuccess) { return 0; }
|
||||
f32 dy = smlua_to_number(L, 3);
|
||||
if (!gSmLuaConvertSuccess) { return 0; }
|
||||
f32 dz = smlua_to_number(L, 4);
|
||||
if (!gSmLuaConvertSuccess) { return 0; }
|
||||
|
||||
obj_move_xyz(o, dx, dy, dz);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_obj_set_model_extended(lua_State* L) {
|
||||
if(!smlua_functions_valid_param_count(L, 2)) { return 0; }
|
||||
|
||||
|
@ -15082,6 +15123,23 @@ int smlua_func_obj_set_model_extended(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_obj_set_vel(lua_State* L) {
|
||||
if(!smlua_functions_valid_param_count(L, 4)) { return 0; }
|
||||
|
||||
struct Object* o = (struct Object*)smlua_to_cobject(L, 1, LOT_OBJECT);
|
||||
if (!gSmLuaConvertSuccess) { return 0; }
|
||||
f32 vx = smlua_to_number(L, 2);
|
||||
if (!gSmLuaConvertSuccess) { return 0; }
|
||||
f32 vy = smlua_to_number(L, 3);
|
||||
if (!gSmLuaConvertSuccess) { return 0; }
|
||||
f32 vz = smlua_to_number(L, 4);
|
||||
if (!gSmLuaConvertSuccess) { return 0; }
|
||||
|
||||
obj_set_vel(o, vx, vy, vz);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_spawn_non_sync_object(lua_State* L) {
|
||||
if(!smlua_functions_valid_param_count(L, 6)) { return 0; }
|
||||
|
||||
|
@ -17002,6 +17060,7 @@ void smlua_bind_functions_autogen(void) {
|
|||
// smlua_obj_utils.h
|
||||
smlua_bind_function(L, "get_temp_object_hitbox", smlua_func_get_temp_object_hitbox);
|
||||
smlua_bind_function(L, "get_trajectory", smlua_func_get_trajectory);
|
||||
smlua_bind_function(L, "obj_check_hitbox_overlap", smlua_func_obj_check_hitbox_overlap);
|
||||
smlua_bind_function(L, "obj_get_first", smlua_func_obj_get_first);
|
||||
smlua_bind_function(L, "obj_get_first_with_behavior_id", smlua_func_obj_get_first_with_behavior_id);
|
||||
smlua_bind_function(L, "obj_get_first_with_behavior_id_and_field_f32", smlua_func_obj_get_first_with_behavior_id_and_field_f32);
|
||||
|
@ -17013,7 +17072,10 @@ void smlua_bind_functions_autogen(void) {
|
|||
smlua_bind_function(L, "obj_get_temp_spawn_particles_info", smlua_func_obj_get_temp_spawn_particles_info);
|
||||
smlua_bind_function(L, "obj_has_behavior_id", smlua_func_obj_has_behavior_id);
|
||||
smlua_bind_function(L, "obj_has_model_extended", smlua_func_obj_has_model_extended);
|
||||
smlua_bind_function(L, "obj_is_valid_for_interaction", smlua_func_obj_is_valid_for_interaction);
|
||||
smlua_bind_function(L, "obj_move_xyz", smlua_func_obj_move_xyz);
|
||||
smlua_bind_function(L, "obj_set_model_extended", smlua_func_obj_set_model_extended);
|
||||
smlua_bind_function(L, "obj_set_vel", smlua_func_obj_set_vel);
|
||||
smlua_bind_function(L, "spawn_non_sync_object", smlua_func_spawn_non_sync_object);
|
||||
smlua_bind_function(L, "spawn_sync_object", smlua_func_spawn_sync_object);
|
||||
|
||||
|
|
|
@ -3,6 +3,76 @@
|
|||
#include "pc/djui/djui_chat_message.h"
|
||||
#include "pc/crash_handler.h"
|
||||
|
||||
#if defined(LUA_PROFILER)
|
||||
#include "../mods/mods.h"
|
||||
#include "game/print.h"
|
||||
#include "gfx_dimensions.h"
|
||||
|
||||
extern u64 SDL_GetPerformanceCounter(void);
|
||||
extern u64 SDL_GetPerformanceFrequency(void);
|
||||
|
||||
#define MAX_PROFILED_MODS 16
|
||||
#define REFRESH_RATE 15
|
||||
|
||||
static struct {
|
||||
f64 start;
|
||||
f64 end;
|
||||
f64 sum;
|
||||
f64 disp;
|
||||
} sLuaProfilerCounters[MAX_PROFILED_MODS];
|
||||
|
||||
static void lua_profiler_start_counter(struct Mod *mod) {
|
||||
for (s32 i = 0; i != MIN(MAX_PROFILED_MODS, gActiveMods.entryCount); ++i) {
|
||||
if (gActiveMods.entries[i] == mod) {
|
||||
f64 freq = SDL_GetPerformanceFrequency();
|
||||
f64 curr = SDL_GetPerformanceCounter();
|
||||
sLuaProfilerCounters[i].start = curr / freq;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void lua_profiler_stop_counter(struct Mod *mod) {
|
||||
for (s32 i = 0; i != MIN(MAX_PROFILED_MODS, gActiveMods.entryCount); ++i) {
|
||||
if (gActiveMods.entries[i] == mod) {
|
||||
f64 freq = SDL_GetPerformanceFrequency();
|
||||
f64 curr = SDL_GetPerformanceCounter();
|
||||
sLuaProfilerCounters[i].end = curr / freq;
|
||||
sLuaProfilerCounters[i].sum += sLuaProfilerCounters[i].end - sLuaProfilerCounters[i].start;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lua_profiler_update_counters() {
|
||||
if (gGlobalTimer % REFRESH_RATE == 0) {
|
||||
for (s32 i = 0; i != MIN(MAX_PROFILED_MODS, gActiveMods.entryCount); ++i) {
|
||||
sLuaProfilerCounters[i].disp = sLuaProfilerCounters[i].sum / (f64) REFRESH_RATE;
|
||||
sLuaProfilerCounters[i].sum = 0;
|
||||
}
|
||||
}
|
||||
for (s32 i = 0, y = SCREEN_HEIGHT - 60; i != MIN(MAX_PROFILED_MODS, gActiveMods.entryCount); ++i, y -= 18) {
|
||||
const char *modName = gActiveMods.entries[i]->relativePath;
|
||||
s32 modCounterUs = (s32) (sLuaProfilerCounters[i].disp * 1000000.0);
|
||||
char text[256];
|
||||
snprintf(text, 256, " %05d", modCounterUs);
|
||||
memcpy(text, modName, MIN(12, strlen(modName) - (gActiveMods.entries[i]->isDirectory ? 0 : 4)));
|
||||
for (s32 j = 0; j != 12; ++j) {
|
||||
char c = text[j];
|
||||
if (c >= 'a' && c <= 'z') c -= ('a' - 'A');
|
||||
if (c == 'J') c = 'I';
|
||||
if (c == 'Q') c = 'O';
|
||||
if (c == 'V') c = 'U';
|
||||
if (c == 'X') c = '*';
|
||||
if (c == 'Z') c = '2';
|
||||
if ((c < '0' || c > '9') && (c < 'A' || c > 'Z')) c = ' ';
|
||||
text[j] = c;
|
||||
}
|
||||
print_text(GFX_DIMENSIONS_FROM_LEFT_EDGE(4), y, text);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#define MAX_HOOKED_REFERENCES 64
|
||||
#define LUA_BEHAVIOR_FLAG (1 << 15)
|
||||
|
||||
|
@ -20,7 +90,13 @@ static int smlua_call_hook(lua_State* L, int nargs, int nresults, int errfunc, s
|
|||
struct Mod* prev = gLuaActiveMod;
|
||||
gLuaActiveMod = activeMod;
|
||||
gLuaLastHookMod = activeMod;
|
||||
#if defined(LUA_PROFILER)
|
||||
lua_profiler_start_counter(activeMod);
|
||||
#endif
|
||||
int rc = lua_pcall(L, nargs, nresults, errfunc);
|
||||
#if defined(LUA_PROFILER)
|
||||
lua_profiler_stop_counter(activeMod);
|
||||
#endif
|
||||
gLuaActiveMod = prev;
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#include "object_constants.h"
|
||||
#include "object_fields.h"
|
||||
#include "src/game/object_helpers.h"
|
||||
#include "src/game/interaction.h"
|
||||
#include "engine/math_util.h"
|
||||
|
||||
#include "pc/lua/smlua.h"
|
||||
#include "smlua_obj_utils.h"
|
||||
|
@ -219,3 +221,32 @@ struct ObjectHitbox* get_temp_object_hitbox(void) {
|
|||
memset(&sTmpHitbox, 0, sizeof(struct ObjectHitbox));
|
||||
return &sTmpHitbox;
|
||||
}
|
||||
|
||||
s32 obj_is_valid_for_interaction(struct Object *o) {
|
||||
return o->activeFlags != ACTIVE_FLAG_DEACTIVATED && o->oIntangibleTimer == 0 && (o->oInteractStatus & INT_STATUS_INTERACTED) == 0;
|
||||
}
|
||||
|
||||
s32 obj_check_hitbox_overlap(struct Object *o1, struct Object *o2) {
|
||||
f32 r2 = sqr(max(o1->hitboxRadius, o1->hurtboxRadius) + max(o2->hitboxRadius, o2->hurtboxRadius));
|
||||
f32 d2 = sqr(o1->oPosX - o2->oPosX) + sqr(o1->oPosZ - o2->oPosZ);
|
||||
if (d2 > r2) return FALSE;
|
||||
f32 hb1lb = o1->oPosY - o1->hitboxDownOffset;
|
||||
f32 hb1ub = hb1lb + max(o1->hitboxHeight, o1->hurtboxHeight);
|
||||
f32 hb2lb = o2->oPosY - o2->hitboxDownOffset;
|
||||
f32 hb2ub = hb2lb + max(o2->hitboxHeight, o2->hurtboxHeight);
|
||||
f32 hbsoh = max(o1->hitboxHeight, o1->hurtboxHeight) + max(o2->hitboxHeight, o2->hurtboxHeight);
|
||||
if (hb2ub - hb1lb > hbsoh || hb1ub - hb2lb > hbsoh) return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void obj_set_vel(struct Object *o, f32 vx, f32 vy, f32 vz) {
|
||||
o->oVelX = vx;
|
||||
o->oVelY = vy;
|
||||
o->oVelZ = vz;
|
||||
}
|
||||
|
||||
void obj_move_xyz(struct Object *o, f32 dx, f32 dy, f32 dz) {
|
||||
o->oPosX += dx;
|
||||
o->oPosY += dy;
|
||||
o->oPosZ += dz;
|
||||
}
|
||||
|
|
|
@ -33,4 +33,9 @@ struct Object *obj_get_next_with_same_behavior_id_and_field_f32(struct Object *o
|
|||
struct SpawnParticlesInfo* obj_get_temp_spawn_particles_info(enum ModelExtendedId modelId);
|
||||
struct ObjectHitbox* get_temp_object_hitbox(void);
|
||||
|
||||
s32 obj_is_valid_for_interaction(struct Object *o);
|
||||
s32 obj_check_hitbox_overlap(struct Object *o1, struct Object *o2);
|
||||
void obj_set_vel(struct Object *o, f32 vx, f32 vy, f32 vz);
|
||||
void obj_move_xyz(struct Object *o, f32 dx, f32 dy, f32 dz);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue