2024-01-01 22:41:28 +01:00
-- 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
2023-12-18 23:01:33 +01:00
-- 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 ,
2023-12-24 22:05:21 +01:00
[ id_bhvMoneybag ] = hurt_moneybag ,
2023-12-18 23:01:33 +01:00
[ 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 \\ \n Sets 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 \\ \n Gives 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
2023-12-24 22:05:21 +01:00
if msg : gsub ( " %s+ " , " " ) == " " and ( network_is_server ( ) or network_is_moderator ( ) ) then
2023-12-18 23:01:33 +01:00
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 ,
2024-01-01 22:41:28 +01:00
shootable_register = shootable_register
2023-12-18 23:01:33 +01:00
}
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 )