224 lines
7.6 KiB
Lua
224 lines
7.6 KiB
Lua
-- 脚本位置 "{命名空间}:{路径}",require 格式 "{命名空间}_{路径}"
|
||
local default = require("tacz_manual_action_state_machine")
|
||
local STATIC_TRACK_LINE = default.STATIC_TRACK_LINE
|
||
local MAIN_TRACK = default.MAIN_TRACK
|
||
local main_track_states = default.main_track_states
|
||
|
||
-- override idle state
|
||
local idle_state = setmetatable({}, {__index = main_track_states.idle})
|
||
|
||
-- custom reload state
|
||
local reload_state = {
|
||
need_ammo = 0,
|
||
loaded_ammo = 0
|
||
}
|
||
|
||
-- override start state so we control the draw animation
|
||
local start_state = setmetatable({}, { __index = main_track_states.start })
|
||
|
||
|
||
local end_state = setmetatable({}, { __index = main_track_states["end"] })
|
||
|
||
|
||
|
||
function end_state.transition(this, context, input)
|
||
if input == INPUT_PUT_AWAY then
|
||
local track = context:getTrack(STATIC_TRACK_LINE, MAIN_TRACK)
|
||
local ammo = context:getAmmoCount() or 0
|
||
local hasBarrel = context:hasBulletInBarrel()
|
||
|
||
if ammo <= 0 and not hasBarrel then
|
||
context:runAnimation("put_away_empty", track, false, PLAY_ONCE_STOP, 0.15)
|
||
else
|
||
context:runAnimation("put_away", track, false, PLAY_ONCE_STOP, 0.15)
|
||
end
|
||
|
||
return nil
|
||
end
|
||
|
||
if main_track_states["end"] and main_track_states["end"].transition then
|
||
return main_track_states["end"].transition(this, context, input)
|
||
end
|
||
return nil
|
||
end
|
||
|
||
|
||
|
||
|
||
|
||
|
||
-------------------------------------------------------
|
||
-- UTILITY
|
||
-------------------------------------------------------
|
||
local function get_ejection_time(context)
|
||
local ejection_time = context:getStateMachineParams().intro_shell_ejecting_time
|
||
if (ejection_time) then
|
||
ejection_time = ejection_time * 1000
|
||
else
|
||
ejection_time = 0
|
||
end
|
||
return ejection_time
|
||
end
|
||
|
||
-------------------------------------------------------
|
||
-- INSPECT ANIM
|
||
-------------------------------------------------------
|
||
local function runInspectAnimation(context)
|
||
local track = context:getTrack(STATIC_TRACK_LINE, MAIN_TRACK)
|
||
local ammo = context:getAmmoCount()
|
||
local hasBarrel = context:hasBulletInBarrel()
|
||
|
||
if (ammo <= 0 and not hasBarrel) then
|
||
context:runAnimation("inspect_empty", track, false, PLAY_ONCE_STOP, 0.2)
|
||
elseif (ammo <= 0) then
|
||
context:runAnimation("inspect_01", track, false, PLAY_ONCE_STOP, 0.2)
|
||
else
|
||
context:runAnimation("inspect", track, false, PLAY_ONCE_STOP, 0.2)
|
||
end
|
||
end
|
||
|
||
-------------------------------------------------------
|
||
-- START (DRAW) OVERRIDE — plays draw_empty when ammo == 0
|
||
-------------------------------------------------------
|
||
function start_state.transition(this, context, input)
|
||
-- when weapon is drawn the state machine sends INPUT_DRAW
|
||
if input == INPUT_DRAW then
|
||
local track = context:getTrack(STATIC_TRACK_LINE, MAIN_TRACK)
|
||
local ammo = context:getAmmoCount() or 0
|
||
-- check chambered bullet too if you want fully empty detection:
|
||
local hasBarrel = context:hasBulletInBarrel()
|
||
if ammo <= 0 and not hasBarrel then
|
||
-- completely empty: draw_empty
|
||
context:runAnimation("draw_empty", track, false, PLAY_ONCE_STOP, 0.15)
|
||
else
|
||
-- has ammo somewhere: normal draw
|
||
context:runAnimation("draw", track, false, PLAY_ONCE_STOP, 0.15)
|
||
end
|
||
|
||
-- after draw, go to idle
|
||
return this.main_track_states.idle
|
||
end
|
||
|
||
-- any other inputs: delegate to default start transition
|
||
if main_track_states.start and main_track_states.start.transition then
|
||
return main_track_states.start.transition(this, context, input)
|
||
end
|
||
return nil
|
||
end
|
||
|
||
-------------------------------------------------------
|
||
-- IDLE TRANSITION OVERRIDE (reload + inspect)
|
||
-------------------------------------------------------
|
||
function idle_state.transition(this, context, input)
|
||
if input == INPUT_PUT_AWAY then
|
||
local track = context:getTrack(STATIC_TRACK_LINE, MAIN_TRACK)
|
||
local ammo = context:getAmmoCount() or 0
|
||
local hasBarrel = context:hasBulletInBarrel()
|
||
|
||
if ammo <= 0 and not hasBarrel then
|
||
context:runAnimation("put_away_empty", track, false, PLAY_ONCE_HOLD, 0.15)
|
||
else
|
||
context:runAnimation("put_away", track, false, PLAY_ONCE_HOLD, 0.15)
|
||
end
|
||
|
||
-- let default machine go to end state
|
||
return this.main_track_states["end"]
|
||
end
|
||
|
||
if input == INPUT_RELOAD then
|
||
return this.main_track_states.reload
|
||
end
|
||
|
||
if input == INPUT_INSPECT then
|
||
runInspectAnimation(context)
|
||
return this.main_track_states.inspect
|
||
end
|
||
|
||
return main_track_states.idle.transition(this, context, input)
|
||
end
|
||
|
||
|
||
-------------------------------------------------------
|
||
-- RELOAD ENTRY
|
||
-------------------------------------------------------
|
||
function reload_state.entry(this, context)
|
||
local state = this.main_track_states.reload
|
||
|
||
local ammo = context:getAmmoCount() or 0
|
||
local hasBarrel = context:hasBulletInBarrel()
|
||
local empty = (ammo <= 0 and not hasBarrel)
|
||
|
||
local track = context:getTrack(STATIC_TRACK_LINE, MAIN_TRACK)
|
||
|
||
if empty then
|
||
state.timestamp = context:getCurrentTimestamp()
|
||
state.ejection_time = get_ejection_time(context)
|
||
context:runAnimation("reload_intro_empty", track, false, PLAY_ONCE_HOLD, 0.2)
|
||
else
|
||
state.timestamp = -1
|
||
state.ejection_time = 0
|
||
context:runAnimation("reload_intro", track, false, PLAY_ONCE_HOLD, 0.2)
|
||
end
|
||
|
||
state.need_ammo = context:getMaxAmmoCount() - context:getAmmoCount()
|
||
state.loaded_ammo = 0
|
||
end
|
||
|
||
-------------------------------------------------------
|
||
-- RELOAD UPDATE
|
||
-------------------------------------------------------
|
||
function reload_state.update(this, context)
|
||
local state = this.main_track_states.reload
|
||
|
||
-- empty intro shell eject
|
||
if (state.timestamp ~= -1 and context:getCurrentTimestamp() - state.timestamp > state.ejection_time) then
|
||
context:popShellFrom(0)
|
||
state.timestamp = -1
|
||
end
|
||
|
||
if (state.loaded_ammo > state.need_ammo or not context:hasAmmoToConsume()) then
|
||
context:trigger(this.INPUT_RELOAD_RETREAT)
|
||
return
|
||
end
|
||
|
||
local track = context:getTrack(STATIC_TRACK_LINE, MAIN_TRACK)
|
||
if (context:isHolding(track)) then
|
||
context:runAnimation("reload_loop", track, false, PLAY_ONCE_HOLD, 0)
|
||
state.loaded_ammo = state.loaded_ammo + 1
|
||
end
|
||
end
|
||
|
||
-------------------------------------------------------
|
||
-- RELOAD TRANSITION END
|
||
-------------------------------------------------------
|
||
function reload_state.transition(this, context, input)
|
||
if (input == this.INPUT_RELOAD_RETREAT or input == INPUT_CANCEL_RELOAD) then
|
||
context:runAnimation("reload_end", context:getTrack(STATIC_TRACK_LINE, MAIN_TRACK), false, PLAY_ONCE_STOP, 0.2)
|
||
return this.main_track_states.idle
|
||
end
|
||
return this.main_track_states.idle.transition(this, context, input)
|
||
end
|
||
|
||
-------------------------------------------------------
|
||
-- EXPORT MACHINE
|
||
-------------------------------------------------------
|
||
local M = setmetatable({
|
||
main_track_states = setmetatable({
|
||
start = start_state,
|
||
idle = idle_state,
|
||
reload = reload_state,
|
||
["end"] = end_state,
|
||
}, { __index = main_track_states }),
|
||
INPUT_RELOAD_RETREAT = "reload_retreat",
|
||
}, { __index = default })
|
||
|
||
|
||
|
||
function M:initialize(context)
|
||
default.initialize(self, context)
|
||
self.main_track_states.reload.need_ammo = 0
|
||
self.main_track_states.reload.loaded_ammo = 0
|
||
end
|
||
|
||
return M
|