mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-25 05:25:14 +00:00
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:
parent
b7b044e0b2
commit
d9e50581ff
28 changed files with 0 additions and 2137 deletions
|
@ -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
|
|
@ -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.
Binary file not shown.
Binary file not shown.
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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,
|
||||
}
|
||||
)
|
|
@ -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
|
|
@ -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
|
||||
)]]
|
|
@ -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.
Binary file not shown.
Binary file not shown.
Loading…
Reference in a new issue