Remove Gun Mod DX

It isn't a finished product, I ran out of time to complete it and removing it can also free up some space for something like a cheats or moveset mod to be in its place.
This commit is contained in:
Agent X 2024-05-26 15:21:29 -04:00
parent b7b044e0b2
commit d9e50581ff
28 changed files with 0 additions and 2137 deletions

View File

@ -1,49 +0,0 @@
if SM64COOPDX_VERSION == nil then
local first = false
hook_event(HOOK_ON_LEVEL_INIT, function()
if not first then
first = true
play_sound(SOUND_MENU_CAMERA_BUZZ, { x = 0, y = 0, z = 0 })
djui_chat_message_create("\\#ff7f7f\\Gun Mod is no longer supported with sm64ex-coop as it uses sm64coopdx exclusive Lua functionality.\n\\#dcdcdc\\To play this mod, try out sm64coopdx, at\n\\#7f7fff\\https://sm64coopdx.com")
end
end)
return
end
-- models
E_MODEL_BULLET_HOLE = smlua_model_util_get_id("bullet_hole_geo")
E_MODEL_SINGLE_ARM = smlua_model_util_get_id("arm_geo")
E_MODEL_PISTOL = smlua_model_util_get_id("pistol_geo")
E_MODEL_MAGNUM = smlua_model_util_get_id("magnum_geo")
E_MODEL_AK47 = smlua_model_util_get_id("ak47_geo")
E_MODEL_SHOTGUN = smlua_model_util_get_id("shotgun_geo")
E_MODEL_ARROW = smlua_model_util_get_id("arrow_geo")
E_MODEL_TROLL_EXPLOSION = smlua_model_util_get_id("troll_explosion_geo")
-- textures
TEX_CROSSHAIR = get_texture_info("gun_mod_crosshair")
-- custom sounds
SOUND_CUSTOM_IMPACT = audio_sample_load("impact.mp3")
SOUND_CUSTOM_RICOCHET = audio_sample_load("ricochet.mp3")
SOUND_CUSTOM_DRY = audio_sample_load("dry.mp3")
SOUND_CUSTOM_BAD_TO_THE_BONE = audio_sample_load("bad_to_the_bone_riff.mp3")
-- actions
-- ACT_CUSTOM_MOVEMENT = allocate_mario_action(ACT_GROUP_CUTSCENE)
-- packet ids
PACKET_ATTACK = 0
PACKET_SOUND = 1
-- misc
START_IN_FIRST_PERSON = true
MAX_INVENTORY_SLOTS = 2
HEALTH_SIGN = 30
HEALTH_BREAKABLE_BOX = 30
HEALTH_BOWLING_BALL = 75
HEALTH_CHUCKYA = 60
HEALTH_KING_BOBOMB = 200
HEALTH_BOWSER = 300

View File

@ -1,228 +0,0 @@
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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,498 +0,0 @@
----------------------
-- bullet functions --
----------------------
--- @param obj Object
--- @return nil
function bullet_ricochet(obj)
if obj == nil then return end
-- ricochet
obj.oAction = 1
if obj.oVelY == 0 then
obj.oForwardVel = -obj.oForwardVel
else
obj.oVelX = -obj.oVelX
obj.oVelY = -obj.oVelY
obj.oVelZ = -obj.oVelZ
end
obj.oPosX = obj.header.gfx.prevPos.x
obj.oPosY = obj.header.gfx.prevPos.y
obj.oPosZ = obj.header.gfx.prevPos.z
audio_sample_play(SOUND_CUSTOM_RICOCHET, { x = obj.oPosX, y = obj.oPosY, z = obj.oPosZ }, 1)
end
--- @param obj Object
local function bullet_hit(obj)
spawn_mist_particles()
--[[if obj_count_objects_with_behavior_id(id_bhvBulletHole) < 100 then
local raycast = collision_find_surface_on_ray(obj.header.gfx.prevPos.x, obj.header.gfx.prevPos.y, obj.header.gfx.prevPos.z, obj.oVelX, obj.oVelY, obj.oVelZ)
if raycast.surface ~= nil and (cur_obj_detect_steep_floor(89) == 0 or cur_obj_detect_steep_floor(-89)) then
spawn_non_sync_object(
id_bhvBulletHole,
E_MODEL_BULLET_HOLE,
raycast.hitPos.x, raycast.hitPos.y, raycast.hitPos.z,
--- @param o Object
function(o)
o.parentObj = raycast.surface.object
end
)
end
end]]
obj_mark_for_deletion(obj)
end
---------------------------
-- hitbox hurt functions --
---------------------------
--- @param obj Object
--- @param bulletObj Object
function hurt_player(obj, bulletObj)
local m = gMarioStates[network_local_index_from_global(obj.globalPlayerIndex)]
if (m.flags & MARIO_METAL_CAP) ~= 0 then
bullet_ricochet(bulletObj)
play_sound(SOUND_GENERAL_METAL_POUND, m.marioObj.header.gfx.cameraToObject)
return false
elseif (m.flags & MARIO_VANISH_CAP) ~= 0 or m.invincTimer > 0 or (m.action & ACT_FLAG_INTANGIBLE) ~= 0 then
return false
else
packet_send(true, PACKET_ATTACK, { globalIndex = obj.globalPlayerIndex, weaponId = obj_get_weapon_id(bulletObj), yoshi = bulletObj.oAction == 2 })
end
return true
end
--- @param bulletObj Object
function hurt_star(_, bulletObj)
bullet_ricochet(bulletObj)
return false
end
--- @param obj Object
--- @param bulletObj Object
function hurt_sign(obj, bulletObj)
if obj.oGmHealth <= 0 or gWeaponTable[obj_get_weapon_id(bulletObj)].strong then
obj.oFaceAnglePitch = -0x4000
obj.oInteractType = 0
obj.hitboxRadius = 0
obj.hitboxHeight = 0
network_send_object(obj, false)
end
return true
end
--- @param obj Object
function hurt_toad(obj)
obj_spawn_yellow_coins(obj, 1)
obj_mark_for_deletion(obj)
network_send_object(obj, false)
return true
end
--- @param obj Object
function hurt_exclamation_box(obj)
if obj.oAction < 4 then
obj.oAction = 4
network_send_object(obj, true)
end
return true
end
--- @param obj Object
function hurt_breakable_box(obj)
if obj.oGmHealth <= 0 then
obj.oInteractStatus = INT_STATUS_INTERACTED | INT_STATUS_WAS_ATTACKED
network_send_object(obj, false)
end
return true
end
--- @param obj Object
function hurt_breakable_box_small(obj)
obj.oInteractStatus = ATTACK_KICK_OR_TRIP | INT_STATUS_INTERACTED | INT_STATUS_WAS_ATTACKED | INT_STATUS_STOP_RIDING
network_send_object(obj, false)
return true
end
--- @param obj Object
--- @param bulletObj Object
function hurt_bowling_ball(obj, bulletObj)
if obj.oGmHealth <= 0 or gWeaponTable[obj_get_weapon_id(bulletObj)].strong then
play_sound(SOUND_GENERAL_BREAK_BOX, obj.header.gfx.cameraToObject)
spawn_triangle_break_particles(30, 138, 3, 4)
obj_mark_for_deletion(obj)
end
return true
end
--- @param obj Object
function hurt_water_bomb(obj)
play_sound(SOUND_OBJ_DIVING_IN_WATER, obj.header.gfx.cameraToObject)
set_camera_shake_from_point(SHAKE_POS_SMALL, obj.oPosX, obj.oPosY, obj.oPosZ)
obj.oAction = WATER_BOMB_ACT_EXPLODE
return true
end
--- @param obj Object
--- @param bulletObj Object
function hurt_tree(obj, bulletObj)
for _ = 1, 10 do
spawn_non_sync_object(
id_bhvLeafParticleSpawner,
E_MODEL_NONE,
bulletObj.oPosX, bulletObj.oPosY, bulletObj.oPosZ,
nil
)
end
play_sound(SOUND_ACTION_CLIMB_UP_TREE, obj.header.gfx.cameraToObject)
return false
end
--- @param obj Object
--- @param bulletObj Object
function hurt_chain_chomp(obj, bulletObj)
if gWeaponTable[obj_get_weapon_id(bulletObj)].strong then
for _ = 1, 5 do
spawn_non_sync_object(
id_bhvExplosion,
E_MODEL_EXPLOSION,
obj.oPosX + math.random(-200, 200), obj.oPosY + 90 + math.random(-200, 200), obj.oPosZ + math.random(-200, 200),
nil
)
end
obj_mark_for_deletion(obj)
else
obj.oForwardVel = obj.oForwardVel - 5
obj.oVelY = -20
obj.oGravity = -4
end
network_send_object(obj, false)
play_sound(SOUND_GENERAL_CHAIN_CHOMP1, obj.header.gfx.cameraToObject)
return true
end
--- @param obj Object
--- @param bulletObj Object
function hurt_goomba(obj, bulletObj)
if gWeaponTable[obj_get_weapon_id(bulletObj)].strong then
obj.oInteractStatus = ATTACK_GROUND_POUND_OR_TWIRL | INT_STATUS_INTERACTED | INT_STATUS_WAS_ATTACKED
else
obj.oInteractStatus = ATTACK_KICK_OR_TRIP | INT_STATUS_INTERACTED | INT_STATUS_WAS_ATTACKED
end
network_send_object(obj, false)
return true
end
--- @param obj Object
function hurt_bobomb(obj)
if obj.oAction ~= BOBOMB_ACT_EXPLODE then
obj.oAction = BOBOMB_ACT_LAUNCHED
end
network_send_object(obj, false)
return true
end
--- @param obj Object
--- @param bulletObj Object
function hurt_amp(obj, bulletObj)
if gWeaponTable[obj_get_weapon_id(bulletObj)].strong then
play_sound(SOUND_GENERAL_BREAK_BOX, obj.header.gfx.cameraToObject)
spawn_triangle_break_particles(30, 138, 3, 4)
obj_mark_for_deletion(obj)
network_send_object(obj, false)
return true
else
bullet_ricochet(bulletObj)
play_sound(SOUND_ACTION_METAL_BONK, obj.header.gfx.cameraToObject)
end
return false
end
--- @param obj Object
function hurt_koopa(obj)
if obj.oKoopaMovementType == KOOPA_BP_UNSHELLED or obj.oKoopaMovementType == KOOPA_BP_NORMAL then
obj.oInteractStatus = ATTACK_KICK_OR_TRIP + (INT_STATUS_INTERACTED | INT_STATUS_WAS_ATTACKED)
network_send_object(obj, false)
end
return true
end
--- @param obj Object
function hurt_snufit(obj)
obj.oInteractStatus = ATTACK_PUNCH + (INT_STATUS_INTERACTED | INT_STATUS_WAS_ATTACKED)
network_send_object(obj, false)
return true
end
--- @param obj Object
function hurt_chuckya(obj)
obj_spawn_loot_yellow_coins(obj, 5, 20)
play_sound(SOUND_OBJ_CHUCKYA_DEATH, obj.header.gfx.cameraToObject)
obj_mark_for_deletion(obj)
network_send_object(obj, false)
return true
end
--- @param obj Object
function hurt_piranha_plant(obj)
obj.oAction = PIRANHA_PLANT_ACT_ATTACKED
stop_secondary_music(50)
network_send_object(obj, false)
return true
end
--- @param obj Object
function hurt_spindrift(obj)
obj.oInteractStatus = ATTACK_PUNCH + (INT_STATUS_INTERACTED | INT_STATUS_WAS_ATTACKED | INT_ATTACK_NOT_FROM_BELOW)
network_send_object(obj, false)
return true
end
--- @param obj Object
function hurt_mr_blizzard(obj)
play_sound(SOUND_OBJ_SNOWMAN_EXPLODE, obj.header.gfx.cameraToObject)
obj_mark_for_deletion(obj)
obj_spawn_loot_yellow_coins(obj, obj.oNumLootCoins, 20)
network_send_object(obj, false)
return true
end
--- @param obj Object
function hurt_scuttlebug(obj)
play_sound(SOUND_OBJ_DYING_ENEMY1, obj.header.gfx.cameraToObject)
obj_spawn_loot_yellow_coins(obj, obj.oNumLootCoins, 20)
obj_mark_for_deletion(obj)
network_send_object(obj, false)
return true
end
--- @param obj Object
function hurt_pokey(obj)
obj.oInteractStatus = ATTACK_PUNCH + (INT_STATUS_INTERACTED | INT_STATUS_WAS_ATTACKED)
return true
end
--- @param obj Object
function hurt_mr_i(obj)
obj.oAction = 3
network_send_object(obj, false)
return true
end
--- @param obj Object
--- @param bulletObj Object
function hurt_bully(obj, bulletObj)
obj.oAction = BULLY_ACT_KNOCKBACK
obj.oMoveAngleYaw = gMarioStates[network_local_index_from_global(obj_get_weapon_owner(bulletObj))].faceAngle.y
obj.oVelY = 30
obj.oForwardVel = if_then_else(gWeaponTable[obj_get_weapon_id(bulletObj)].strong, 30, 10)
obj.oInteractStatus = ATTACK_PUNCH + (INT_STATUS_INTERACTED | INT_STATUS_WAS_ATTACKED | INT_ATTACK_NOT_FROM_BELOW)
network_send_object(obj, false)
return true
end
--- @param obj Object
function hurt_moneybag(obj)
obj.oInteractStatus = INT_STATUS_INTERACTED | INT_STATUS_WAS_ATTACKED | INT_ATTACK_NOT_FROM_BELOW
network_send_object(obj, false)
return true
end
--- @param obj Object
--- @param bulletObj Object
function hurt_king_bobomb(obj, bulletObj)
if (obj.oGmHealth <= 0 or gWeaponTable[obj_get_weapon_id(bulletObj)].strong) and obj.oHealth > 0 then
obj.oGmHealth = HEALTH_KING_BOBOMB
obj.oMoveFlags = obj.oMoveFlags | OBJ_MOVE_LANDED
obj.oAction = 4
network_send_object(obj, true)
end
return true
end
--- @param obj Object
function hurt_bowser(obj)
if obj.oGmHealth <= 0 and obj.oHealth > 0 then
obj.oGmHealth = HEALTH_BOWSER
obj.oHealth = obj.oHealth - 1
if obj.oHealth <= 0 then
obj.oAction = 4
else
obj.oAction = 12
end
network_send_object(obj, true)
end
return true
end
--- @param bulletObj Object
function hurt_yoshi(_, bulletObj)
bullet_ricochet(bulletObj)
bulletObj.oAction = 2
djui_chat_message_create("\\#a0ffa0\\Yoshi\\#dcdcdc\\: no lol")
play_sound(SOUND_MENU_MESSAGE_APPEAR, gGlobalSoundSource)
return false
end
-------------
-- objects --
-------------
--- @param o Object
local function bhv_debug_indicator_init(o)
o.oFlags = OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE
obj_set_billboard(o)
cur_obj_scale(0.5)
end
local function bhv_debug_indicator_loop(o)
if o.oTimer > 90 then obj_mark_for_deletion(o) end
end
id_bhvDebugIndicator = hook_behavior(nil, OBJ_LIST_UNIMPORTANT, true, bhv_debug_indicator_init, bhv_debug_indicator_loop)
--- @param o Object
local function bhv_bullet_init(o)
o.oFlags = OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE
o.oGraphYOffset = if_then_else(obj_has_model_extended(o, E_MODEL_YELLOW_COIN) ~= 0, -5, 0)
o.hitboxRadius = 20
o.hitboxHeight = 20
o.hitboxDownOffset = 10
o.oWallHitboxRadius = 30
o.oIntangibleTimer = 0
vec3f_set(o.header.gfx.pos, o.oPosX, o.oPosY, o.oPosZ)
obj_set_billboard(o)
cur_obj_scale(gWeaponTable[obj_get_weapon_id(o)].bulletScale)
cur_obj_hide()
network_init_object(o, true, {})
end
--- @param o Object
local function bhv_bullet_loop(o)
if o.oTimer > 150 then
obj_mark_for_deletion(o)
return
end
if o.oTimer == 1 then cur_obj_unhide() end
local prevPos = { x = o.oPosX, y = o.oPosY, z = o.oPosZ }
if o.oVelY == 0 then
cur_obj_move_xz_using_fvel_and_yaw()
else
cur_obj_move_using_vel()
end
cur_obj_update_floor_and_resolve_wall_collisions(0)
local marioObj = gMarioStates[network_local_index_from_global(obj_get_weapon_owner(o))].marioObj
local shootableHitboxes = gShootableHitboxes -- localizing saves microseconds
-- loop through every shootable behavior
for behavior, hurt in pairs(shootableHitboxes) do
-- get the nearest object with the current shootable behavior
local target = obj_get_nearest_object_with_behavior_id(o, behavior)
if target ~= nil then
-- check if the bullet (o) intersects with the target object (target)
local shot = obj_check_hitbox_overlap(target, o)
-- if not, begin using the substep system to see if hitboxes overlap then
local weapon = gWeaponTable[obj_get_weapon_id(o)]
if not shot then
local bulletSteps = weapon.bulletSteps
for i = 0, bulletSteps do
local step = i / bulletSteps
-- go from the previous position of the bullet to the current one over bullet steps
local x = lerp(prevPos.x, o.oPosX, step)
local y = lerp(prevPos.y, o.oPosY, step)
local z = lerp(prevPos.z, o.oPosZ, step)
-- spawn_non_sync_object(id_bhvDebugIndicator, E_MODEL_RED_COIN_NO_SHADOW, x, y, z, nil)
-- check if the bullet (o) now intersects with target object (target)
shot = obj_check_hitbox_overlap_xyz(target, o, x, y, z)
-- hit target and break out of loop if so, otherwise continue
if shot and (marioObj._pointer ~= target._pointer or o.oAction > 0) then
target.oGmHealth = target.oGmHealth - weapon.damage
if hurt ~= nil and hurt(target, o) then
bullet_hit(o)
return
end
break
end
end
elseif marioObj._pointer ~= target._pointer or o.oAction > 0 then
target.oGmHealth = target.oGmHealth - weapon.damage
if hurt ~= nil and hurt(target, o) then
bullet_hit(o)
return
end
break
end
end
end
-- spawn_non_sync_object(id_bhvDebugIndicator, E_MODEL_YELLOW_COIN_NO_SHADOW, prevPos.x, prevPos.y, prevPos.z, nil)
-- spawn_non_sync_object(id_bhvDebugIndicator, E_MODEL_YELLOW_COIN_NO_SHADOW, o.oPosX, o.oPosY, o.oPosZ, nil)
local raycast = collision_find_surface_on_ray(prevPos.x, prevPos.y, prevPos.z, o.oPosX - prevPos.x, o.oPosY - prevPos.y, o.oPosZ - prevPos.z)
if raycast.surface ~= nil or (o.oMoveFlags & OBJ_MOVE_HIT_WALL) ~= 0 then
vec3f_to_object_pos(o, raycast.hitPos)
bullet_hit(o)
end
end
id_bhvBullet = hook_behavior(nil, OBJ_LIST_UNIMPORTANT, true, bhv_bullet_init, bhv_bullet_loop, "bhvGmBullet")
--- @param o Object
local function bhv_bullet_hole_init(o)
o.oFlags = OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE
end
--- @param o Object
local function bhv_bullet_hole_loop(o)
cur_obj_align_gfx_with_floor()
if o.oTimer == 450 then obj_mark_for_deletion(o) end
end
id_bhvBulletHole = hook_behavior(nil, OBJ_LIST_UNIMPORTANT, true, bhv_bullet_hole_init, bhv_bullet_hole_loop, "bhvGmBulletHole")
function spawn_bullets_player(x, y, z, count)
local weapon = cur_weapon()
if weapon == nil then return end
--- @type MarioState
local m = gMarioStates[0]
for _ = 1, count do
local spread = math.random() * weapon.spread
spawn_sync_object(
id_bhvBullet,
weapon.bulletModel,
x + spread, y + spread, z + spread,
--- @param o Object
function(o)
obj_set_weapon_params(o, gNetworkPlayers[0].globalIndex, weapon.id, 0, 0)
local enabled = get_first_person_enabled()
o.oFaceAngleYaw = if_then_else(enabled, m.area.camera.yaw + 0x8000, m.faceAngle.y)
o.oForwardVel = weapon.bulletSpeed
if enabled or (m.input & INPUT_FIRST_PERSON) ~= 0 then
-- thanks Peachy
local dx = m.area.camera.focus.x - m.area.camera.pos.x
local dy = m.area.camera.focus.y - m.area.camera.pos.y
local dz = m.area.camera.focus.z - m.area.camera.pos.z
local dv = math.sqrt(dx * dx + dy * dy + dz * dz)
o.oVelX = weapon.bulletSpeed * (dx / dv)
o.oVelY = weapon.bulletSpeed * (dy / dv)
o.oVelZ = weapon.bulletSpeed * (dz / dv)
end
end
)
end
end

View File

@ -1,89 +0,0 @@
if SM64COOPDX_VERSION == nil then return end
--- @param weapon Weapon
--- @return nil
function common_shoot(weapon)
--- @type MarioState
local m = gMarioStates[0]
if not weapon.reqCheck(m) then return end
if weapon.ammo <= 0 and weapon.maxAmmo > 0 then
audio_sample_play(SOUND_CUSTOM_DRY, gMarioStates[0].pos, 1)
return
end
local enabled = get_first_person_enabled()
local x = if_then_else(enabled, gLakituState.pos.x, m.pos.x)
local y = if_then_else(enabled, gLakituState.pos.y, m.pos.y + FIRST_PERSON_MARIO_HEAD_POS_SHORT)
local z = if_then_else(enabled, gLakituState.pos.z, m.pos.z)
spawn_bullets_player(x, y, z, weapon.bulletCount)
if #weapon.primarySounds > 0 then
sync_audio_sample_play(weapon.primarySounds[math.random(#weapon.primarySounds)], gMarioStates[0].pos, 1)
end
if weapon.maxAmmo > 0 then
weapon.ammo = weapon.ammo - 1
if weapon.ammo == 0 then common_reload(weapon) end
end
useDualWieldWeapon = not useDualWieldWeapon
end
--- @param weapon Weapon
--- @return nil
function common_reload(weapon)
--- @type MarioState
local m = gMarioStates[0]
if weapon.reloadTimer > 0 or not weapon.reqCheck(m) then return end
local weapon2 = if_then_else(useDualWieldWeapon, cur_weapon(), cur_dual_wield_weapon())
if weapon.ammo >= weapon.maxAmmo then
weapon.cooldownTimer = 0
if weapon2 ~= nil then
if weapon2.ammo >= weapon2.maxAmmo then
weapon2.cooldownTimer = 0
else
if #weapon.secondarySounds > 0 then
sync_audio_sample_play(weapon.secondarySounds[math.random(#weapon.secondarySounds)], m.pos, 1)
end
weapon2.ammo = 0
weapon2.reloadTimer = weapon2.reloadTime
end
end
return
end
if weapon2 ~= nil then
if weapon2.ammo >= weapon2.maxAmmo then
weapon2.cooldownTimer = 0
else
if #weapon.secondarySounds > 0 then
sync_audio_sample_play(weapon.secondarySounds[math.random(#weapon.secondarySounds)], m.pos, 1)
end
weapon2.ammo = 0
weapon2.reloadTimer = weapon2.reloadTime
end
end
if #weapon.secondarySounds > 0 then
sync_audio_sample_play(weapon.secondarySounds[math.random(#weapon.secondarySounds)], m.pos, 1)
end
weapon.ammo = 0
weapon.reloadTimer = weapon.reloadTime
end
--- @param m MarioState
function check_common_gun_requirements(m)
return m.health > 0xFF and
m.action ~= ACT_STAR_DANCE_EXIT and
m.action ~= ACT_STAR_DANCE_NO_EXIT and
m.action ~= ACT_STAR_DANCE_WATER and
m.action ~= ACT_LEDGE_GRAB and
m.action ~= ACT_LEDGE_CLIMB_FAST and
m.action ~= ACT_LEDGE_CLIMB_SLOW_1 and
m.action ~= ACT_LEDGE_CLIMB_SLOW_2 and
(m.action & ACT_GROUP_MASK) ~= ACT_GROUP_SUBMERGED and
m.action ~= ACT_DISAPPEARED
end

View File

@ -1,42 +0,0 @@
local seen = false
--- @param o Object
local function bhv_dialog_arrow_init(o)
o.oFlags = OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE
o.parentObj = obj_get_nearest_object_with_behavior_id(o, id_bhvMessagePanel)
if o.parentObj == nil then
obj_mark_for_deletion(o)
return
end
o.oDrawingDistance = o.parentObj.oDrawingDistance
o.oPosX = o.parentObj.oPosX
o.oPosY = o.parentObj.oPosY + 150
o.oPosZ = o.parentObj.oPosZ
end
--- @param o Object
local function bhv_dialog_arrow_loop(o)
o.oGraphYOffset = math.sin(o.oTimer * 0.1) * 20
if gMarioStates[0].interactObj == o.parentObj then
seen = true
obj_mark_for_deletion(o)
elseif o.parentObj.oInteractType == 0 then
obj_mark_for_deletion(o)
end
end
local id_bhvDialogArrow = hook_behavior(nil, OBJ_LIST_UNIMPORTANT, true, bhv_dialog_arrow_init, bhv_dialog_arrow_loop)
function spawn_dialog_arrow()
if gNetworkPlayers[0].currLevelNum ~= LEVEL_CASTLE_GROUNDS or not level_is_vanilla_level(LEVEL_CASTLE_GROUNDS) or seen then return end
spawn_non_sync_object(
id_bhvDialogArrow,
E_MODEL_ARROW,
-1567, 386, 3492,
nil
)
end

View File

@ -1,96 +0,0 @@
smlua_anim_util_register_animation("arm_idle",
0,
189,
0,
0,
60,
{
0x0000, 0xFFDD, 0x0000, 0x0000, 0x0000, 0xDFFF, 0xE000, 0xE002, 0xE006,
0xE00B, 0xE011, 0xE019, 0xE021, 0xE02A, 0xE034, 0xE03F, 0xE04A, 0xE056,
0xE061, 0xE06E, 0xE07A, 0xE086, 0xE092, 0xE09E, 0xE0AA, 0xE0B5, 0xE0C0,
0xE0CA, 0xE0D3, 0xE0DB, 0xE0E2, 0xE0E9, 0xE0EE, 0xE0F1, 0xE0F4, 0xE0F5,
0xE0F4, 0xE0F1, 0xE0EE, 0xE0E9, 0xE0E2, 0xE0DB, 0xE0D3, 0xE0CA, 0xE0C0,
0xE0B5, 0xE0AA, 0xE09E, 0xE092, 0xE086, 0xE07A, 0xE06E, 0xE061, 0xE056,
0xE04A, 0xE03F, 0xE034, 0xE02A, 0xE021, 0xE019, 0xE011, 0xE00B, 0xE006,
0xE002, 0xE000, 0xDFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF,
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF,
0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000,
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF,
0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF,
0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF,
0x0000, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0x0000,
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000,
0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x2000,
},
{
0x0001, 0x0000, 0x0001, 0x0001, 0x0001, 0x0002, 0x0001, 0x0003, 0x0001,
0x0004, 0x003D, 0x0005, 0x003D, 0x0042, 0x003D, 0x007F, 0x0001, 0x00BC,
}
)
smlua_anim_util_register_animation("arm_reload_start",
1,
189,
0,
0,
15,
{
0x0000, 0xFFE7, 0x0000, 0x0000, 0x0000, 0xDFFF, 0xE178, 0xE4FF, 0xE938,
0xECBF, 0xEE38, 0xECF3, 0xE973, 0xE428, 0xDD93, 0xD64E, 0xCF09, 0xC874,
0xC32A, 0xBFA9, 0xBE64, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0xFFFF,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF,
0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF, 0x0000, 0x2000, 0x2000,
0x2000, 0x2000, 0x2000, 0x2000, 0x1F2B, 0x1CE6, 0x1984, 0x155F, 0x10D5,
0x0C4C, 0x0826, 0x04C5, 0x027F, 0x01AA,
},
{
0x0001, 0x0000, 0x0001, 0x0001, 0x0001, 0x0002, 0x0001, 0x0003, 0x0001,
0x0004, 0x0010, 0x0005, 0x000F, 0x0015, 0x0010, 0x0024, 0x0010, 0x0034,
}
)
smlua_anim_util_register_animation("arm_reload_end",
1,
189,
0,
0,
15,
{
0x0000, 0xFFDD, 0x0000, 0x0000, 0x0000, 0xBE64, 0xBECF, 0xBFFC, 0xC1D1,
0xC432, 0xC704, 0xCA28, 0xCD7E, 0xD0E5, 0xD43C, 0xD760, 0xDA31, 0xDC92,
0xDE67, 0xDF94, 0xDFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0xFFFF,
0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF, 0xFFFF, 0x0000,
0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0xFFFF,
0xFFFF, 0xFFFF, 0x0000, 0xFD70, 0xFDDE, 0xFF13, 0x00F6, 0x0368, 0x064E,
0x0989, 0x0CF8, 0x1079, 0x13E8, 0x1723, 0x1A09, 0x1C7B, 0x1E5D, 0x1F92,
0x2000,
},
{
0x0001, 0x0000, 0x0001, 0x0001, 0x0001, 0x0002, 0x0001, 0x0003, 0x0001,
0x0004, 0x0010, 0x0005, 0x000C, 0x0015, 0x000F, 0x0021, 0x0010, 0x0030,
}
)
smlua_anim_util_register_animation("arm_shoot",
1,
189,
0,
0,
8,
{
0x0000, 0xFFDD, 0x0000, 0x0000, 0x0000, 0xDFFF, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF,
0x0000, 0xFFFF, 0x0000, 0x2000, 0x21AA, 0x2555, 0x2901, 0x2AAB, 0x2901,
0x2555, 0x21AA, 0x2000,
},
{
0x0001, 0x0000, 0x0001, 0x0001, 0x0001, 0x0002, 0x0001, 0x0003, 0x0001,
0x0004, 0x0001, 0x0005, 0x0007, 0x0006, 0x0008, 0x000D, 0x0009, 0x0015,
}
)

View File

@ -1,135 +0,0 @@
if SM64COOPDX_VERSION == nil then return end
local CAP_FLICKER_FRAMES = 0x4444449249255555 -- this is beyond my comprehension
gFirstPersonViewmodels = {
armObjs = { nil, nil },
gunObjs = { nil, nil }
}
--- @param o Object
local function bhv_viewmodel_init(o)
o.oFlags = OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE
o.oGraphYOffset = 0
end
--- @param o Object
local function bhv_viewmodel_loop(o)
if not gGlobalSyncTable.gunModEnabled or not get_first_person_enabled() then
obj_mark_for_deletion(o)
return
end
local dualWield = obj_get_weapon_dual_wield(o) ~= 0
--- @type Weapon
local weapon = if_then_else(dualWield, cur_dual_wield_weapon(), cur_weapon())
if not weapon.reqCheck(gMarioStates[0]) then
cur_obj_hide()
else
cur_obj_unhide()
end
local horizontalOffset = 30
if cur_dual_wield_weapon() ~= nil then
horizontalOffset = if_then_else(obj_get_weapon_dual_wield(o) ~= 0, -50, 50)
end
-- math to calculate staying in the same screen position no matter what
o.oPosX = gLakituState.pos.x - 35 * coss(gFirstPersonCamera.pitch) * sins(gFirstPersonCamera.yaw)
o.oPosY = gLakituState.pos.y - 35 * sins(gFirstPersonCamera.pitch)
o.oPosZ = gLakituState.pos.z - 35 * coss(gFirstPersonCamera.pitch) * coss(gFirstPersonCamera.yaw)
-- math to offset it to the left or right
o.oPosX = o.oPosX + sins(gFirstPersonCamera.yaw + 0x4000) * horizontalOffset
o.oPosZ = o.oPosZ + coss(gFirstPersonCamera.yaw + 0x4000) * horizontalOffset
o.oFaceAnglePitch = 0
o.oFaceAngleYaw = gFirstPersonCamera.yaw + 0x4000
o.oFaceAngleRoll = -gFirstPersonCamera.pitch
if weapon ~= nil then
if weapon.deployTimer > 0 then
obj_set_animation(o, "arm_reload_end")
-- freeze animation if the time hasn't come to show the arm rising up
if o.header.gfx.animInfo.animFrame > 0 and weapon.deployTimer - o.header.gfx.animInfo.curAnim.loopEnd > 0 then
o.header.gfx.animInfo.animFrame = 0
end
else
local half = math.floor(weapon.reloadTime * 0.5)
if weapon.reloadTimer <= 0 then
if weapon.cooldownTimer > 0 then
obj_set_animation(o, "arm_shoot")
else
obj_set_animation(o, "arm_idle")
-- *try* keep both arms in sync
if dualWield then
o.header.gfx.animInfo.animFrame = gFirstPersonViewmodels.armObjs[1].header.gfx.animInfo.animFrame
end
end
elseif weapon.reloadTimer < half then
obj_set_animation(o, "arm_reload_end")
else
obj_set_animation(o, "arm_reload_start")
end
end
end
o.globalPlayerIndex = gNetworkPlayers[0].globalIndex
--- @type MarioState
local m = gMarioStates[0]
if m.capTimer < 64 and ((1 << m.capTimer) & CAP_FLICKER_FRAMES) ~= 0 then
o.oAnimState = 0
else
local vanishCap = if_then_else((gMarioStates[0].flags & MARIO_VANISH_CAP) ~= 0, 2, 0)
local metalCap = if_then_else((gMarioStates[0].flags & MARIO_METAL_CAP) ~= 0, 1, 0)
o.oAnimState = metalCap + vanishCap
end
end
id_bhvViewmodel = hook_behavior(nil, OBJ_LIST_GENACTOR, true, bhv_viewmodel_init, bhv_viewmodel_loop, "bhvGmViewmodel")
--- @param weapon Weapon
local function spawn_viewmodel(weapon, dualWield)
local index = if_then_else(dualWield, 1, 2)
dualWield = if_then_else(dualWield, 1, 0)
gFirstPersonViewmodels.armObjs[index] = spawn_non_sync_object(
id_bhvViewmodel,
weapon.armModel,
0, -10000, 0,
--- @param o Object
function(o)
obj_set_weapon_params(o, 0, 0, dualWield, 0)
end
)
gFirstPersonViewmodels.gunObjs[index] = spawn_non_sync_object(
id_bhvViewmodel,
weapon.model,
0, -10000, 0,
--- @param o Object
function(o)
obj_set_weapon_params(o, 0, 0, dualWield, 0)
end
)
end
function spawn_viewmodels()
local weapon1 = cur_weapon()
local weapon2 = cur_dual_wield_weapon()
if weapon1 == nil then return end
spawn_viewmodel(weapon1, false)
if weapon2 ~= nil then spawn_viewmodel(weapon2, true) end
end
function delete_viewmodels()
gFirstPersonViewmodels.armObjs[1] = obj_mark_for_deletion(gFirstPersonViewmodels.armObjs[1])
gFirstPersonViewmodels.armObjs[2] = obj_mark_for_deletion(gFirstPersonViewmodels.armObjs[2])
gFirstPersonViewmodels.gunObjs[1] = obj_mark_for_deletion(gFirstPersonViewmodels.gunObjs[1])
gFirstPersonViewmodels.gunObjs[2] = obj_mark_for_deletion(gFirstPersonViewmodels.gunObjs[2])
end

View File

@ -1,593 +0,0 @@
if SM64COOPDX_VERSION == nil then return end
---------------------------------------
-- API and other important functions --
---------------------------------------
--- @class Weapon
--- @field public id integer
--- @field public name string
--- @field public dualWield boolean
--- @field public model ModelExtendedId
--- @field public armModel ModelExtendedId
--- @field public bulletModel ModelExtendedId
--- @field public primarySounds integer[]
--- @field public secondarySounds integer[]
--- @field public strong boolean
--- @field public rapidFire boolean
--- @field public spread number
--- @field public damage number
--- @field public bulletCount integer
--- @field public bulletScale number
--- @field public bulletSpeed number
--- @field public bulletSteps integer
--- @field public maxAmmo integer
--- @field public ammo integer
--- @field public deployTime integer
--- @field public cooldownTime integer
--- @field public reloadTime integer
--- @field public deployTimer integer
--- @field public cooldownTimer integer
--- @field public reloadTimer integer
--- @field public primaryFireFunc fun(weapon:Weapon)
--- @field public secondaryFireFunc fun(weapon:Weapon)
--- @field public reqCheck fun(m:MarioState)
--- @class WeaponId
--- @type Weapon[]
gWeaponTable = {}
--- @type Weapon[]
gInventory = {}
for i = 1, MAX_INVENTORY_SLOTS do gInventory[i] = nil end
inventorySlot = 1
useDualWieldWeapon = false
local weaponObtained = false
local weaponId = -1
local sMutableWeaponFields = {
["ammo"] = true,
["deployTimer"] = true,
["cooldownTimer"] = true,
["reloadTimer"] = true
}
local sReadonlyMetatable = {
__index = function(table, key)
return rawget(table, key)
end,
__newindex = function()
error("attempt to update a read-only table", 2)
end
}
local sWeaponMetatable = {
__index = function(table, key)
return rawget(table, key)
end,
__newindex = function(table, key, value)
if sMutableWeaponFields[key] then
rawset(table, key, value)
else
error("attempt to update an immutable weapon field", 2)
end
end
}
--- @param name string
--- @param dualWield boolean
--- @param model ModelExtendedId
--- @param armModel ModelExtendedId
--- @param bulletModel ModelExtendedId
--- @param primarySounds integer[]
--- @param secondarySounds integer[]
--- @param strong boolean
--- @param rapidFire boolean
--- @param spread number
--- @param damage number
--- @param bulletCount integer
--- @param bulletScale number
--- @param bulletSpeed number
--- @param bulletSteps integer
--- @param maxAmmo integer
--- @param deployTime integer
--- @param cooldownTime integer
--- @param reloadTime integer
--- @param primaryFireFunc fun(weapon:Weapon)
--- @param secondaryFireFunc fun(weapon:Weapon)
--- @param reqCheck function
--- @return integer
--- Registers a weapon metatable into existence
function weapon_register(name, dualWield, model, armModel, bulletModel, primarySounds, secondarySounds, strong, rapidFire, spread, damage, bulletCount, bulletScale, bulletSpeed, bulletSteps, maxAmmo, deployTime, cooldownTime, reloadTime, primaryFireFunc, secondaryFireFunc, reqCheck)
weaponId = weaponId + 1
gWeaponTable[weaponId] = {
id = weaponId,
name = name,
dualWield = dualWield,
model = model,
armModel = armModel,
bulletModel = bulletModel,
primarySounds = primarySounds,
secondarySounds = secondarySounds,
strong = strong,
rapidFire = rapidFire,
spread = spread,
damage = damage,
bulletCount = bulletCount,
bulletScale = bulletScale,
bulletSpeed = bulletSpeed,
bulletSteps = bulletSteps,
maxAmmo = maxAmmo,
ammo = maxAmmo,
deployTime = deployTime,
cooldownTime = cooldownTime,
reloadTime = reloadTime,
deployTimer = deployTime,
cooldownTimer = 0,
reloadTimer = 0,
primaryFireFunc = primaryFireFunc,
secondaryFireFunc = secondaryFireFunc,
reqCheck = reqCheck
}
setmetatable(gWeaponTable[weaponId], sReadonlyMetatable)
return weaponId
end
--- @param id integer
--- @return nil
--- Unregisters a weapon from existence by ID
function weapon_unregister(id)
if type(id) ~= "number" then return end
gWeaponTable[id] = nil
end
--- @return nil
--- Unregisters all weapons from existence
function weapon_unregister_all()
gWeaponTable = {}
end
--- @return string
--- Properly formatted weapon list string for commands
function get_weapon_list_string()
local string = "["
for id, weapon in pairs(gWeaponTable) do
string = string .. weapon.name:lower()
if id < weaponId then
string = string .. "|"
end
end
string = string .. "]"
return string
end
--- @param obj Object
--- @param owner integer
--- @param id integer
--- @param dualWield integer
--- @param extra integer
--- @return nil
--- Returns a 4 byte behavior parameter integer for weapon objects.
function obj_set_weapon_params(obj, owner, id, dualWield, extra)
if obj == nil then return end
if type(owner) ~= "number" or type(id) ~= "number" or type(dualWield) ~= "number" or type(extra) ~= "number" then return end
obj.oBehParams = owner | (id << 8) | (dualWield << 16) | (extra << 24)
obj.oBehParams2ndByte = id
end
--- @param obj Object
--- @return integer
--- Returns the owner parameter (first parameter) of a weapon object.
function obj_get_weapon_owner(obj)
if obj == nil then return 0 end
return obj.oBehParams & 0xFF
end
--- @param obj Object
--- @return integer
--- Returns the id parameter (second parameter) of a weapon object.
function obj_get_weapon_id(obj)
if obj == nil then return 0 end
return obj.oBehParams2ndByte
end
--- @param obj Object
--- @return integer
--- Returns the dual wield parameter (third parameter) of a weapon object.
function obj_get_weapon_dual_wield(obj)
if obj == nil then return 0 end
return (obj.oBehParams >> 16) & 0xFF
end
--- @param obj Object
--- @return integer
--- Returns the extra parameter (fourth parameter) of a weapon object.
function obj_get_weapon_extra(obj)
if obj == nil then return 0 end
return (obj.oBehParams >> 24) & 0xFF
end
--- @return Weapon|nil
--- Returns the table of the current weapon
function cur_weapon()
return gInventory[inventorySlot]
end
--- @return Weapon|nil
--- Returns the table of the current dual wielding weapon
function cur_dual_wield_weapon()
local weapon = cur_weapon()
if weapon == nil or not weapon.dualWield then return nil end
local weaponBefore = gInventory[inventorySlot - 1]
if weaponBefore ~= nil and weaponBefore.dualWield and weaponBefore.id == weapon.id then return weaponBefore end
local weaponAfter = gInventory[inventorySlot + 1]
if weaponAfter ~= nil and weaponAfter.dualWield and weaponAfter.id == weapon.id then return weaponAfter end
return nil
end
--- @return integer
--- Returns the current inventory slot
function get_inventory_slot()
return inventorySlot
end
--- @param slot integer
--- @return nil
--- Sets the current inventory slot
function set_inventory_slot(slot)
if type(slot) ~= "number" then return end
-- reset fields
gInventory[slot].deployTimer = gInventory[slot].deployTime
gInventory[slot].cooldownTimer = 0
gInventory[slot].reloadTimer = if_then_else(gInventory[slot].ammo <= 0 and gInventory[slot].maxAmmo > 0, gInventory[slot].reloadTime, 0)
inventorySlot = clamp(slot, 1, MAX_INVENTORY_SLOTS)
sync_current_weapons()
delete_held_weapon()
if get_first_person_enabled() then
delete_viewmodels()
spawn_viewmodels()
end
end
local function table_clone(table)
local cloned = {}
for k, v in pairs(table) do
if type(v) == "table" then
cloned[k] = table_clone(v)
else
cloned[k] = v
end
end
return cloned
end
--- @param weapon WeaponId
local function inventory_clone(weapon)
local table = table_clone(gWeaponTable[weapon])
setmetatable(table, sWeaponMetatable)
return table
end
local function get_inventory_slots_used()
local count = 0
for i = 1, MAX_INVENTORY_SLOTS do
if gInventory[i] ~= nil then
count = count + 1
end
end
return count
end
--- @param weapon WeaponId
--- @return boolean
--- Picks up a weapon by ID
function pickup_weapon(weapon)
if type(weapon) ~= "number" then return false end
for i = 1, MAX_INVENTORY_SLOTS do
if gInventory[i] == weapon then
return false
elseif gInventory[i] == nil or get_inventory_slots_used() == MAX_INVENTORY_SLOTS then
if not weaponObtained then
play_sound(SOUND_MENU_STAR_SOUND, gMarioStates[0].marioObj.header.gfx.cameraToObject)
weaponObtained = true
else
play_sound(SOUND_MENU_CLICK_CHANGE_VIEW, gMarioStates[0].marioObj.header.gfx.cameraToObject)
end
gInventory[i] = inventory_clone(weapon)
set_inventory_slot(i)
return true
end
end
return false
end
function sync_current_weapons()
gPlayerSyncTable[0].curWeapon = nil
gPlayerSyncTable[0].curWeapon2 = nil
local weapon = cur_weapon()
if weapon ~= nil then
gPlayerSyncTable[0].curWeapon = weapon.id
end
local weapon2 = cur_dual_wield_weapon()
if weapon2 ~= nil then
gPlayerSyncTable[0].curWeapon2 = weapon2.id
end
end
--- @param weapon Weapon
function handle_reloading(weapon)
if weapon == nil then return end
if weapon.reloadTimer > 0 then
weapon.reloadTimer = weapon.reloadTimer - 1
if weapon.name == "Shotgun" then
weapon.ammo = math.floor(lerp(weapon.maxAmmo, 0, weapon.reloadTimer / weapon.reloadTime))
end
if weapon.reloadTimer == 0 then
weapon.ammo = weapon.maxAmmo
end
end
end
function weapon_update()
--- @type MarioState
local m = gMarioStates[0]
-- update inventory slot
if (m.controller.buttonPressed & U_JPAD) ~= 0 then
inventorySlot = inventorySlot + 1
if inventorySlot > MAX_INVENTORY_SLOTS then
inventorySlot = 1
end
set_inventory_slot(inventorySlot)
elseif (m.controller.buttonPressed & D_JPAD) ~= 0 then
inventorySlot = inventorySlot - 1
if inventorySlot < 1 then
inventorySlot = MAX_INVENTORY_SLOTS
end
set_inventory_slot(inventorySlot)
end
local weapon1 = cur_weapon()
local weapon2 = cur_dual_wield_weapon()
--- @type Weapon
local weapon = if_then_else(weapon2 ~= nil and useDualWieldWeapon, weapon2, weapon1)
if weapon1 == nil then return end -- if the player isn't holding a weapon
if weapon.deployTimer <= 0 and weapon.cooldownTimer <= 0 then
local buttonFlags = if_then_else(weapon.rapidFire, m.controller.buttonDown, m.controller.buttonPressed)
if (buttonFlags & Y_BUTTON) ~= 0 and weapon.primaryFireFunc ~= nil then
weapon.cooldownTimer = weapon.cooldownTime
weapon.primaryFireFunc(weapon)
elseif (buttonFlags & X_BUTTON) ~= 0 and weapon.secondaryFireFunc ~= nil then
weapon.cooldownTimer = weapon.cooldownTime
weapon.secondaryFireFunc(weapon)
end
end
weapon1.deployTimer = handle_timer(weapon1.deployTimer)
weapon1.cooldownTimer = handle_timer(weapon1.cooldownTimer)
if weapon2 ~= nil then
weapon2.deployTimer = handle_timer(weapon2.deployTimer)
weapon2.cooldownTimer = handle_timer(weapon2.cooldownTimer)
end
handle_reloading(weapon1)
handle_reloading(weapon2)
end
function delete_held_weapon()
local held = obj_get_first_with_behavior_id(id_bhvHeldWeapon)
while held ~= nil do
if obj_get_weapon_owner(held) == gNetworkPlayers[0].globalIndex then
obj_mark_for_deletion(held)
end
held = obj_get_next_with_same_behavior_id(held)
end
end
-------------
-- objects --
-------------
--- @param o Object
local function bhv_held_weapon_init(o)
o.oFlags = OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE
o.oGraphYOffset = 10
cur_obj_scale(0.6)
cur_obj_hide()
end
--- @param o Object
local function bhv_held_weapon_loop(o)
local np = network_player_from_global_index(obj_get_weapon_owner(o))
if np == nil or not gGlobalSyncTable.gunModEnabled then
obj_mark_for_deletion(o)
return
end
local m = gMarioStates[np.localIndex]
local dualWield = obj_get_weapon_dual_wield(o)
--- @type Weapon|nil
local weapon = if_then_else(dualWield ~= 0, cur_dual_wield_weapon(), cur_weapon())
if active_player(m) == 0 or weapon == nil then
obj_mark_for_deletion(o)
return
end
local index = if_then_else(dualWield ~= 0, 1, 0)
if m.marioBodyState.updateTorsoTime == gMarioStates[0].marioBodyState.updateTorsoTime and m.marioBodyState.handState == MARIO_HAND_FISTS and weapon.reqCheck(m) then
cur_obj_unhide()
o.oPosX = get_hand_foot_pos_x(m, index) + m.vel.x - (sins(m.faceAngle.y) * 30)
o.oPosY = get_hand_foot_pos_y(m, index) + m.vel.y + if_then_else(m.action == ACT_JUMP or m.action == ACT_DOUBLE_JUMP, 20, 0)
o.oPosZ = get_hand_foot_pos_z(m, index) + m.vel.z - (coss(m.faceAngle.y) * 30)
o.oFaceAngleYaw = m.faceAngle.y - 0x4000
o.oFaceAnglePitch = 0
o.oFaceAngleRoll = 0
else
cur_obj_hide()
o.oPosX = m.pos.x
o.oPosY = m.pos.y + 60
o.oPosZ = m.pos.z
end
if m.playerIndex == 0 and get_first_person_enabled() then
cur_obj_hide()
end
obj_set_model_extended(o, weapon.model)
end
id_bhvHeldWeapon = hook_behavior(nil, OBJ_LIST_GENACTOR, true, bhv_held_weapon_init, bhv_held_weapon_loop, "bhvGmHeldWeapon")
--- @param o Object
local function bhv_pickup_weapon_init(o)
o.oFlags = OBJ_FLAG_UPDATE_GFX_POS_AND_ANGLE
o.oIntangibleTimer = 0
obj_scale(o, 0.75)
o.hitboxRadius = 90
o.hitboxHeight = 90
network_init_object(o, true, {})
end
--- @param o Object
local function bhv_pickup_weapon_loop(o)
cur_obj_update_floor_height()
o.oPosY = o.oFloorHeight + 130
o.oFaceAngleYaw = o.oFaceAngleYaw + 0x800
local nearest = nearest_mario_state_to_object(o)
if obj_check_hitbox_overlap(o, nearest.marioObj) and o.oIntangibleTimer == 0 and nearest.playerIndex == 0 then
o.oIntangibleTimer = 450
pickup_weapon(o.oBehParams)
end
if o.oIntangibleTimer ~= 0 then
cur_obj_hide()
else
cur_obj_unhide()
o.oGraphYOffset = math.sin(o.oTimer * 0.5) * 5
end
end
id_bhvWeaponPickup = hook_behavior(nil, OBJ_LIST_LEVEL, true, bhv_pickup_weapon_init, bhv_pickup_weapon_loop, "bhvGmWeaponPickup")
-------------
-- weapons --
-------------
WEAPON_PISTOL = weapon_register(
"Pistol", -- name
true, -- dual wieldable
E_MODEL_PISTOL, -- weapon model
E_MODEL_SINGLE_ARM, -- arm model
E_MODEL_YELLOW_COIN, -- bullet model
{ sync_audio_sample_load("pistol_shoot.mp3") }, -- primary sounds
{ sync_audio_sample_load("pistol_reload.mp3") }, -- secondary sounds
false, -- strong weapon
false, -- rapid fire
10, -- spread
15, -- damage
1, -- bullet count
0.2, -- bullet scale
500, -- bullet speed
10, -- bullet steps
18, -- max ammo
15, -- deploy time
5, -- cooldown time
60, -- reload time
common_shoot, -- primary fire
common_reload, -- secondary fire
check_common_gun_requirements -- requirement checks function
)
WEAPON_MAGNUM = weapon_register(
"Magnum", -- name
true, -- dual wieldable
E_MODEL_MAGNUM, -- weapon model
E_MODEL_SINGLE_ARM, -- arm model
E_MODEL_METALLIC_BALL, -- bullet model
{ sync_audio_sample_load("magnum_shoot.mp3") }, -- primary sounds
{ sync_audio_sample_load("magnum_reload.mp3") }, -- secondary sounds
false, -- strong weapon
false, -- rapid fire
0, -- spread
50, -- damage
1, -- bullet count
0.2, -- bullet scale
2000, -- bullet speed
40, -- bullet steps
6, -- max ammo
15, -- deploy time
30, -- cooldown time
90, -- reload time
common_shoot, -- primary fire
common_reload, -- secondary fire
check_common_gun_requirements -- requirement checks function
)
WEAPON_AK47 = weapon_register(
"AK47", -- name
false, -- dual wieldable
E_MODEL_AK47, -- weapon model
E_MODEL_SINGLE_ARM, -- arm model
E_MODEL_YELLOW_COIN, -- bullet model
{ sync_audio_sample_load("ak47_shoot.mp3") }, -- primary sounds
{ sync_audio_sample_load("pistol_reload.mp3") }, -- secondary sounds
false, -- strong weapon
true, -- rapid fire
30, -- spread
10, -- damage
1, -- bullet count
0.2, -- bullet scale
500, -- bullet speed
10, -- bullet steps
40, -- max ammo
30, -- deploy time
4, -- cooldown time
70, -- reload time
common_shoot, -- primary fire
common_reload, -- secondary fire
check_common_gun_requirements -- requirement checks function
)
--[[WEAPON_SHOTGUN = weapon_register(
"Shotgun", -- name
false, -- dual wieldable
E_MODEL_SHOTGUN, -- weapon model
E_MODEL_SINGLE_ARM, -- arm model
E_MODEL_RED_COIN, -- bullet model
{ sync_audio_sample_load("shotgun_shoot.mp3") }, -- primary sounds
{}, -- secondary sounds
true, -- strong weapon
false, -- rapid fire
50, -- spread
6, -- damage
5, -- bullet count
0.2, -- bullet scale
1000, -- bullet speed
20, -- bullet steps
7, -- max ammo
15, -- deploy time
30, -- cooldown time
120, -- reload time
common_shoot, -- primary fire
common_reload, -- secondary fire
check_common_gun_requirements -- requirement checks function
)]]

View File

@ -1,407 +0,0 @@
-- 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)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.