228 lines
5.8 KiB
Lua
228 lines
5.8 KiB
Lua
if SM64COOPDX_VERSION == nil then return end
|
|
|
|
define_custom_obj_fields({
|
|
oGmHealth = "f32"
|
|
})
|
|
|
|
--- @return number
|
|
--- Gets the player's health in 0-100 format
|
|
function get_health()
|
|
return clampf((gMarioStates[0].health - 0xFF) / (0x880 - 0xFF), 0, 1) * 100
|
|
end
|
|
|
|
--- @return nil
|
|
--- Sets the player's health in 0-100 format
|
|
function set_health(health)
|
|
gMarioStates[0].health = (health * 19.21) + 0xFF
|
|
end
|
|
|
|
function packet_send(reliable, packet, dataTable)
|
|
dataTable.packet = packet
|
|
dataTable.level = gNetworkPlayers[0].currLevelNum
|
|
dataTable.area = gNetworkPlayers[0].currAreaIndex
|
|
dataTable.act = gNetworkPlayers[0].currActNum
|
|
network_send(reliable, dataTable)
|
|
on_packet_receive(dataTable)
|
|
end
|
|
|
|
------------------
|
|
-- synced audio --
|
|
------------------
|
|
|
|
gSoundTable = {}
|
|
local soundId = -1
|
|
|
|
function sync_audio_sample_load(filename)
|
|
local sound = audio_sample_load(filename)
|
|
if sound ~= nil then
|
|
soundId = soundId + 1
|
|
gSoundTable["snd" .. soundId] = sound
|
|
return "snd" .. soundId
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function sync_audio_sample_play(audio, position, volume)
|
|
local packet = {
|
|
sound = audio,
|
|
x = position.x,
|
|
y = position.y,
|
|
z = position.z,
|
|
volume = volume
|
|
}
|
|
packet_send(false, PACKET_SOUND, packet)
|
|
end
|
|
|
|
|
|
--------------------
|
|
-- misc functions --
|
|
--------------------
|
|
|
|
--- @param m MarioState
|
|
function active_player(m)
|
|
local np = gNetworkPlayers[m.playerIndex]
|
|
if m.playerIndex == 0 then
|
|
return 1
|
|
end
|
|
if not np.connected then
|
|
return 0
|
|
end
|
|
if np.currCourseNum ~= gNetworkPlayers[0].currCourseNum then
|
|
return 0
|
|
end
|
|
if np.currActNum ~= gNetworkPlayers[0].currActNum then
|
|
return 0
|
|
end
|
|
if np.currLevelNum ~= gNetworkPlayers[0].currLevelNum then
|
|
return 0
|
|
end
|
|
if np.currAreaIndex ~= gNetworkPlayers[0].currAreaIndex then
|
|
return 0
|
|
end
|
|
return is_player_active(m)
|
|
end
|
|
|
|
function if_then_else(cond, ifTrue, ifFalse)
|
|
if cond then return ifTrue end
|
|
return ifFalse
|
|
end
|
|
|
|
function handle_timer(timer)
|
|
if timer > 0 then
|
|
timer = timer - 1
|
|
end
|
|
return timer
|
|
end
|
|
|
|
function split(s)
|
|
local result = {}
|
|
for match in (s):gmatch(string.format("[^%s]+", " ")) do
|
|
table.insert(result, match)
|
|
end
|
|
return result
|
|
end
|
|
|
|
function on_or_off(value)
|
|
if value then return "\\#00ff00\\ON" end
|
|
return "\\#ff0000\\OFF"
|
|
end
|
|
|
|
function name_without_hex(name)
|
|
local s = ''
|
|
local inSlash = false
|
|
for i = 1, #name do
|
|
local c = name:sub(i,i)
|
|
if c == '\\' then
|
|
inSlash = not inSlash
|
|
elseif not inSlash then
|
|
s = s .. c
|
|
end
|
|
end
|
|
return s
|
|
end
|
|
|
|
function lerp(a,b,t) return a * (1-t) + b * t end
|
|
|
|
--- @param obj Object
|
|
function obj_set_animation(obj, name)
|
|
if obj == nil then return end
|
|
|
|
local animPointer = nil
|
|
if obj.header.gfx.animInfo.curAnim ~= nil then animPointer = obj.header.gfx.animInfo.curAnim._pointer end
|
|
smlua_anim_util_set_animation(obj, name)
|
|
if obj.header.gfx.animInfo.curAnim._pointer ~= animPointer then
|
|
obj.header.gfx.animInfo.animAccel = 0
|
|
obj.header.gfx.animInfo.animFrame = obj.header.gfx.animInfo.curAnim.startFrame
|
|
end
|
|
end
|
|
|
|
--- @param o1 Object
|
|
--- @param o2 Object
|
|
--- Basically `obj_check_hitbox_overlap()` except it uses 3 variables for object 1's X, Y and Z coordinates
|
|
function obj_check_hitbox_overlap_xyz(o1, o2, x2, y2, z2)
|
|
if o1 == nil or o2 == nil then return false end
|
|
|
|
local o1H = maxf(o1.hitboxHeight, o1.hurtboxHeight) -- object 1 hitbox height
|
|
local o1R = maxf(o1.hitboxRadius, o1.hurtboxRadius) -- object 1 hitbox radius
|
|
local o2H = maxf(o2.hitboxHeight, o2.hurtboxHeight) -- object 2 hitbox height
|
|
local o2R = maxf(o2.hitboxRadius, o2.hurtboxRadius) -- object 2 hitbox radius
|
|
|
|
-- calculate the distance between the cylinder centers in the xz-plane
|
|
local distanceXZ = math.sqrt(sqrf(x2 - o1.oPosX) + sqrf(z2 - o1.oPosZ))
|
|
|
|
-- check for collision in the xz-plane (ignoring height)
|
|
if distanceXZ <= o1R + o2R then
|
|
-- check for collision in the y-axis (height)
|
|
if math.abs(y2 - o1.oPosY) <= maxf(o1H, o2H) * 0.5 then
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
--- @param obj Object
|
|
function obj_skip_in_view_check(obj)
|
|
obj.header.gfx.skipInViewCheck = true
|
|
end
|
|
|
|
--- @param o Object
|
|
function obj_sign_hitbox(o)
|
|
o.hitboxRadius = o.hitboxRadius * 0.75
|
|
o.hitboxHeight = o.hitboxHeight * 1.5
|
|
o.oGmHealth = HEALTH_SIGN
|
|
end
|
|
|
|
--- @param o Object
|
|
function obj_amp_hitbox(o)
|
|
if o.oAction ~= AMP_ACT_ATTACK_COOLDOWN then
|
|
o.hitboxHeight = o.hitboxHeight * 2
|
|
end
|
|
end
|
|
|
|
--- @param o Object
|
|
function obj_chuckya_hitbox(o)
|
|
o.hitboxHeight = o.hitboxHeight * 2
|
|
o.oGmHealth = HEALTH_CHUCKYA
|
|
end
|
|
|
|
--- @param o Object
|
|
function obj_snufit_hitbox(o)
|
|
o.hitboxRadius = o.hitboxRadius * 0.6
|
|
o.hitboxHeight = o.hitboxHeight * 2
|
|
o.hitboxDownOffset = 60
|
|
end
|
|
|
|
--- @param o Object
|
|
function obj_king_bobomb_hitbox(o)
|
|
o.oGmHealth = HEALTH_KING_BOBOMB
|
|
o.hitboxHeight = o.hitboxHeight * 3
|
|
end
|
|
|
|
-- generic
|
|
function obj_generate_hitbox_multiply_func(radius, height)
|
|
--- @param o Object
|
|
local func = function(o)
|
|
o.hitboxRadius = o.hitboxRadius * radius
|
|
o.hitboxHeight = o.hitboxHeight * height
|
|
end
|
|
return func
|
|
end
|
|
|
|
-- generic
|
|
function obj_generate_health_func(health)
|
|
--- @param o Object
|
|
local func = function(o)
|
|
o.oGmHealth = health
|
|
end
|
|
return func
|
|
end
|
|
|
|
function gm_hook_behavior(id, override, init, loop)
|
|
hook_behavior(
|
|
id,
|
|
get_object_list_from_behavior(get_behavior_from_id(id)), -- automatically get the correct object list
|
|
override, init, loop,
|
|
"bhvGm" .. get_behavior_name_from_id(id):sub(4) -- give the behavior a consistent behavior name (for example, bhvGoomba will become bhvGmGoomba)
|
|
)
|
|
end |