507 lines
15 KiB
Text
507 lines
15 KiB
Text
--function printf()
|
|
--end
|
|
|
|
local MARKER_IN = 1
|
|
local MARKER_OUT = 2
|
|
local MARKER_IDLE = 3
|
|
|
|
--' Àíèìàöèè ïåðñîíàæà
|
|
--' ìû óæå íàõîäèìñÿ â íåîáõîäèìîì ñîñòîÿíèè?
|
|
class "eva_state_mgr_animation" (property_evaluator)
|
|
function eva_state_mgr_animation:__init(name, st) super (nil, name)
|
|
self.st = st
|
|
end
|
|
function eva_state_mgr_animation:evaluate()
|
|
--printf("%s [%s] == [%s]", self.object:name(), tostring(state_lib.states[self.st.target_state].animation), tostring(self.st.animation.states.current_state))
|
|
return state_lib.states[self.st.target_state].animation == self.st.animation.states.current_state
|
|
end
|
|
|
|
|
|
--' Îòûãðûâàåì ëè ìû ñåé÷àñ èçâðàùåííóþ àíèìàöèþ
|
|
class "eva_state_mgr_animation_play_now" (property_evaluator)
|
|
function eva_state_mgr_animation_play_now:__init(name, st) super (nil, name)
|
|
self.st = st
|
|
end
|
|
function eva_state_mgr_animation_play_now:evaluate()
|
|
return self.st.animation.states.current_state ~= nil
|
|
end
|
|
|
|
|
|
--' ìû óæå íå îòûãðûâàåì íèêàêóþ èçâðàùåííóþ àíèìàöèþ
|
|
class "eva_state_mgr_animation_none_now" (property_evaluator)
|
|
function eva_state_mgr_animation_none_now:__init(name, st) super (nil, name)
|
|
self.st = st
|
|
end
|
|
function eva_state_mgr_animation_none_now:evaluate()
|
|
return self.st.animation.states.current_state == nil
|
|
end
|
|
|
|
--' Ìû íà÷àëè îòûãðûâàòü àíèìàöèþ è æäåì êîëëáåêà îò íåå
|
|
class "eva_state_mgr_animation_locked" (property_evaluator)
|
|
function eva_state_mgr_animation_locked:__init(name, st) super (nil, name)
|
|
self.st = st
|
|
end
|
|
function eva_state_mgr_animation_locked:evaluate()
|
|
--printf("anim_locked [%s] fast_set[%s] anim_marker[%s] sid[%s]", self.object:name(), tostring(self.st.fast_set), tostring(self.st.animation.states.anim_marker), tostring(self.st.animation.sid))
|
|
|
|
-- if self.st.fast_set == true then
|
|
-- return false
|
|
-- end
|
|
|
|
return self.st.animation.states.anim_marker ~= nil
|
|
end
|
|
|
|
|
|
|
|
--' Èãðàåì âõîäíóþ àíèìàöèþ
|
|
class "act_state_mgr_animation_start" (action_base)
|
|
function act_state_mgr_animation_start:__init(name, st) super (nil, name)
|
|
self.st = st
|
|
end
|
|
function act_state_mgr_animation_start:initialize()
|
|
action_base.initialize(self)
|
|
|
|
self.st.animation:set_state(state_lib.states[self.st.target_state].animation)
|
|
self.st.animation:set_control()
|
|
end
|
|
function act_state_mgr_animation_start:execute()
|
|
action_base.execute(self)
|
|
end
|
|
function act_state_mgr_animation_start:finalize()
|
|
action_base.finalize(self)
|
|
end
|
|
|
|
|
|
--' Èãðàåì âûõîäíóþ àíèìàöèþ
|
|
class "act_state_mgr_animation_stop" (action_base)
|
|
function act_state_mgr_animation_stop:__init(name, st) super (nil, name)
|
|
self.st = st
|
|
end
|
|
function act_state_mgr_animation_stop:initialize()
|
|
action_base.initialize(self)
|
|
|
|
self.st.animation:set_state(nil, self.st.fast_set or state_lib.states[self.st.target_state].fast_set)
|
|
self.st.animation:set_control()
|
|
end
|
|
function act_state_mgr_animation_stop:execute()
|
|
action_base.execute(self)
|
|
end
|
|
function act_state_mgr_animation_stop:finalize()
|
|
action_base.finalize(self)
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class "animation"
|
|
function animation:__init(npc, mgr, anim_path)
|
|
self.mgr = mgr
|
|
self.npc = npc
|
|
self.name = anim_path
|
|
|
|
self.anim_path = _G[anim_path]
|
|
self.sid = math.random(1000)
|
|
--printf("ANIMCLASS %s sid %s", self.npc:name(), tostring(self.sid))
|
|
--callstack()
|
|
|
|
self.states = {
|
|
last_id = nil,
|
|
current_state = nil,
|
|
target_state = nil,
|
|
anim_marker = nil,
|
|
next_rnd = nil,
|
|
seq_id = 1 }
|
|
|
|
end
|
|
-- Ïåðåäà÷à óïðàâëåíèÿ äàííîìó ýêçåìïëÿðó êëàññà.
|
|
function animation:set_control()
|
|
--printf("[%s] [%s] set control current_state[%s] marker[%s] sid[%s]", self.npc:name(), self.name, tostring(self.states.current_state), tostring(self.states.anim_marker), self.sid)
|
|
-- Óñòàíàâëèâàåì êîëëáåê
|
|
self.npc:set_callback(callback.script_animation, animation.animation_callback, self)
|
|
if self.name == "state_mgr_animation_list" then
|
|
self.mgr.animstate.states.anim_marker = nil
|
|
end
|
|
if self.states.anim_marker == nil then
|
|
self:update_anim()
|
|
end
|
|
end
|
|
-- Èíèöèàëèçèðóåì âûáîð àíèìàöèè
|
|
function animation:update_anim()
|
|
local anim, state = self:select_anim()
|
|
|
|
if anim ~= nil then
|
|
self:add_anim(anim, state)
|
|
end
|
|
end
|
|
-- Óñòàíîâêà öåëè, êàêóþ àíèìàöèþ íóæíî îòûãðûâàòü.
|
|
function animation:set_state(new_state, fast_set)
|
|
--printf("[%s] [%s] set new animation [%s], current_state [%s]", self.npc:name(), self.name, tostring(new_state), tostring(self.states.current_state))
|
|
-- print_table(self.states)
|
|
|
|
-- Áûñòðûé âûõîä, åñëè ïîíàäîáèòñÿ.
|
|
if fast_set == true then
|
|
--printf(" FAST SET %s sid(%s)", self.npc:name(), self.sid)
|
|
|
|
-- clear_animations
|
|
self.npc:clear_animations()
|
|
|
|
-- Äåòà÷íóòü àòà÷íóòûå ïðåäìåòû
|
|
local state
|
|
|
|
if self.states.anim_marker == MARKER_IN then
|
|
-- Åñëè â ìîìåíò ðåñåòà ìû èãðàåì âõîäíóþ àíèìàöèþ
|
|
state = self.anim_path.animations[self.states.target_state]
|
|
else
|
|
-- Åñëè â ìîìåíò ðåñåòà ìû èãðàåì âûõîäíóþ àíèìàöèþ èëè àéäë
|
|
state = self.anim_path.animations[self.states.current_state]
|
|
end
|
|
|
|
if state ~= nil and state.out ~= nil then
|
|
local wpn_slot = self:weapon_slot()
|
|
local anim_for_slot = self:anim_for_slot(wpn_slot, state.out)
|
|
|
|
if anim_for_slot ~= nil then
|
|
for k,next_anim in pairs(anim_for_slot) do
|
|
if type(next_anim) == "table" then
|
|
self:process_special_action(next_anim)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
|
|
-- ïåðåâåñòè current_state â nil
|
|
--printf("NULIFY ANIM MARKER %s", tostring(self.states.anim_marker))
|
|
self.states.anim_marker = nil
|
|
|
|
self.states.current_state = new_state
|
|
self.states.target_state = new_state
|
|
self.states.seq_id = 1
|
|
|
|
self.states.next_rnd = time_global()
|
|
return
|
|
end
|
|
|
|
|
|
self.states.target_state = new_state
|
|
self.states.next_rnd = time_global()
|
|
end
|
|
|
|
-- Âûáîð àíèìàöèè.
|
|
function animation:select_anim()
|
|
local states = self.states
|
|
--printf("[%s] [%s] select anim [%s], current_state [%s]", self.npc:name(), self.name, tostring(states.target_state), tostring(states.current_state))
|
|
--printf(" time %s", time_global())
|
|
--printf(" current state %s", utils.to_str(states.current_state))
|
|
--printf(" target state %s", utils.to_str(states.target_state))
|
|
|
|
|
|
if states.target_state ~= states.current_state then
|
|
-- Îäèí èç âîçìîæíûõ âàðèàíòîâ âûáîðà àíèìàøêè:
|
|
-- 1. Íóæíî îòûãðàòü âûõîä èç àíèìàöèè.
|
|
if states.target_state == nil then
|
|
--printf(" select out")
|
|
|
|
local state = self.anim_path.animations[states.current_state]
|
|
|
|
-- Åñëè íåò OUT àíèìàöèè
|
|
if state.out == nil then
|
|
states.anim_marker = MARKER_OUT
|
|
self:animation_callback(true)
|
|
return
|
|
end
|
|
|
|
states.anim_marker = MARKER_OUT
|
|
local wpn_slot = self:weapon_slot()
|
|
local anim_for_slot = self:anim_for_slot(wpn_slot, state.out)
|
|
if anim_for_slot == nil then
|
|
states.anim_marker = MARKER_OUT
|
|
self:animation_callback(true)
|
|
return nil
|
|
end
|
|
|
|
local next_anim = anim_for_slot[states.seq_id]
|
|
-- Åñëè ñëåäóþùàÿ àíèìàöèÿ - ñïåö äåéñòâèå
|
|
if type(next_anim) == "table" then
|
|
self:process_special_action(next_anim)
|
|
self:animation_callback()
|
|
return
|
|
end
|
|
return next_anim, state
|
|
end
|
|
|
|
-- 2. Íóæíî îòûãðàòü âõîä â àíèìàöèþ
|
|
if states.current_state == nil then
|
|
--printf(" select into, seq_id [%s], target [%s]", tostring(states.seq_id), tostring(states.target_state))
|
|
|
|
local state = self.anim_path.animations[states.target_state]
|
|
|
|
-- Åñëè íåò INTO àíèìàöèè
|
|
if state.into == nil then
|
|
states.anim_marker = MARKER_IN
|
|
self:animation_callback(true)
|
|
return nil
|
|
end
|
|
|
|
states.anim_marker = MARKER_IN
|
|
local wpn_slot = self:weapon_slot()
|
|
local anim_for_slot = self:anim_for_slot(wpn_slot, state.into)
|
|
if anim_for_slot == nil then
|
|
--printf("anim for slot nil")
|
|
states.anim_marker = MARKER_IN
|
|
self:animation_callback(true)
|
|
return nil
|
|
end
|
|
local next_anim = anim_for_slot[states.seq_id]
|
|
-- Åñëè ñëåäóþùàÿ àíèìàöèÿ - ñïåö äåéñòâèå
|
|
if type(next_anim) == "table" then
|
|
self:process_special_action(next_anim)
|
|
self:animation_callback()
|
|
return nil
|
|
end
|
|
return next_anim, state
|
|
end
|
|
end
|
|
|
|
-- 3. Íóæíî îòûãðàòü àéäë àíèìàöèè èëè ðàíäîì
|
|
if states.target_state == states.current_state and states.current_state ~= nil then
|
|
--printf(" select rnd")
|
|
local wpn_slot = self:weapon_slot()
|
|
local state = self.anim_path.animations[self.states.current_state]
|
|
local anim
|
|
if state.rnd ~= nil then
|
|
anim = self:select_rnd(state, wpn_slot, time_global() >= states.next_rnd)
|
|
end
|
|
|
|
-- Åñëè íå âûáðàëè ðàíäîìíóþ, òî èãðàåì àéäë
|
|
if anim == nil and state.idle ~= nil then
|
|
anim = self:anim_for_slot(wpn_slot, state.idle)
|
|
end
|
|
if anim ~= nil then
|
|
states.anim_marker = MARKER_IDLE
|
|
end
|
|
return anim, state
|
|
end
|
|
end
|
|
--' Âîçâðàùàåò òåêóùèé îðóæåéíûé ñëîò
|
|
function animation:weapon_slot()
|
|
local weapon = self.npc:active_item()
|
|
if weapon == nil or self.npc:weapon_strapped() == true then
|
|
return 0
|
|
end
|
|
return weapon:animation_slot()
|
|
end
|
|
--' Âîçâðàùàåò àíèìàöèþ ïîä ïåðåäàííûé îðóæåéíûé ñëîò
|
|
function animation:anim_for_slot(slot, t)
|
|
-- printf("ANIM [%s] for slot [%s]", self.name, tostring(slot))
|
|
-- print_table(t)
|
|
-- printf("-------------------------")
|
|
|
|
if t[slot] == nil then
|
|
slot = 0
|
|
end
|
|
|
|
if t[0] == nil then
|
|
-- print_table(t)
|
|
-- abort("cant find animation for slot %s", tonumber(slot))
|
|
end
|
|
return t[slot]
|
|
end
|
|
-- Âûáîðêà ðàíäîìíîé àíèìàöèè
|
|
function animation:select_rnd(anim_state, wpn_slot, must_play)
|
|
if not must_play and math.random(100) > self.anim_path.animations[self.states.current_state].prop.rnd then
|
|
return nil
|
|
end
|
|
|
|
local anima = self:anim_for_slot(wpn_slot,anim_state.rnd)
|
|
if anima == nil then
|
|
return nil
|
|
end
|
|
|
|
local states = self.states
|
|
local r
|
|
if #anima > 1 then
|
|
if states.last_id == nil then
|
|
r = math.random(#anima)
|
|
else
|
|
r = math.random(#anima-1)
|
|
if r >= states.last_id then
|
|
r = r + 1
|
|
end
|
|
end
|
|
self.states.last_id = r
|
|
else
|
|
r = 1
|
|
end
|
|
return anima[r]
|
|
end
|
|
|
|
|
|
-- Äîáàâëåíèå àíèìàöèè, óñòàíîâêà êîëëáåêà
|
|
function animation:add_anim(anim, state)
|
|
local npc = self.npc
|
|
local animation_props = state.prop
|
|
--printf("[%s][%s] add_anim[%s] time[%s] no_rootmove[%s] %s", self.npc:name(), self.name, tostring(anim), time_global(), tostring(animation_props == nil or animation_props.moving ~= true), device():time_global())
|
|
|
|
if not (npc:weapon_unstrapped() or npc:weapon_strapped()) then
|
|
--callstack()
|
|
abort("Illegal call of add animation. Weapon is strapping now!!! %s", npc:name())
|
|
end
|
|
|
|
|
|
if animation_props == nil or animation_props.moving ~= true then
|
|
npc:add_animation(anim, true, false)
|
|
return
|
|
end
|
|
|
|
-- Åñëè ïîçèöèé/íàïðàâëåíèå àíèìàöèè íå çàäàíû èëè îíè óæå ïðèìåíèëèñü
|
|
if self.mgr.animation_position == nil or self.mgr.pos_direction_applied == true then
|
|
-- Àíèìàöèÿ ñ ïåðåäâèæåíèåì.
|
|
--npc:set_sight(CSightParams.eSightTypeAnimationDirection, false,false)
|
|
-- printf("%s no pos", npc:name())
|
|
npc:add_animation(anim, true, true)
|
|
else
|
|
if self.mgr.animation_direction == nil then
|
|
abort("Animation direction missing")
|
|
end
|
|
|
|
-- Ñþäà ïåðåäàåòñÿ äèðåêøí (åäèíè÷íûé âåêòîð. íóæíî åãî ïåðåâåñòè â âåêòîð ðîòåéøíîâ ïî êîñòÿì)
|
|
local rot_y = -math.deg(math.atan2(self.mgr.animation_direction.x, self.mgr.animation_direction.z))
|
|
|
|
--local rot_y2 = math.deg(math.acos( (v1.x*v2.x + v1.y*v2.y)/math.sqrt((v1.x*v1.x + v1.y*v1.y)*(v2.x*v2.x + v2.y*v2.y)) ))
|
|
|
|
--printf("%s UGOL %s", npc:name(), rot_y)
|
|
-- Íèæåñëåäóþùàÿ ñòðîêà - ýòî êîãäà íóæíî îòûãðàòü àíèìàöèþ â ãëîáàëüíûõ êîîðäèíàòàõ.
|
|
npc:add_animation (anim, true, self.mgr.animation_position, vector():set(0, rot_y, 0), false)
|
|
|
|
self.mgr.pos_direction_applied = true
|
|
end
|
|
end
|
|
|
|
-- Âûçîâ êîëëáåêà, îáû÷íî â ýòîò ìîìåíò íóæåí âûáîð íîâîé àíèìàöèè.
|
|
function animation:animation_callback(skip_multianim_check)
|
|
--printf("[%s][%s] ANIM CALLBACK time[%s] count[%s]", self.npc:name(), self.name, time_global(), self.npc:animation_count())
|
|
if(self.npc:animation_count()~=0) then
|
|
return
|
|
end
|
|
local states = self.states
|
|
|
|
-- 1. Îòûãðàëè INTO àíèìàöèþ
|
|
if states.anim_marker == MARKER_IN then
|
|
states.anim_marker = nil
|
|
-- Åñëè INTO àíèìàöèé íåñêîëüêî
|
|
if skip_multianim_check ~= true then
|
|
local into_table = {}
|
|
local target_anims = self.anim_path.animations[states.target_state]
|
|
if target_anims ~= nil and target_anims.into ~= nil then
|
|
into_table = self:anim_for_slot(self:weapon_slot(), target_anims.into)
|
|
end
|
|
|
|
if into_table ~= nil and #into_table > states.seq_id then
|
|
states.seq_id = states.seq_id + 1
|
|
self:update_anim()
|
|
return
|
|
end
|
|
end
|
|
|
|
states.seq_id = 1
|
|
states.current_state = states.target_state
|
|
self:update_anim()
|
|
return
|
|
end
|
|
|
|
|
|
-- 2. Îòûãðàëè RND èëè IDLE
|
|
if states.anim_marker == MARKER_IDLE then
|
|
states.anim_marker = nil
|
|
local props = self.anim_path.animations[states.current_state].prop
|
|
if props.maxidle == 0 then
|
|
states.next_rnd = time_global() + props.sumidle*1000
|
|
else
|
|
states.next_rnd = time_global() + (props.sumidle + math.random(props.maxidle))*1000
|
|
end
|
|
|
|
|
|
self:update_anim()
|
|
return
|
|
end
|
|
|
|
|
|
-- 3. Îòûãðàëè OUT àíèìàöèþ
|
|
if states.anim_marker == MARKER_OUT then
|
|
states.anim_marker = nil
|
|
if skip_multianim_check ~= true then
|
|
-- Åñëè OUT àíèìàöèé íåñêîëüêî
|
|
local out_table = {}
|
|
if(self.anim_path.animations[states.current_state].out) then
|
|
out_table = self:anim_for_slot(self:weapon_slot(), self.anim_path.animations[states.current_state].out)
|
|
end
|
|
|
|
if out_table ~= nil and #out_table > states.seq_id then
|
|
states.seq_id = states.seq_id + 1
|
|
self:update_anim()
|
|
return
|
|
end
|
|
end
|
|
|
|
states.seq_id = 1
|
|
states.current_state = nil
|
|
|
|
-- Ïåðåäàòü óïðàâëåíèå àíèìñòåéòó.
|
|
if self.name == "state_mgr_animation_list" then
|
|
if self.mgr.animstate ~= nil and self.mgr.animstate.set_control ~= nil then
|
|
self.mgr.animstate:set_control()
|
|
--self.mgr.animstate:update_anim()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
-- Îáðàáîòêà ñïåöäåéñòâèé
|
|
function animation:process_special_action(action_table)
|
|
--printf("[%s] process_special_action", self.npc:name())
|
|
-- Ïðîèçâîäèì äåéñòâèÿ íàõîäÿùèåñÿ íà 1 ïîçèöèè
|
|
-- Àòòà÷ ïðåäìåòà
|
|
if action_table.a ~= nil then
|
|
printf("item [%s] attach", utils.to_str(action_table.a))
|
|
local obj = self.npc:object(action_table.a)
|
|
if obj then
|
|
obj:enable_attachable_item(true)
|
|
end
|
|
end
|
|
-- Äåòà÷ ïðåäìåòà
|
|
if action_table.d ~= nil then
|
|
printf("item [%s] detach", utils.to_str(action_table.d))
|
|
local obj = self.npc:object(action_table.d)
|
|
if obj then
|
|
obj:enable_attachable_item(false)
|
|
end
|
|
end
|
|
-- Îòûãðàòü çâóê
|
|
if action_table.s ~= nil then
|
|
xr_sound.set_sound_play(self.npc:id(), action_table.s)
|
|
end
|
|
-- Íàíåñòè õèò ñåáå
|
|
if action_table.sh ~= nil then
|
|
-- íàíîñèì õèò ñåáå.
|
|
local h = hit()
|
|
h.power = action_table.sh
|
|
h.direction = vector_rotate_y(self.npc:direction(), 90)
|
|
h.draftsman = self.npc
|
|
h.impulse = 200
|
|
h.type = hit.wound
|
|
self.npc:hit(h)
|
|
end
|
|
-- Çàïóñê ëþáîé ôóíêöèè
|
|
if action_table.f ~= nil then
|
|
--printf("called function [%s]", tostring(action_table.f))
|
|
action_table.f(self.npc)
|
|
end
|
|
end
|