-- name: Gun Mod DX -- incompatible: weapon -- description: Gun Mod DX v3.0.2\nBy \\#ec7731\\Agent X\\#dcdcdc\\\nSpecial thanks to \\#f296af\\PeachyPeach\\#dcdcdc\\\n\nThis is a rewritten & overhauled version of my original Gun Mod for sm64ex-coop. I thought this would make a good mod to bundle with sm64coopdx. If you have two pistols, you are able to dual wield them as well!\n\nPress [\\#3040ff\\Y\\#dcdcdc\\] to shoot\nPress [\\#3040ff\\X\\#dcdcdc\\] to reload\nRun \\#00ffff\\/gm help\\#dcdcdc\\ for help -- deluxe: true if SM64COOPDX_VERSION == nil then return end gGlobalSyncTable.gunModEnabled = true local renderHud = true gShootableHitboxes = { [id_bhvMario] = hurt_player, [id_bhvStar] = hurt_star, [id_bhvMessagePanel] = hurt_sign, [id_bhvToadMessage] = hurt_toad, [id_bhvExclamationBox] = hurt_exclamation_box, [id_bhvBreakableBox] = hurt_breakable_box, [id_bhvBreakableBoxSmall] = hurt_breakable_box_small, [id_bhvBowlingBall] = hurt_bowling_ball, [id_bhvWaterBomb] = hurt_water_bomb, [id_bhvTree] = hurt_tree, [id_bhvChainChomp] = hurt_chain_chomp, [id_bhvGoomba] = hurt_goomba, [id_bhvBobomb] = hurt_bobomb, [id_bhvHomingAmp] = hurt_amp, [id_bhvCirclingAmp] = hurt_amp, [id_bhvKoopa] = hurt_koopa, [id_bhvFlyGuy] = hurt_snufit, [id_bhvChuckya] = hurt_chuckya, [id_bhvPiranhaPlant] = hurt_piranha_plant, [id_bhvSnufit] = hurt_snufit, [id_bhvSwoop] = hurt_snufit, [id_bhvSpindrift] = hurt_spindrift, [id_bhvMrBlizzard] = hurt_mr_blizzard, [id_bhvMrI] = hurt_mr_i, [id_bhvScuttlebug] = hurt_scuttlebug, [id_bhvPokeyBodyPart] = hurt_pokey, [id_bhvSkeeter] = hurt_scuttlebug, [id_bhvSmallBully] = hurt_bully, [id_bhvBigBully] = hurt_bully, [id_bhvSmallChillBully] = hurt_bully, [id_bhvBigChillBully] = hurt_bully, [id_bhvMoneybag] = hurt_moneybag, [id_bhvKingBobomb] = hurt_king_bobomb, [id_bhvBowser] = hurt_bowser, [id_bhvYoshi] = hurt_yoshi } --- @param enable boolean --- @return nil --- Globally enables or disables Gun Mod local function enable_gun_mod(enable) if not network_is_server() and not network_is_moderator() then return end if type(enable) ~= "boolean" then return end gGlobalSyncTable.gunModEnabled = enable djui_popup_create("Gun Mod has been " .. if_then_else(gGlobalSyncTable.gunModEnabled, "enabled.", "disabled."), 2) end --- @param weapon WeaponId --- Returns a weapon by its ID local function get_weapon(weapon) return gWeaponTable[weapon] end --- @return nil --- Returns whether or not the Gun Mod HUD will render local function get_render_hud() return renderHud end --- @param enable boolean --- @return nil --- Sets whether or not the Gun Mod HUD will render local function set_render_hud(enable) if type(enable) ~= "boolean" then return end renderHud = enable end --- @param behavior BehaviorId --- @param hurtFunc fun(obj:Object, bulletObj:Object) --- @return nil local function shootable_register(behavior, hurtFunc) if type(behavior) ~= "number" or type(hurtFunc) ~= "function" then return end gShootableHitboxes[behavior] = hurtFunc end --- @param m MarioState local function mario_update(m) if active_player(m) == 0 then return end if gGlobalSyncTable.gunModEnabled and gPlayerSyncTable[m.playerIndex].curWeapon ~= nil then local spawned = false local held = obj_get_first_with_behavior_id(id_bhvHeldWeapon) while held ~= nil do if obj_get_weapon_owner(held) == gNetworkPlayers[m.playerIndex].globalIndex then spawned = true break end held = obj_get_next_with_same_behavior_id(held) end if not spawned then spawn_non_sync_object( id_bhvHeldWeapon, gWeaponTable[gPlayerSyncTable[m.playerIndex].curWeapon].model, 0, 0, 0, --- @param o Object function(o) obj_set_weapon_params(o, gNetworkPlayers[m.playerIndex].globalIndex, gPlayerSyncTable[m.playerIndex].curWeapon, 0, 0) end ) if gPlayerSyncTable[m.playerIndex].curWeapon2 ~= nil then spawn_non_sync_object( id_bhvHeldWeapon, gWeaponTable[gPlayerSyncTable[m.playerIndex].curWeapon2].model, 0, 0, 0, --- @param o Object function(o) obj_set_weapon_params(o, gNetworkPlayers[m.playerIndex].globalIndex, gPlayerSyncTable[m.playerIndex].curWeapon2, 1, 0) end ) end end end if m.playerIndex ~= 0 then return end if vec3f_dist(m.pos, m.area.camera.pos) < 500 and (m.action & ACT_GROUP_MASK) ~= ACT_GROUP_CUTSCENE then m.marioBodyState.modelState = m.marioBodyState.modelState | MODEL_STATE_NOISE_ALPHA end if get_first_person_enabled() then if gGlobalSyncTable.gunModEnabled and obj_get_first_with_behavior_id(id_bhvViewmodel) == nil and cur_weapon() ~= nil then spawn_viewmodels() end if (m.action & ACT_FLAG_IDLE) ~= 0 then m.faceAngle.y = gLakituState.yaw + 0x8000 end -- movement -- if m.action ~= ACT_CUSTOM_MOVEMENT then -- set_mario_action(m, ACT_CUSTOM_MOVEMENT, 0) -- vec3f_copy(gPlayerFirstPerson.movement.pos, m.pos) -- end elseif not camera_config_is_mouse_look_enabled() then djui_hud_set_mouse_locked(false) end -- disable negative vertical speed conservation so guns don't appear lower than normal local group = (m.action & ACT_GROUP_MASK) if (group == ACT_GROUP_MOVING or group == ACT_GROUP_STATIONARY or group == ACT_GROUP_OBJECT) and (m.action & ACT_FLAG_AIR) == 0 and m.vel.y < 0 then m.vel.y = 0 end if gGlobalSyncTable.gunModEnabled then weapon_update() end end local function on_level_init() local obj = obj_get_first(OBJ_LIST_SURFACE) while obj ~= nil do obj.header.gfx.skipInViewCheck = true obj = obj_get_next(obj) end spawn_dialog_arrow() if not mod_storage_load_bool("init") then mod_storage_save_bool("init", true) audio_sample_play(SOUND_CUSTOM_BAD_TO_THE_BONE, gMarioStates[0].pos, 1) end end local function on_hud_render_behind() local weapon = cur_weapon() if weapon == nil or not renderHud or not gGlobalSyncTable.gunModEnabled or gNetworkPlayers[0].currActNum == 99 or obj_get_first_with_behavior_id(id_bhvActSelector) ~= nil then return end djui_hud_set_resolution(RESOLUTION_N64) djui_hud_set_font(FONT_HUD) local width = djui_hud_get_screen_width() local height = djui_hud_get_screen_height() if get_first_person_enabled() and weapon ~= nil and not is_game_paused() then djui_hud_set_color(255, 255, 0, 127) djui_hud_render_texture(TEX_CROSSHAIR, width * 0.5 - 4, height * 0.5 - 4, 0.5, 0.5) end local y = height - 35 djui_hud_set_color(255, 255, 255, 255) if weapon.maxAmmo ~= 0 then djui_hud_print_text(weapon.ammo .. "/" .. weapon.maxAmmo, width - 128, y, 1) end local weapon2 = cur_dual_wield_weapon() if weapon2 ~= nil and weapon2.maxAmmo ~= 0 then djui_hud_print_text(weapon2.ammo .. "/" .. weapon2.maxAmmo, 16, y, 1) end end function on_packet_receive(dataTable) if dataTable.packet == PACKET_ATTACK then if gNetworkPlayers[0].currLevelNum == dataTable.level and gNetworkPlayers[0].currAreaIndex == dataTable.area and gNetworkPlayers[0].currActNum == dataTable.act then audio_sample_play(SOUND_CUSTOM_IMPACT, gMarioStates[0].pos, 1) end if dataTable.yoshi then local pos = gMarioStates[network_local_index_from_global(dataTable.globalIndex)].pos spawn_non_sync_object( id_bhvExplosion, E_MODEL_TROLL_EXPLOSION, pos.x, pos.y + 80, pos.z, nil ) end if gNetworkPlayers[0].globalIndex ~= dataTable.globalIndex then return end if dataTable.yoshi then set_health(0) else set_health(get_health() - gWeaponTable[dataTable.weaponId].damage) end elseif dataTable.packet == PACKET_SOUND then if gNetworkPlayers[0].currLevelNum == dataTable.level and gNetworkPlayers[0].currAreaIndex == dataTable.area and gNetworkPlayers[0].currActNum == dataTable.act then -- audio_sample_stop(gSoundTable[dataTable.sound]) audio_sample_play(gSoundTable[dataTable.sound], { x = dataTable.x, y = dataTable.y, z = dataTable.z }, dataTable.volume) end end end -------------- -- commands -- -------------- local function on_fp_command() set_first_person_enabled(not gFirstPersonCamera.enabled) djui_chat_message_create("[Gun Mod] First person mode status: " .. on_or_off(gFirstPersonCamera.enabled)) return true end local function on_fov_command(msg) local fov = tonumber(msg) if fov ~= nil then if fov <= 0 then fov = FIRST_PERSON_DEFAULT_FOV end mod_storage_save_number("fov", fov) gFirstPersonCamera.fov = fov djui_chat_message_create("[Gun Mod] Set FOV to " .. fov) return true end djui_chat_message_create("/gm \\#00ffff\\fov\\#ffff00\\ [number]\\#ffffff\\\nSets the first person camera FOV, default is \\#ffff00\\70\\#ffffff\\") return true end local function on_give_command(msg) -- if not network_is_server() and not network_is_moderator() then -- djui_chat_message_create("\\#ffa0a0\\You do not have permission to run this command.") -- return true -- end if not gGlobalSyncTable.gunModEnabled then djui_chat_message_create("\\#ffa0a0\\[Gun Mod] You need to enable Gun Mod to give yourself a weapon.") return true end for id, weapon in pairs(gWeaponTable) do if weapon.name:lower() == msg:lower() then pickup_weapon(id) local text = string.format("[Gun Mod] Gave %s %s", name_without_hex(gNetworkPlayers[0].name), weapon.name) djui_chat_message_create(text) return true end end djui_chat_message_create("/gm \\#00ffff\\give\\#ffff00\\ " .. get_weapon_list_string() .. "\\#ffffff\\\nGives yourself a gun") return true end local function on_gm_command(msg) local args = split(msg) if args[1] == "fp" then return on_fp_command() elseif args[1] == "fov" then return on_fov_command(args[2] or "") elseif args[1] == "give" then return on_give_command(args[2] or "") end if msg:gsub("%s+", "") == "" and (network_is_server() or network_is_moderator()) then gGlobalSyncTable.gunModEnabled = not gGlobalSyncTable.gunModEnabled djui_chat_message_create("[Gun Mod] Status: " .. on_or_off(gGlobalSyncTable.gunModEnabled)) else djui_chat_message_create("/gm \\#00ffff\\[fp|fov|give]\\#7f7f7f\\ (leave blank to toggle Gun Mod on or off)") end return true end smlua_text_utils_dialog_replace(DIALOG_167, 1, 4, 30, 200, "Welcome to Gun Mod. After\ 4 months in development,\ hopefully it will have\ been worth the wait.\ This mod has actually been\ in development for 16\ months, but progress was\ pretty slow until recently.\ I decided to rewrite the\ rewrite to make this\ mod's code less of a\ total mess.\ -- TUTORIAL --\ Press X to shoot\ Press Y to reload\ Run slash gm help\ Princess Toadstool's\ castle is just ahead.\ \ \ Press [A] to jump, [Z] to\ crouch, and [B] to punch,\ read a sign, or grab\ something.\ Press [B] again to throw\ something you're holding.") gServerSettings.playerInteractions = PLAYER_INTERACTIONS_PVP _G.gunModApi = { enable_gun_mod = enable_gun_mod, get_render_hud = get_render_hud, set_render_hud = set_render_hud, get_weapon = get_weapon, weapon_register = weapon_register, weapon_unregister = weapon_unregister, weapon_unregister_all = weapon_unregister_all, get_weapon_list_string = get_weapon_list_string, obj_set_weapon_params = obj_set_weapon_params, obj_get_weapon_owner = obj_get_weapon_owner, obj_get_weapon_id = obj_get_weapon_id, obj_get_weapon_dual_wield = obj_get_weapon_dual_wield, obj_get_weapon_extra = obj_get_weapon_extra, cur_weapon = cur_weapon, cur_dual_wield_weapon = cur_dual_wield_weapon, get_inventory_slot = get_inventory_slot, set_inventory_slot = set_inventory_slot, pickup_weapon = pickup_weapon, get_health = get_health, set_health = set_health, common_shoot = common_shoot, common_reload = common_reload, bullet_ricochet = bullet_ricochet, obj_generate_hitbox_multiply_func = obj_generate_hitbox_multiply_func, obj_generate_health_func = obj_generate_health_func, shootable_register = shootable_register } local fov = mod_storage_load_number("fov") if fov == 0 then fov = FIRST_PERSON_DEFAULT_FOV mod_storage_save_number("fov", fov) end gFirstPersonCamera.fov = fov if START_IN_FIRST_PERSON then set_first_person_enabled(true) end hook_event(HOOK_MARIO_UPDATE, mario_update) hook_event(HOOK_ON_LEVEL_INIT, on_level_init) hook_event(HOOK_ON_PACKET_RECEIVE, on_packet_receive) hook_event(HOOK_ON_HUD_RENDER_BEHIND, on_hud_render_behind) gm_hook_behavior(id_bhvMessagePanel, false, obj_sign_hitbox) gm_hook_behavior(id_bhvExclamationBox, false, nil, obj_generate_hitbox_multiply_func(1, 1.8)) gm_hook_behavior(id_bhvBreakableBox, false, obj_generate_health_func(HEALTH_BREAKABLE_BOX)) gm_hook_behavior(id_bhvBowlingBall, false, obj_generate_health_func(HEALTH_BOWLING_BALL)) gm_hook_behavior(id_bhvWaterBomb, false, nil, obj_generate_hitbox_multiply_func(1, 2)) gm_hook_behavior(id_bhvChainChomp, false, nil, obj_generate_hitbox_multiply_func(1.5, 1.5)) gm_hook_behavior(id_bhvHomingAmp, false, nil, obj_amp_hitbox) gm_hook_behavior(id_bhvCirclingAmp, false, nil, obj_amp_hitbox) gm_hook_behavior(id_bhvFlyGuy, false, nil, obj_generate_hitbox_multiply_func(0.75, 1.75)) gm_hook_behavior(id_bhvChuckya, false, obj_chuckya_hitbox) gm_hook_behavior(id_bhvSnufit, false, nil, obj_snufit_hitbox) gm_hook_behavior(id_bhvSpindrift, false, nil, obj_generate_hitbox_multiply_func(0.75, 2)) gm_hook_behavior(id_bhvKingBobomb, false, obj_king_bobomb_hitbox) gm_hook_behavior(id_bhvBowser, false, obj_generate_health_func(HEALTH_BOWSER)) gm_hook_behavior(id_bhvStaticObject, false, obj_skip_in_view_check) hook_chat_command("gm", "\\#00ffff\\[fp|fov|give]\\#7f7f7f\\ (leave blank to toggle Gun Mod on or off)", on_gm_command) -- matches the function(s) below for i = 0, MAX_PLAYERS - 1 do gPlayerSyncTable[i].curWeapon = WEAPON_MAGNUM gPlayerSyncTable[i].curWeapon2 = WEAPON_PISTOL end pickup_weapon(WEAPON_MAGNUM) pickup_weapon(WEAPON_PISTOL)