if SM64COOPDX_VERSION == nil then return end gItemHeld = {} -- setup held items for i = 0, (MAX_PLAYERS - 1) do gItemHeld[i] = nil end ATTACH_NONE = 0 ATTACH_HAND = 1 ATTACH_HEAD = 2 ------------ ------------ define_custom_obj_fields({ oArenaItemHeldType = 'u32', oArenaItemHeldOwner = 'u32', }) function bhv_arena_item_held_init(obj) obj.oFlags = OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE obj.oOpacity = 255 obj.oArenaItemHeldType = ITEM_FIRE_FLOWER obj.hookRender = 1 obj_scale(obj, 1) cur_obj_hide() end function bhv_arena_item_held_loop(obj) local m = gMarioStates[obj.oArenaItemHeldOwner] local s = gPlayerSyncTable[obj.oArenaItemHeldOwner] local data = gItemHeldData[s.item] -- check if this should be inactive if s.item == ITEM_NONE or data == nil or not active_player(m) then cur_obj_hide() return end -- if the player is off screen, hide the obj if m.marioBodyState.updateTorsoTime ~= gMarioStates[0].marioBodyState.updateTorsoTime then cur_obj_hide() return end -- update pallet local np = gNetworkPlayers[obj.oArenaItemHeldOwner] if np ~= nil then obj.globalPlayerIndex = np.globalIndex end -- check if this should be activated if obj_is_hidden(obj) ~= 0 or obj.oArenaItemHeldType ~= s.item then cur_obj_unhide() obj_set_model_extended(obj, data.heldModel) obj_scale(obj, data.scale) obj.oAnimState = 0 if data.billboard then obj.header.gfx.node.flags = obj.header.gfx.node.flags | GRAPH_RENDER_BILLBOARD else obj.header.gfx.node.flags = obj.header.gfx.node.flags & ~GRAPH_RENDER_BILLBOARD end if data.animations ~= nil then obj.oAnimations = data.animations cur_obj_init_animation(data.animationIndex) else obj.oAnimations = nil end end -- update things obj.oArenaItemHeldType = s.item if data.updateAnimState then obj.oAnimState = obj.oAnimState + 1 end end id_bhvArenaItemHeld = hook_behavior(nil, OBJ_LIST_DEFAULT, true, bhv_arena_item_held_init, bhv_arena_item_held_loop) ------------ function on_level_init() -- initialize all held items for i = 0, (MAX_PLAYERS - 1) do gItemHeld[i] = spawn_non_sync_object(id_bhvArenaItemHeld, E_MODEL_NONE, 0, 0, 0, function(obj) obj.oArenaItemHeldType = ITEM_NONE obj.oArenaItemHeldOwner = i end) end end function dot_along_angle(obj, m, angle) local v1 = { x = obj.oPosX - m.pos.x, y = obj.oPosY - m.pos.y, z = obj.oPosZ - m.pos.z, } vec3f_normalize(v1) local v2 = { x = sins(m.faceAngle.y + angle), y = 0, z = coss(m.faceAngle.y + angle), } return vec3f_dot(v1, v2) end function bhv_arena_item_held_hammer_render(obj) local m = gMarioStates[obj.oArenaItemHeldOwner] local e = gMarioStateExtras[obj.oArenaItemHeldOwner] local animFrame = m.marioObj.header.gfx.animInfo.animFrame if m.action == ACT_DIVE then obj.oFaceAnglePitch = e.rotAngle obj.oFaceAngleRoll = 0 elseif m.action == ACT_DIVE_SLIDE then obj.oFaceAnglePitch = 0x4000 obj.oFaceAngleRoll = 0 elseif m.action == ACT_STOMACH_SLIDE_STOP then local loopEnd = m.marioObj.header.gfx.animInfo.curAnim.loopEnd local scalar = 1 if loopEnd == 38 then scalar = (1 - (animFrame / loopEnd) ^ 2) end obj.oFaceAnglePitch = 0x4000 * scalar obj.oFaceAngleRoll = 0 elseif m.action == ACT_PUNCHING or m.action == ACT_MOVE_PUNCHING then local scalar = dot_along_angle(obj, m, 0) * 1.5 if scalar > 0.723 then scalar = 0.723 end obj.oFaceAnglePitch = 0x5000 * scalar + 0x500 obj.oFaceAngleRoll = 0x1000 * dot_along_angle(obj, m, -0x4000) elseif m.action == ACT_GROUND_POUND then local loopEnd = m.marioObj.header.gfx.animInfo.curAnim.loopEnd if m.actionState == 0 then obj.oFaceAnglePitch = 0x16000 * animFrame / loopEnd else obj.oFaceAnglePitch = 0x4000 end obj.oFaceAngleRoll = 0 elseif m.action == ACT_GROUND_POUND_LAND then local loopEnd = m.marioObj.header.gfx.animInfo.curAnim.loopEnd local scalar = 1 if loopEnd == 6 then scalar = (1 - (animFrame / loopEnd) ^ 2) end obj.oFaceAnglePitch = 0x4000 * scalar obj.oFaceAngleRoll = 0 elseif m.action == ACT_JUMP_KICK then local loopEnd = m.marioObj.header.gfx.animInfo.curAnim.loopEnd local scalar = (animFrame / loopEnd) * 9 if scalar > 4 then scalar = 4 end obj.oFaceAnglePitch = -0x8000 * scalar obj.oFaceAngleRoll = 0 elseif m.action == ACT_BACKFLIP then local loopEnd = m.marioObj.header.gfx.animInfo.curAnim.loopEnd local scalar = (animFrame / loopEnd) * 4 if scalar > 4 then scalar = 4 end obj.oFaceAnglePitch = -0x8000 * scalar obj.oFaceAngleRoll = 0x1000 * dot_along_angle(obj, m, -0x4000) elseif m.action == ACT_TRIPLE_JUMP then local loopEnd = m.marioObj.header.gfx.animInfo.curAnim.loopEnd local scalar = (animFrame / loopEnd) * 4 if scalar > 4 then scalar = 4 end obj.oFaceAnglePitch = 0x8000 * scalar obj.oFaceAngleRoll = 0x1000 * dot_along_angle(obj, m, -0x4000) elseif m.action == ACT_SIDE_FLIP then local loopEnd = m.marioObj.header.gfx.animInfo.curAnim.loopEnd local scalar = (animFrame / loopEnd) * 2 if scalar > 4 then scalar = 4 end obj.oFaceAnglePitch = 0x8000 * scalar obj.oFaceAngleRoll = 0x1000 * dot_along_angle(obj, m, -0x4000) else obj.oFaceAnglePitch = 0x2500 * dot_along_angle(obj, m, 0) + 0x500 obj.oFaceAngleRoll = 0x1000 * dot_along_angle(obj, m, -0x4000) end end function on_object_render(obj) if get_id_from_behavior(obj.behavior) ~= id_bhvArenaItemHeld then return end local m = gMarioStates[obj.oArenaItemHeldOwner] local data = gItemHeldData[obj.oArenaItemHeldType] if data == nil or not active_player(m) then return end obj.oFaceAngleYaw = m.faceAngle.y + data.yawOffset obj.oFaceAnglePitch = data.pitchOffset obj.oFaceAngleRoll = 0 if data.attachment == ATTACH_HAND then obj.oPosX = get_hand_foot_pos_x(m, 0) obj.oPosY = get_hand_foot_pos_y(m, 0) + data.yOffset obj.oPosZ = get_hand_foot_pos_z(m, 0) elseif data.attachment == ATTACH_HEAD then obj.oPosX = m.marioBodyState.headPos.x obj.oPosY = m.marioBodyState.headPos.y + data.yOffset obj.oPosZ = m.marioBodyState.headPos.z end if data.renderAdjust ~= nil then data.renderAdjust(obj) end -- if the player is off screen, move the obj to the player origin if m.marioBodyState.updateTorsoTime ~= gMarioStates[0].marioBodyState.updateTorsoTime then obj.oPosX = m.pos.x obj.oPosY = m.pos.y obj.oPosZ = m.pos.z end if data.forwardOffset > 0 then obj.oPosX = obj.oPosX + sins(m.faceAngle.y) * data.forwardOffset obj.oPosZ = obj.oPosZ + coss(m.faceAngle.y) * data.forwardOffset end obj.header.gfx.pos.x = obj.oPosX obj.header.gfx.pos.y = obj.oPosY obj.header.gfx.pos.z = obj.oPosZ end hook_event(HOOK_ON_OBJECT_RENDER, on_object_render) hook_event(HOOK_ON_LEVEL_INIT, on_level_init) ---- gItemHeldData = { [ITEM_NONE] = { heldModel = E_MODEL_NONE, updateAnimState = false, billboard = false, scale = 1, attachment = ATTACH_NONE, yawOffset = 0, pitchOffset = 0, yOffset = 0, forwardOffset = 0, renderAdjust = nil, }, [ITEM_METAL_CAP] = { heldModel = E_MODEL_NONE, updateAnimState = false, billboard = false, scale = 1, attachment = ATTACH_NONE, yawOffset = 0, pitchOffset = 0, yOffset = 0, forwardOffset = 0, renderAdjust = nil, }, [ITEM_HAMMER] = { heldModel = E_MODEL_HAMMER, updateAnimState = false, billboard = false, scale = 1, attachment = ATTACH_HAND, yawOffset = 0, pitchOffset = 0x1000, yOffset = 0, forwardOffset = 10, renderAdjust = bhv_arena_item_held_hammer_render, }, [ITEM_FIRE_FLOWER] = { heldModel = E_MODEL_RED_FLAME, updateAnimState = true, billboard = true, scale = 2, attachment = ATTACH_HAND, yawOffset = 0, pitchOffset = 0, forwardOffset = 25, yOffset = 10, renderAdjust = nil, }, [ITEM_CANNON_BOX] = { heldModel = E_MODEL_CANNON_BOX, updateAnimState = false, billboard = false, scale = 0.65, attachment = ATTACH_HEAD, yawOffset = -0x4000, pitchOffset = 0, yOffset = 50, forwardOffset = 0, renderAdjust = nil, }, [ITEM_BOBOMB] = { heldModel = E_MODEL_BLACK_BOBOMB, updateAnimState = false, billboard = false, scale = 0.5, attachment = ATTACH_HAND, yawOffset = 0, pitchOffset = 0, yOffset = -25, forwardOffset = 25, animations = gObjectAnimations.bobomb_seg8_anims_0802396C, animationIndex = 1, renderAdjust = nil, }, [ITEM_COIN] = { heldModel = E_MODEL_NONE, updateAnimState = false, billboard = false, scale = 1, attachment = ATTACH_NONE, yawOffset = 0, pitchOffset = 0, yOffset = 0, forwardOffset = 0, renderAdjust = nil, }, }