----------------------------------------------------------------------------------------------------------------------
--' Ńóěŕńřĺäřčé ďđčäóđîę řâűđ˙ĺňń˙ ăđŕíŕňŕěč
--' ver: 2.0
--' ŕâňîđ: xStream
--' TODO:
----------------------------------------------------------------------------------------------------------------------
gr_types={
[1]="grenade_f1",
[2]="grenade_rgd5"
}
grenades = {}
grenadiers = {}
pseudo_grenades = {}
test_grenades={}
evid_crazy_grenadier=18670
evid_aaa_grenade=evid_crazy_grenadier + 1
actid_crazy_fire_in_the_hole=evid_crazy_grenadier
actid_run_from_grenade=actid_crazy_fire_in_the_hole + 1
grenade_max_dist = 50
grenade_bone = "bip01_head"
snd_grenade_replics={
stalker = {
[[stalker\ready_1]],
[[stalker\ready_2]],
[[stalker\ready_3]],
[[stalker\ready_4]],
[[stalker\ready_5]],
[[stalker\ready_6]],
[[stalker\ready_7]],
[[stalker\ready_8]]
},
military = {
[[voyaki\ready_1]],
[[voyaki\ready_2]],
[[voyaki\ready_3]]
},
bandit = {
[[bandos\ready_1]],
[[bandos\ready_2]],
[[bandos\ready_3]],
[[bandos\ready_4]],
[[bandos\ready_5]],
[[bandos\ready_6]],
[[bandos\ready_7]],
[[bandos\ready_8]],
[[bandos\ready_9]],
[[bandos\ready_10]]
},
monolith = {
[[mono\ready_1]],
[[mono\ready_2]],
[[mono\ready_3]]
},
killer = {
[[merc\ready_1]],
[[merc\ready_2]]
},
dolg = {
[[dolgos\abuse_3]],
[[dolgos\backup_3]],
[[dolgos\panic_monster_2]],
[[dolgos\panic_monster_4]],
[[dolgos\search_8]],
[[dolgos\threat_distant_2]],
[[dolgos\threat_distant_5]]
},
freedom = {
[[freedom\freedom1]],
[[freedom\freedom2]],
[[freedom\freedom3]]
}
}
----------------------------------------------------------------------------------------------------------------------
-- EVALUATORS
----------------------------------------------------------------------------------------------------------------------
class "evaluator_crazy_grenadier" (property_evaluator)
function evaluator_crazy_grenadier:__init(name, storage) super (nil, name)
self.a = storage
self.a.next_check_time = time_global() + math.random(5000,20000)
self.a.throwing = false
self.a.grenades = {}
for k,v in pairs(gr_types) do
self.a.grenades[v] = {}
self.a.grenades[v].radius, self.a.grenades[v].explode_time = get_grenade_radius(v)
end
end
function evaluator_crazy_grenadier:evaluate()
if self.a.throwing then return true end
local npc = self.object
if self.a.testing then
if not self.a.test_grenades.hi or not self.a.test_grenades.lo or
not alife():object(self.a.test_grenades.hi) or not alife():object(self.a.test_grenades.hi) or
not level.object_by_id(self.a.test_grenades.hi) or not level.object_by_id(self.a.test_grenades.lo)
then
self.a.testing = false
self.a.test_running = false
self.a.test_begun = false
self.a.next_check_time = time_global() + 1000
if alife():object(self.a.test_grenades.hi) then alife():release(alife():object(self.a.test_grenades.hi)) end
if alife():object(self.a.test_grenades.lo) then alife():release(alife():object(self.a.test_grenades.lo)) end
test_grenades[self.a.test_grenades.hi]=nil
test_grenades[self.a.test_grenades.lo]=nil
return false
end
if not self.a.test_begun then
self.a.grenades_from_pos = npc:bone_position(grenade_bone)
npc:drop_item_and_teleport(get_grenade(self.a.test_grenades.hi), self.a.grenades_from_pos)
npc:drop_item_and_teleport(get_grenade(self.a.test_grenades.lo), self.a.grenades_from_pos)
self.a.test_begun = true
return false
end
if self.a.test_begun and not self.a.test_running and get_grenade(self.a.test_grenades.hi) and get_grenade(self.a.test_grenades.lo) then
throw(self.a.test_grenades.hi,'hi',self.a.target_point)
--level.map_add_object_spot(self.a.test_grenades.hi, "green_location", 1)
throw(self.a.test_grenades.lo,'lo',self.a.target_point)
--level.map_add_object_spot(self.a.test_grenades.lo, "red_location", 1)
self.a.test_running = true
self.a.test_end_time = time_global() + self.a.grenades[self.a.test_grenades_sect].explode_time
return false
end
if self.a.test_running and self.a.test_end_time<time_global() then
local hi_pos,lo_pos = get_grenade(self.a.test_grenades.hi):position(),get_grenade(self.a.test_grenades.lo):position()
local pos = level.vertex_position(self.a.from_vert)
local radius = self.a.grenades[self.a.test_grenades_sect].radius
local can_throw=false
local hi_d,lo_d = false,false
if hi_pos:distance_to(pos)>radius and hi_pos:distance_to(self.a.target_point)<radius then
hi_d = hi_pos:distance_to(self.a.target_point)
end
if lo_pos:distance_to(pos)>radius and lo_pos:distance_to(self.a.target_point)<radius then
lo_d = lo_pos:distance_to(self.a.target_point)
end
if hi_d then
can_throw=true
self.a.throwing_type="hi"
end
if lo_d and lo_d<(hi_d or 10000) then
can_throw=true
self.a.throwing_type="lo"
end
if can_throw and get_grenade(self.a.grenade) then
self.a.throwing=true
end
alife():release(alife():object(self.a.test_grenades.hi))
alife():release(alife():object(self.a.test_grenades.lo))
test_grenades[self.a.test_grenades.hi]=nil
test_grenades[self.a.test_grenades.lo]=nil
self.a.testing = false
self.a.test_running = false
self.a.test_begun = false
self.a.next_check_time = time_global() + 1000
end
return false
end
if self.a.next_check_time < time_global() then
if npc:body_state()==move.crouch then return false end
self.a.next_check_time = time_global() + 1000
local be = npc:best_enemy()
if not be then return false end
if check_enemy(npc,be) then
local curr_gr = nil
for k,v in pairs(gr_types) do
curr_gr = npc:object(v)
if curr_gr and self:check_grenade(curr_gr:section())==true then
break
end
curr_gr = nil
end
if curr_gr==nil then return false end
--ěîćíî řâűđ˙ňüń˙ - âĺđî˙ňíîńňü íčęîăî íĺ çŕäĺňü (ęđîěĺ âđŕăîâ) äîńňŕňî÷íî âĺëčęŕ
self.a.from_vert = npc:level_vertex_id()
self.a.from_pos = npc:position()
self.a.target_point = be:position():add(vector_rotate_y(be:position():sub(npc:position()),90):normalize():mul(2))
self.a.grenade = curr_gr:id()
local timeout = time_global() + self.a.grenades[get_grenade(self.a.grenade):section()].explode_time
self.a.test_grenades={}
local t
t = alife():create(get_grenade(self.a.grenade):section().."_test", npc:position(), npc:level_vertex_id(), npc:game_vertex_id(), npc:id())
test_grenades[t.id]=timeout+5000
self.a.test_grenades.hi=t.id
t = alife():create(get_grenade(self.a.grenade):section().."_test", npc:position(), npc:level_vertex_id(), npc:game_vertex_id(), npc:id())
test_grenades[t.id]=timeout+5000
self.a.test_grenades.lo=t.id
self.a.test_grenades_sect = get_grenade(self.a.grenade):section()
self.a.test_end_time = timeout
self.a.testing = true
end
end
return false
end
function evaluator_crazy_grenadier:check_grenade(section)
local npc = self.object
local be = npc:best_enemy()
local bp = be:position()
local np = npc:position()
local throw_dist=np:distance_to(bp)
--äŕëĺęî ęčäŕňü íčęŕę, ěű ć íĺ ŕňëĺňű...
if throw_dist>grenade_max_dist then return false end
local throw_dir=be:position():sub(np)
-- ĺńëč íŕęđîĺň âçđűâîě - íĺ áóäĺě ęčäŕňü
if throw_dist<self.a.grenades[section].radius then return false end
--[[
--ňĺďĺđü ďđîâĺđčě, ÷ňîá íĺ çŕäĺňü ńâîčő č íĺéňđŕëîâ
local function check_item(obj)
obj=obj:object()
if obj==nil or obj.clsid==nil then return false end
if not obj:clsid() == clsid.actor and not obj:clsid() == clsid.script_stalker then return false end
if npc:relation(obj) ~= game_object.enemy then
local d=bp:distance_to(obj:position())
if d<self.a.grenades[section].radius then return true end
end
return false
end
for o in npc:memory_visible_objects() do
if check_item(o) then return false end
end
for o in npc:memory_sound_objects() do
if check_item(o) then return false end
end
]]
--ěîćíî čńďîëüçîâŕňü ýňó ăđŕíŕňó....
return true
end
class "evaluator_aaa_grenade" (property_evaluator)
function evaluator_aaa_grenade:__init(name, storage) super (nil, name)
self.a = storage
self.a.throwing = false
self.a.grenades = {}
for k,v in pairs(gr_types) do
self.a.grenades[v] = {}
self.a.grenades[v].radius, self.a.grenades[v].explode_time = get_grenade_radius(v)
end
end
function evaluator_aaa_grenade:evaluate()
local npc = self.object
if self.a.danger_inert and self.a.danger_inert>time_global() then return true end
local danger,danger_r,dist = false,0,1000
for k,v in pairs(grenades) do
if get_grenade(k) and v-1500 > time_global() then
local gdist = get_grenade(k):position():distance_to(npc:position())
if gdist<self.a.grenades[get_grenade(k):section()].radius and gdist<dist then
danger = get_grenade(k):position()
danger_r = self.a.grenades[get_grenade(k):section()].radius
dist=gdist
end
end
end
if danger then
self.a.danger = danger
self.a.danger_r = danger_r
self.a.last_danger_time = time_global()
return true
else
if (self.a.last_danger_time or 0)+1000 > time_global() then
if npc:position():distance_to(self.a.danger)<self.a.danger_r then
self.a.danger_inert = time_global()+1500
return true
end
self.a.danger = nil
self.a.danger_r = nil
self.a.last_danger_time = nil
end
end
return false
end
----------------------------------------------------------------------------------------------------------------------
-- ACTIONS
----------------------------------------------------------------------------------------------------------------------
class "action_fire_in_the_hole" (action_base)
function action_fire_in_the_hole:__init (npc,action_name,storage) super (nil,action_name)
self.a = storage
end
function action_fire_in_the_hole:initialize()
action_base.initialize(self)
self.at_pos = false
self.begin_throw = false
self.throw_end = false
self.time_back_to_pos = time_global()+5000
self.can_explode = false
self.finalized = false
local npc = self.object
xr_sound.set_sound(npc, nil)
stop_play_sound(npc)
end
function action_fire_in_the_hole:execute()
action_base.execute (self)
if self.finalized then return end
if not get_grenade(self.a.grenade) then
self.a.throwing = false
return
end
local npc = self.object
if not self.at_pos then
if time_global()>self.time_back_to_pos then
self.a.throwing = false
return
end
if self.a.from_vert==npc:level_vertex_id() and self.a.from_pos:distance_to(npc:position())<0.3 then
local en_inj,fr_inj = false,false
local r = self.a.grenades[get_grenade(self.a.grenade):section()].radius
for a=0,65535 do
local obj = level.object_by_id(a)
if obj and obj.clsid and obj:alive() then
local od=self.a.target_point:distance_to(obj:position())
if od<r then
if obj:clsid() == clsid.actor or obj:clsid() == clsid.script_stalker then
if npc:relation(obj) == game_object.enemy then
en_inj=true
else
if od<r/2 then
fr_inj=true
break
end
end
elseif IsMonster(alife():object(a)) then
en_inj=true
end
end
end
end
if fr_inj or not en_inj then
self.a.grenade = nil
self.a.throwing = false
self.a.target_point = nil
self.finalized = true
return
end
npc:set_item(object.idle,nil)
npc:set_movement_type(move.stand)
npc:set_mental_state(anim.danger)
npc:set_body_state(move.standing)
npc:movement_enabled(true)
local snd_sect = snd_grenade_replics[npc:character_community()] or snd_grenade_replics.stalker
local snd = [[grenadier\]]..snd_sect[math.random(table.getn(snd_sect))]
snd = xr_sound.get_safe_sound_object(snd)
snd:play_no_feedback(npc, sound_object.s3d, 0, npc:position(), 1.0)
self.start_time = time_global()
self.throw_time = self.start_time + 1000
self.end_time = self.throw_time + 300
grenadiers[npc:id()]=self.a.grenade
self.at_pos = true
return
end
utils.send_to_nearest_accessible_vertex(npc, self.a.from_vert)
npc:set_movement_type(move.run)
npc:set_body_state(move.standing)
npc:set_desired_position(self.a.from_pos)
npc:clear_animations()
local be = npc:best_enemy()
if be and npc:see(be) then
npc:set_sight(look.point,be:position())
npc:set_desired_direction(be:position():sub(npc:position()))
end
return
end
npc:set_sight(look.point,self.a.target_point)
npc:set_desired_direction(utils.vector_copy_by_val(self.a.target_point):sub(npc:position()))
if time_global() > self.throw_time and not self.begin_throw then
self.begin_throw=true
npc:clear_animations()
if self.a.throwing_type == 'lo' then
npc:add_animation("udar_0")
else
npc:add_animation("norm_all_6_attack_2")
end
return
end
if time_global() > self.end_time and not self.can_explode then
npc:drop_item_and_teleport(get_grenade(self.a.grenade), self.a.grenades_from_pos)
grenadiers[npc:id()]=nil
self.can_explode=time_global()
return
end
if self.can_explode then
throw(self.a.grenade,self.a.throwing_type,self.a.target_point)
level.map_add_object_spot(self.a.grenade, "grenade_location", get_grenade(self.a.grenade):section())
local timeout = self.a.grenades[get_grenade(self.a.grenade):section()].explode_time-(time_global()-self.can_explode)
grenades[get_grenade(self.a.grenade):id()] = time_global() + timeout
self.a.grenade = nil
self.a.next_check_time = time_global() + math.random(10000,60000)
self.a.throwing = false
self.a.target_point = nil
self.finalized = true
end
end
class "action_run_from_grenade" (action_base)
function action_run_from_grenade:__init (npc,action_name,storage) super (nil,action_name)
self.a = storage
end
function action_run_from_grenade:initialize()
action_base.initialize(self)
local npc=self.object
xr_sound.set_sound(npc, nil)
stop_play_sound(npc)
end
function action_run_from_grenade:execute()
action_base.execute (self)
local npc=self.object
npc:clear_animations()
if npc:animation_count()>0 then return end
npc:clear_animations()
npc:set_movement_type(move.run)
npc:set_body_state(move.standing)
npc:movement_enabled(true)
if npc:position():distance_to(self.a.danger)<self.a.danger_r/2 then
npc:set_mental_state(anim.panic)
else
npc:set_mental_state(anim.danger)
end
local best_dist,best_dir = 0,vector():set(0,0,0)
local dir = npc:position():sub(self.a.danger):normalize()
local dvert=npc:level_vertex_id()
for a=-120,120,10 do
local ndir = vector_rotate_y(dir,a)
local vert = level.vertex_in_direction(npc:level_vertex_id(),ndir,50)
local ndist = level.vertex_position(vert):distance_to(self.a.danger)
if ndist>best_dist then
best_dist=ndist
dvert = vert
end
end
local be = npc:best_enemy()
if be and npc:see(be) and npc:position():distance_to(self.a.danger)>self.a.danger_r/2 then
npc:set_sight(look.point,be:position())
end
utils.send_to_nearest_accessible_vertex(npc, dvert)
end
function action_run_from_grenade:finalize()
action_base.finalize (self)
end
----------------------------------------------------------------------------------------------------------------------
-- BINDER
----------------------------------------------------------------------------------------------------------------------
function add_to_binder(object, ini, scheme, section, storage)
local operators = {}
local properties = {}
local manager = object:motivation_action_manager()
operators["fire_in_the_hole"] = actid_crazy_fire_in_the_hole
operators["run_from_grenade"] = actid_run_from_grenade
properties["crazy_grenadier"] = evid_crazy_grenadier
properties["aaa_grenade"] = evid_aaa_grenade
local zombi=object:character_community()=="ecolog" or object:character_community()=="zombied" or object:character_community()=="trader" or
object:character_community()=="arena_enemy" or object:name()=="mil_stalker0012" or object:name()=="yantar_ecolog_general"
if zombi then
manager:add_evaluator (properties["crazy_grenadier"], property_evaluator_const(false))
manager:add_evaluator (properties["aaa_grenade"], property_evaluator_const(false))
else
manager:add_evaluator (properties["crazy_grenadier"], evaluator_crazy_grenadier("crazy_grenadier", storage))
manager:add_evaluator (properties["aaa_grenade"], evaluator_aaa_grenade("aaa_grenade", storage))
end
local action = action_fire_in_the_hole (object,"fire_in_the_hole", storage)
action:add_precondition(world_property(stalker_ids.property_alive, true))
action:add_precondition(world_property(xr_evaluators_id.sidor_wounded_base, false))
action:add_precondition (world_property(properties["aaa_grenade"], false))
action:add_precondition (world_property(properties["crazy_grenadier"], true))
action:add_effect (world_property(properties["crazy_grenadier"], false))
manager:add_action (operators["fire_in_the_hole"], action)
local action = action_run_from_grenade (object,"run_from_grenade", storage)
action:add_precondition(world_property(stalker_ids.property_alive, true))
action:add_precondition(world_property(xr_evaluators_id.sidor_wounded_base, false))
action:add_precondition (world_property(properties["crazy_grenadier"], false))
action:add_precondition (world_property(properties["aaa_grenade"], true))
action:add_effect (world_property(properties["aaa_grenade"], false))
manager:add_action (operators["run_from_grenade"], action)
action = manager:action (xr_actions_id.alife)
action:add_precondition (world_property(properties["crazy_grenadier"], false))
action:add_precondition (world_property(properties["aaa_grenade"], false))
action = manager:action (stalker_ids.action_combat_planner)
action:add_precondition (world_property(properties["crazy_grenadier"], false))
action:add_precondition (world_property(properties["aaa_grenade"], false))
action = manager:action (stalker_ids.action_danger_planner)
action:add_precondition (world_property(properties["crazy_grenadier"], false))
action:add_precondition (world_property(properties["aaa_grenade"], false))
end
function set_scheme(npc, ini, scheme, section)
local st = xr_logic.assign_storage_and_bind(npc, ini, scheme, section)
end
function disable_scheme(npc, scheme)
local st = db.storage[npc:id()][scheme]
if st then
st.enabled = false
end
end
----------------------------------------------------------------------------------------------------------------------
-- HELPERS
----------------------------------------------------------------------------------------------------------------------
function get_grenade(id)
return level.object_by_id(id)
end
function get_grenade_radius(section)
local r,t = 1000,0
local ini = system_ini()
local br = utils.cfg_get_number(ini, section, "blast_r", false, false, false, 1000)
local fr = utils.cfg_get_number(ini, section, "frags_r", false, false, false, 1000)
t = utils.cfg_get_number(ini, section, "destroy_time", false, false, false, 0)
r = math.max(br,fr)
return r,t
end
function update(delta)
for k,v in pairs(pseudo_grenades) do
local sobj = alife():object(k)
if sobj then
local obj = level.object_by_id(k)
if obj then
obj:explode(0)
pseudo_grenades[k]=nil
end
else
pseudo_grenades[k]=nil
end
end
for k,v in pairs(grenades) do
local sobj = alife():object(k)
if sobj then
if time_global()>v then
local obj = level.object_by_id(k)
if obj then
local a = alife():create(obj:section().."_fake",obj:position():add(vector():set(0,1,0)),obj:level_vertex_id(),obj:game_vertex_id())
if a then
pseudo_grenades[a.id]=true
end
end
alife():release(sobj)
grenades[k]=nil
end
else
grenades[k]=nil
end
end
for k,v in pairs(test_grenades) do
local sobj = alife():object(k)
if sobj then
if time_global()>v then
alife():release(sobj)
test_grenades[k]=nil
end
else
test_grenades[k]=nil
end
end
end
function death_callback(npc)
if grenadiers[npc:id()] then
local grenade = grenadiers[npc:id()]
local dummy,timeout = get_grenade_radius(get_grenade(grenade):section())
grenade = alife():create(get_grenade(grenade):section(), npc:bone_position(grenade_bone), npc:level_vertex_id(), npc:game_vertex_id())
grenades[grenade.id] = time_global() + timeout
grenadiers[npc:id()]=nil
end
local remove_grenades={}
npc:iterate_inventory(function (dummy, item)
if item==nil or alife():object(item:id())==nil then return end
for k,v in pairs(gr_types) do
if item:section()==v then
table.insert(remove_grenades, item:id())
break
end
end
end, npc)
for k,v in pairs(remove_grenades) do
alife():release(alife():object(v),true)
end
end
function check_enemy(npc,be)
return npc:alive() and be and (
be:clsid() == clsid.script_stalker or
be:clsid() == clsid.actor or
be:clsid() == clsid.bloodsucker_s or
be:clsid() == clsid.burer_s or
be:clsid() == clsid.controller_s or
be:clsid() == clsid.poltergeist_s or
be:clsid() == clsid.gigant_s or
be:clsid() == clsid.zombie_s
) and be:alive() and npc:see(be) and be:position():distance_to(level.vertex_position(be:level_vertex_id()))<2 --čç-çŕ ăëţęîâ äâčćęŕ ęčäŕňü áóäĺě ňîëüęî â îáúĺęňű, íĺäŕëĺęî îň ŕč ńĺňęč
end
function npc_update(binder)
local npc = binder.object
if not npc:alive() then return end
if not binder.grenade_update_time then binder.grenade_update_time=time_global()+15000 end
if npc:character_community()=="ecolog" or npc:character_community()=="zombied" or npc:character_community()=="trader" or
npc:character_community()=="arena_enemy" or npc:name()=="mil_stalker0012" or
npc:name()=="yantar_ecolog_general" then return end
if time_global()>binder.grenade_update_time then
for k,v in pairs(gr_types) do
local curr_gr = npc:object(v)
if not curr_gr then
local sobj = alife():object(npc:id())
if sobj and sobj.rank and sobj:rank()~=0 then
local prb = sobj:rank()/2500
if prb>0.9 then prb=0.9 end
if prb<0.01 then prb=0.01 end
if v=="grenade_f1" then prb=prb/2 end
if math.random()<prb then alife():create(v,npc:position(),npc:level_vertex_id(),npc:game_vertex_id(),npc:id()) end
end
else
break
end
end
binder.grenade_update_time=time_global()+180000
end
end
function throw(id,typ,target)
if not get_grenade(id):get_physics_shell() then return end
local bone = get_grenade(id):get_physics_shell():get_element_by_bone_name("wpn_body")
local dir=utils.vector_copy_by_val(target):sub(get_grenade(id):position())
dir:mul(1300)
if typ=="lo" then
dir:add(vector():set(0,8000,0))
else
dir:add(vector():set(0,19000,0))
end
if bone then bone:apply_force(dir.x,dir.y,dir.z) end
end
function net_spawn()
for a=0,65534 do
local sobj = alife():object(a)
if sobj then
for k,v in pairs(gr_types) do
if sobj:section_name()==v.."_test" or sobj:section_name()==v.."_fake" then
alife():release(sobj)
break
end
end
end
end
end
function fake_pickup(obj)
level.map_remove_object_spot(obj:id(), "grenade_location")
for k,v in pairs(gr_types) do
if obj:section()==v.."_test" or obj:section()==v.."_fake" then
alife():release(alife():object(obj:id()))
return
end
end
end
[error]Expression : assertion failed
[error]Function : CInventory::DropItem
[error]File : E:\stalker\sources\trunk\xr_3da\xrGame\Inventory.cpp
[error]Line : 220
[error]Description : InSlot(pIItem)
Użytkownicy przeglądający to forum: Brak zarejestrowanych użytkowników oraz 1 gość