875 lines
21 KiB
Plaintext
875 lines
21 KiB
Plaintext
function init()
|
||
rank_unit = 1/ranks.get_rank_interval(get_rank_list()[#get_rank_list()])[1]
|
||
init_clsid()
|
||
end
|
||
--------------------------------------ini---------------------------------------
|
||
local sys_ini = system_ini()
|
||
function read_from_ini(ini,sec,lin,def,typ)
|
||
if not (sec and lin) then
|
||
ABORT("read_from_ini: ini [%s] sec [%s] lin [%s] def [%s] typ [%s]",ini~=nil,sec,lin,def,typ)
|
||
end
|
||
if not ini then
|
||
ini = sys_ini
|
||
end
|
||
if ini:line_exist(sec,lin) then
|
||
if typ == 1 then
|
||
return ini:r_string(sec,lin) or def
|
||
elseif typ == nil then
|
||
return ini:r_float(sec,lin) or def
|
||
elseif typ == 0 then
|
||
local r = ini:r_bool(sec,lin)
|
||
return r == nil and def or r
|
||
elseif typ == 2 then
|
||
return ini:r_string_wq(sec,lin) or def
|
||
elseif typ == 3 then
|
||
return ini:r_s32(sec,lin) or def
|
||
elseif typ == 4 then
|
||
return ini:r_vector(sec,lin) or def
|
||
end
|
||
end
|
||
return def
|
||
end
|
||
|
||
function collect_sections(ini,sections,vfunc,dval,convert)
|
||
if vfunc == true then
|
||
vfunc = tonumber
|
||
end
|
||
local r,p,c = {},{},{}
|
||
for k,v in ipairs(sections) do
|
||
if ini:section_exist(v) then
|
||
local n = ini:line_count(v)
|
||
if n > 0 then
|
||
for i = 0,n-1 do
|
||
local res,id,val = ini:r_line(v,i,"","")
|
||
if r[id] == nil then
|
||
r[id] = dval or vfunc and vfunc(val) or val
|
||
if convert ~= nil then
|
||
table.insert(c,convert == false and r[id] or id)
|
||
end
|
||
end
|
||
end
|
||
end
|
||
p[k] = n
|
||
else
|
||
p[k] = 0
|
||
end
|
||
end
|
||
if convert ~= nil then
|
||
return c,r
|
||
end
|
||
return r,p
|
||
end
|
||
|
||
function parse_list(ini,sec,val,convert,vfunc)
|
||
local tmp = str_explode(",",read_from_ini(ini,sec,val,"",1))
|
||
if vfunc then
|
||
if vfunc == true then
|
||
vfunc = tonumber
|
||
end
|
||
for i,v in ipairs(tmp) do
|
||
local res = vfunc(v)
|
||
if res ~= nil then
|
||
tmp[i] = res
|
||
end
|
||
end
|
||
end
|
||
if convert then
|
||
local swap,func = convert == -1,type(convert) == "function"
|
||
local t = {}
|
||
for i,v in ipairs(tmp) do
|
||
t[v] = swap and i or func and convert(v,i) or convert
|
||
end
|
||
return t,tmp
|
||
end
|
||
return tmp
|
||
end
|
||
|
||
local ranksl
|
||
function get_rank_list()
|
||
if ranksl then
|
||
return ranksl
|
||
end
|
||
local tmp = parse_list(nil,"game_relations","rating")
|
||
ranksl = {}
|
||
for i,rn in ipairs(tmp) do
|
||
if not tonumber(rn) then
|
||
table.insert(ranksl,rn)
|
||
end
|
||
end
|
||
return ranksl
|
||
end
|
||
|
||
local communitiesl
|
||
function get_communities_list()
|
||
if communitiesl then
|
||
return communitiesl
|
||
end
|
||
local tmp = parse_list(nil,"game_relations","communities")
|
||
communitiesl = {}
|
||
for i,cn in ipairs(tmp) do
|
||
if not tonumber(cn) then
|
||
table.insert(communitiesl,cn)
|
||
end
|
||
end
|
||
return communitiesl
|
||
end
|
||
|
||
rank_unit = 0.01
|
||
--------------------------------------str---------------------------------------
|
||
function trim(s)
|
||
return (string.gsub(s,"^%s*(.-)%s*$","%1"))
|
||
end
|
||
|
||
function str_explode(div,str)
|
||
local t = {}
|
||
for sect in str:gmatch('[^%s*%'..div..']+') do
|
||
if sect and sect ~= "" then
|
||
table.insert(t, sect)
|
||
end
|
||
end
|
||
return t
|
||
end
|
||
|
||
function vec_to_str(vec)
|
||
if vec == nil then return "<nil>" end
|
||
return string.format("[%s:%s:%s]",vec.x,vec.y,vec.z)
|
||
end
|
||
|
||
local function format_safe(str,...)
|
||
local i,args = 0,{...}
|
||
local f = function()
|
||
i = i + 1
|
||
local a = args[i]
|
||
if a == nil then
|
||
return "<nil>"
|
||
elseif type(a) == "userdata" then
|
||
if a.setHP then
|
||
return vec_to_str(a)
|
||
elseif a.name then
|
||
return "<obj>:"..a:name()
|
||
end
|
||
return "<userdata>"
|
||
end
|
||
return tostring(a)
|
||
end
|
||
return string.gsub(str,"%%s",f)
|
||
end
|
||
|
||
----------------------------------------------------------------------------------
|
||
function count_table(t)
|
||
local cnt = 0
|
||
for k,v in pairs(t) do
|
||
cnt = cnt+1
|
||
end
|
||
return cnt
|
||
end
|
||
|
||
function transform_tiny(m,v)
|
||
local res = vector()
|
||
res.x = m.i.x * v.x + m.k.x * v.z + m.j.x * v.y + m.c.x;
|
||
res.y = m.k.y * v.z + m.j.y * v.y + m.i.y * v.x + m.c.y;
|
||
res.z = m.k.z * v.z + m.j.z * v.y + m.i.z * v.x + m.c.z;
|
||
return res
|
||
end
|
||
|
||
function random_choice(...)
|
||
local args = {...}
|
||
if #args == 1 then
|
||
return args[1][math.random(#args[1])]
|
||
end
|
||
return args[math.random(#args)]
|
||
end
|
||
|
||
--------------------------------------class---------------------------------------
|
||
actor_clsid = clsid.script_actor
|
||
|
||
creatures_clslist = {
|
||
actor = actor_clsid,
|
||
stalker = clsid.script_stalker,
|
||
dog = clsid.dog_s,
|
||
boar = clsid.boar_s,
|
||
flesh = clsid.flesh_s,
|
||
pseudodog = clsid.pseudodog_s,
|
||
bloodsucker = clsid.bloodsucker_s,
|
||
snork = clsid.snork_s,
|
||
tushkano = clsid.tushkano_s,
|
||
zombie = clsid.zombie_s,
|
||
giant = clsid.gigant_s,
|
||
chimera = clsid.chimera_s,
|
||
burer = clsid.burer_s,
|
||
controller = clsid.controller_s,
|
||
poltergeist = clsid.poltergeist_s,
|
||
fracture = clsid.fracture_s,
|
||
cat = clsid.cat_s,
|
||
psy_dog = clsid.psy_dog_s,
|
||
psy_dog_phantom = clsid.psy_dog_phantom_s
|
||
}
|
||
|
||
local firearm_clst
|
||
function item_is_fa(o,c)
|
||
if not c then
|
||
c = o and o:clsid()
|
||
end
|
||
if c and firearm_clst[c] then
|
||
return true
|
||
end
|
||
return false
|
||
end
|
||
|
||
local knife_cls
|
||
function item_is_knife(o,c)
|
||
if not c then
|
||
c = o and o:clsid()
|
||
end
|
||
return c == knife_cls
|
||
end
|
||
|
||
local grenade_clst
|
||
function item_is_grenade(o,c)
|
||
if not c then
|
||
c = o and o:clsid()
|
||
end
|
||
if c and grenade_clst[c] then
|
||
return true
|
||
end
|
||
return false
|
||
end
|
||
|
||
local blaster_clst
|
||
function item_is_blaster(o,c)
|
||
if not c then
|
||
c = o and o:clsid()
|
||
end
|
||
if c and blaster_clst[c] then
|
||
return true
|
||
end
|
||
return false
|
||
end
|
||
|
||
local ammo_clst
|
||
function item_is_ammo(o,c)
|
||
if not c then
|
||
c = o and o:clsid()
|
||
end
|
||
if c and ammo_clst[c] then
|
||
return true
|
||
end
|
||
return false
|
||
end
|
||
|
||
function is_actor(o,c)
|
||
if not c then
|
||
c = o and o:clsid()
|
||
end
|
||
return c == actor_clsid
|
||
end
|
||
|
||
local anom_clst
|
||
function is_anomaly(o,c)
|
||
if not c then
|
||
c = o and o:clsid()
|
||
end
|
||
if c and anom_clst[c] then
|
||
return true
|
||
end
|
||
return false
|
||
end
|
||
|
||
function is_story_object(game_obj)
|
||
return game_obj:story_id() < 4294967296
|
||
end
|
||
|
||
function init_clsid()
|
||
firearm_clst = {
|
||
[clsid.wpn_pm_s] = true,
|
||
[clsid.wpn_walther_s] = true,
|
||
[clsid.wpn_usp45_s] = true,
|
||
[clsid.wpn_hpsa_s] = true,
|
||
[clsid.wpn_bm16_s] = true,
|
||
[clsid.wpn_shotgun_s] = true,
|
||
[clsid.wpn_ak74_s] = true,
|
||
[clsid.wpn_lr300_s] = true,
|
||
[clsid.wpn_groza_s] = true,
|
||
[clsid.wpn_val_s] = true,
|
||
[clsid.wpn_vintorez_s] = true,
|
||
[clsid.wpn_svu_s] = true,
|
||
[clsid.wpn_svd_s] = true,
|
||
[clsid.wpn_rg6_s] = true,
|
||
[clsid.wpn_rpg7_s] = true,
|
||
-- [clsid.wpn_knife_s] = true,
|
||
}
|
||
blaster_clst = {
|
||
[clsid.wpn_rg6_s] = true,
|
||
[clsid.wpn_rpg7_s] = true
|
||
}
|
||
grenade_clst = {
|
||
[clsid.wpn_grenade_f1] = true,
|
||
[clsid.wpn_grenade_rgd5] = true
|
||
}
|
||
ammo_clst = {
|
||
[clsid.wpn_ammo] = true,
|
||
[clsid.wpn_ammo_vog25] = true,
|
||
[clsid.wpn_ammo_m209] = true,
|
||
[clsid.wpn_ammo_og7b] = true
|
||
}
|
||
anom_clst = {
|
||
-- [clsid.ameba_zone] = true,
|
||
[clsid.torrid_zone] = true,
|
||
[clsid.zone_acid_fog] = true,
|
||
[clsid.zone_bfuzz] = true,
|
||
[clsid.zone_bfuzz_s] = true,
|
||
[clsid.zone_dead] = true,
|
||
[clsid.zone_galant_s] = true,
|
||
[clsid.zone_galantine] = true,
|
||
[clsid.zone_mbald_s] = true,
|
||
[clsid.zone_mincer] = true,
|
||
[clsid.zone_mincer_s] = true,
|
||
[clsid.zone_mosquito_bald] = true,
|
||
-- [clsid.zone_radioactive] = true,
|
||
[clsid.zone_rusty_hair] = true,
|
||
-- [clsid.zone_torrid_s] = true
|
||
}
|
||
knife_cls = clsid.wpn_knife_s
|
||
end
|
||
--------------------------------------sch---------------------------------------
|
||
function add_anim(npc,anim,hand_usage,use_movement_controller)
|
||
if anim then
|
||
npc:add_animation(anim,hand_usage==true,use_movement_controller==true)
|
||
end
|
||
end
|
||
|
||
function get_sound(snd)
|
||
if snd then
|
||
return sound_object(snd)
|
||
end
|
||
end
|
||
--------------------------------------net------------------------------------------
|
||
local stpk = net_packet()
|
||
local nph,npt -- <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
|
||
function get_weapon_data(sobj)
|
||
if not sobj then
|
||
return {}
|
||
end
|
||
if time_global() == npt then
|
||
if nph[sobj] then
|
||
return nph[sobj]
|
||
end
|
||
else
|
||
nph = {}
|
||
npt = time_global()
|
||
end
|
||
stpk:w_begin(0)
|
||
sobj:STATE_Write(stpk)
|
||
local size = stpk:w_tell()
|
||
stpk:r_seek(2)
|
||
local t = {}
|
||
parse_object_packet(t,stpk)
|
||
parse_visual_packet(t,stpk)
|
||
parse_item_packet(t,stpk)
|
||
parse_item_weapon_packet(t,stpk)
|
||
nph[sobj] = t
|
||
return t
|
||
end
|
||
|
||
function parse_object_packet(ret,stpk)
|
||
ret.gvid = stpk:r_u16()
|
||
ret.obf32u1 = stpk:r_float()
|
||
ret.obs32u2 = stpk:r_s32()
|
||
ret.lvid = stpk:r_s32()
|
||
ret.oflags = stpk:r_s32()
|
||
ret.custom = stpk:r_stringZ()
|
||
ret.sid = stpk:r_s32()
|
||
ret.obs32u3 = stpk:r_s32()
|
||
return ret
|
||
end
|
||
|
||
function parse_visual_packet(ret,stpk)
|
||
ret.visual = stpk:r_stringZ()
|
||
ret.vsu8u1 = stpk:r_u8()
|
||
return ret
|
||
end
|
||
|
||
function parse_item_packet(ret,stpk)
|
||
ret.condition = stpk:r_float()
|
||
ret.upgrades = readvu32stringZ(stpk)
|
||
return ret
|
||
end
|
||
|
||
function parse_item_weapon_packet(ret,stpk)
|
||
ret.ammo_current = stpk:r_u16()
|
||
ret.ammo_elapsed = stpk:r_u16()
|
||
ret.weapon_state = stpk:r_u8()
|
||
ret.addon_flags = stpk:r_u8()
|
||
ret.ammo_type = stpk:r_u8()
|
||
ret.xz1 = stpk:r_u8()
|
||
return ret
|
||
end
|
||
|
||
function readvu8uN(packet,n)
|
||
local v = {}
|
||
for i=1,n,1 do
|
||
table.insert(v,packet:r_u8())
|
||
end
|
||
return v
|
||
end
|
||
|
||
function set_weapon_data(t,sobj)
|
||
if sobj then
|
||
stpk:w_begin(0)
|
||
fill_object_packet(t,stpk)
|
||
fill_visual_packet(t,stpk)
|
||
fill_item_packet(t,stpk)
|
||
fill_item_weapon_packet(t,stpk)
|
||
local size = stpk:w_tell()
|
||
stpk:r_seek(2)
|
||
sobj:STATE_Read(stpk,size)
|
||
end
|
||
end
|
||
|
||
function fill_object_packet(ret,stpk)
|
||
stpk:w_u16(ret.gvid)
|
||
stpk:w_float(ret.obf32u1)
|
||
stpk:w_s32(ret.obs32u2)
|
||
stpk:w_s32(ret.lvid)
|
||
stpk:w_s32(ret.oflags)
|
||
stpk:w_stringZ(ret.custom)
|
||
stpk:w_s32(ret.sid)
|
||
stpk:w_s32(ret.obs32u3)
|
||
end
|
||
|
||
function fill_visual_packet(ret,stpk)
|
||
stpk:w_stringZ(ret.visual)
|
||
stpk:w_u8(ret.vsu8u1)
|
||
end
|
||
|
||
function fill_item_packet(ret,stpk)
|
||
stpk:w_float(ret.condition)
|
||
writevu32stringZ(stpk,ret.upgrades)
|
||
return ret
|
||
end
|
||
|
||
function fill_item_weapon_packet(ret,stpk)
|
||
stpk:w_u16(ret.ammo_current)
|
||
stpk:w_u16(ret.ammo_elapsed)
|
||
stpk:w_u8(ret.weapon_state)
|
||
stpk:w_u8(ret.addon_flags)
|
||
stpk:w_u8(ret.ammo_type)
|
||
stpk:w_u8(ret.xz1)
|
||
return ret
|
||
end
|
||
|
||
function writevu8uN(pk,v)
|
||
local len = table.getn(v)
|
||
for i=1,len,1 do
|
||
pk:w_u8(v[i])
|
||
end
|
||
end
|
||
|
||
function readvu32stringZ(packet)
|
||
local v = {}
|
||
local len = packet:r_s32()
|
||
for i=1,len,1 do
|
||
table.insert(v,packet:r_stringZ())
|
||
end
|
||
return v
|
||
end
|
||
|
||
function writevu32stringZ(pk,v)
|
||
if v == nil then
|
||
v = {}
|
||
end
|
||
local len = #v
|
||
pk:w_s32(len)
|
||
for i=1,len,1 do
|
||
pk:w_stringZ(v[i])
|
||
end
|
||
end
|
||
|
||
--------------------------------------weapon---------------------------------------
|
||
|
||
game_object.get_wm = function (npc,enabled_only)
|
||
local wm = rx_ai.get_storage(npc:id()).wm
|
||
if wm and not (enabled_only and wm.disabled) then
|
||
return wm
|
||
end
|
||
end
|
||
|
||
function get_weapon(npc)
|
||
local wm = rx_ai.get_storage(npc:id()).wm
|
||
return wm and wm:get_weapon() or npc:best_weapon()
|
||
end
|
||
|
||
function get_ammo_type(wpn,id)
|
||
return get_weapon_data(alife():object(id or wpn:id())).ammo_type or 0
|
||
end
|
||
--[[
|
||
function in_grenade_mode(wpn)
|
||
local pak = get_weapon_w_gl_full_data(alife():object(wpn:id()))
|
||
if bit_and(pak.addon_flags,2) == 2 then
|
||
return pak.updgrenade_mode ~= 0
|
||
end
|
||
return false
|
||
end]]
|
||
|
||
EWeaponStates = {
|
||
eFire = 5,
|
||
eFire2 = 6,
|
||
eReload = 7,
|
||
eMisfire = 8,
|
||
eMagEmpty = 9,
|
||
eSwitch = 10
|
||
}
|
||
function get_weapon_state(wpn,id)
|
||
return get_weapon_data(alife():object(id or wpn:id())).weapon_state
|
||
end
|
||
|
||
function get_mag_size(section)
|
||
return (rx_wmgr and not rx_wmgr.wm_modes.forbiddens[section] and rx_wmgr.read_wpn_params(section).mag) or read_from_ini(nil,section,"ammo_mag_size",1,3)
|
||
end
|
||
|
||
function get_wpn_type(section)
|
||
return (rx_wmgr and not rx_wmgr.wm_modes.forbiddens[section] and rx_wmgr.read_wpn_params(section).typ) or read_from_ini(nil,section,"ef_weapon_type",0,3)
|
||
end
|
||
|
||
--------------------------------------addons---------------------------------------
|
||
function get_addon_status(wpn,addon)
|
||
if addon == "sc" then
|
||
return wpn:weapon_scope_status()
|
||
elseif addon == "sl" then
|
||
return wpn:weapon_silencer_status()
|
||
elseif addon == "gl" then
|
||
return wpn:weapon_grenadelauncher_status()
|
||
end
|
||
return 0
|
||
end
|
||
|
||
function get_addon_flag(wpn,with_int)
|
||
local flag = 0
|
||
if wpn:weapon_is_scope() then
|
||
if with_int or get_addon_status(wpn,"sc") == 2 then
|
||
flag = 1
|
||
end
|
||
end
|
||
if wpn:weapon_is_silencer() then
|
||
if with_int or get_addon_status(wpn,"sl") == 2 then
|
||
flag = flag+4
|
||
end
|
||
end
|
||
if wpn:weapon_is_grenadelauncher() then
|
||
if with_int or get_addon_status(wpn,"gl") == 2 then
|
||
flag = flag+2
|
||
end
|
||
end
|
||
return flag
|
||
end
|
||
|
||
local ft = {sc = 1,sl = 4,gl = 2}
|
||
function addon_attached(wpn,addon,flag)
|
||
if ft[addon] then
|
||
return bit_and(flag or get_addon_flag(wpn,true),ft[addon]) == ft[addon]
|
||
end
|
||
end
|
||
|
||
--------------------------------------ai-----------------------------------------
|
||
function cover_in_direction(lvid,dir,bs)
|
||
if bs == move.crouch then
|
||
return level.low_cover_in_direction(lvid,dir)
|
||
else
|
||
return level.high_cover_in_direction(lvid,dir)
|
||
end
|
||
end
|
||
|
||
function npc_in_cover(npc,stand)
|
||
local st = rx_ai.get_storage(npc:id(),"in_cover")
|
||
local be,de = npc:best_enemy(),db.storage[npc:id()].danger_flag
|
||
if (be and not xr_wounded.is_wounded(be) or de) then
|
||
if stand and not npc:path_completed() then
|
||
st.evn = false
|
||
return false
|
||
end
|
||
else
|
||
return true
|
||
end
|
||
local tg = time_global()
|
||
if (st.wait or 0) > tg then
|
||
return st.evn
|
||
end
|
||
local enemies,tt = {},{}
|
||
if be and not xr_wounded.is_wounded(be) then
|
||
enemies[1] = be
|
||
tt[be:id()] = true
|
||
else -- <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
if not be and de and npc:best_danger() then
|
||
local bd = npc:best_danger()
|
||
local dir = bd:position():sub(npc:position())
|
||
if dir:magnitude() < (bd:type() == danger_object.grenade and 20 or 8) or 1-cover_in_direction(npc:level_vertex_id(),dir,npc:body_state()) < 0.3 then
|
||
st.evn = false
|
||
st.wait = tg+3000
|
||
return false
|
||
end
|
||
end
|
||
st.evn = true
|
||
st.wait = tg+2000
|
||
return true
|
||
end
|
||
for o in npc:memory_visible_objects() do
|
||
local obj = o:object()
|
||
if obj then
|
||
local id = obj:id()
|
||
if not tt[id] and obj:alive() and npc:relation(obj) == game_object.enemy and (IsStalker(obj) and not xr_wounded.is_wounded(obj) or IsMonster(obj)) then
|
||
table.insert(enemies,obj)
|
||
tt[id] = true
|
||
end
|
||
end
|
||
end
|
||
for o in npc:memory_sound_objects() do
|
||
local obj = o:object()
|
||
if obj and obj:alive() and not tt[obj:id()] and npc:relation(obj) == game_object.enemy and (IsStalker(obj) and not xr_wounded.is_wounded(obj) or IsMonster(obj)) then
|
||
table.insert(enemies,obj)
|
||
end
|
||
end
|
||
local npc_lvid,npc_id,bs = npc:level_vertex_id(),npc:id(),npc:body_state()
|
||
local f = 28
|
||
for i,enemy in ipairs(enemies) do
|
||
if IsMonster(enemy) then
|
||
local dist = enemy:position():distance_to_sqr(npc:position())
|
||
local ebe = enemy:get_enemy()
|
||
if (dist < 12*12 and enemy:see(npc)) or (dist < 50*50 and ebe and ebe:id() == npc_id) then
|
||
st.evn = false
|
||
st.wait = tg+5000
|
||
return false
|
||
end
|
||
else
|
||
local dir = enemy:position():sub(npc:position())
|
||
local dist = dir:magnitude()
|
||
local seez = npc:see(enemy) and enemy:see(npc) -- <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>
|
||
local cover = cover_in_direction(npc_lvid,dir,bs)
|
||
if seez or dist < 7 or cover > 0.8 or dist*cover > dist-f*cover then -- <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>, <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
st.evn = false
|
||
st.wait = tg+2500
|
||
return false
|
||
end
|
||
end
|
||
end
|
||
st.evn = true
|
||
st.wait = tg+400
|
||
return true
|
||
end
|
||
|
||
function actor_aiming_at_me(npc,df)
|
||
local aim_dir = device().cam_dir
|
||
local my_dir = npc:center():sub(device().cam_pos)
|
||
local aH,aP = aim_dir:getH(),aim_dir:getP()
|
||
local fH,fP = my_dir:getH(),my_dir:getP()
|
||
local f = 0.03+(df or 0.5)/my_dir:magnitude()
|
||
if (aH > fH and aH-fH or fH-aH) < f and (aP > fP and aP-fP or fP-aP) < f*2 then
|
||
return true
|
||
end
|
||
end
|
||
|
||
function eat_medkit(npc,medkit)
|
||
local health = read_from_ini(nil,medkit:section(),'npc_eat_health')
|
||
if health then
|
||
npc.health = health
|
||
end
|
||
npc:eat(medkit)
|
||
end
|
||
|
||
function IsTrader(npc)
|
||
local st = rx_ai.get_storage(npc:id())
|
||
if st.is_trader == nil then
|
||
local dbst = db.storage[npc:id()]
|
||
local trader = false
|
||
if npc:character_community() == "trader" or npc:clsid() == clsid.script_trader then
|
||
trader = true
|
||
elseif string.find(npc:section(),"trader") or string.find(npc:name(),"trader") then
|
||
trader = true
|
||
elseif dbst.ini and dbst.section_logic and dbst.ini:section_exist(dbst.section_logic) and dbst.ini:line_exist(dbst.section_logic,"trade") then
|
||
trader = true
|
||
end
|
||
if dbst.stype then -- <09><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
st.is_trader = trader
|
||
else
|
||
return trader
|
||
end
|
||
end
|
||
return st.is_trader == true
|
||
end
|
||
|
||
function safe_bone_pos(npc,bone)
|
||
local cls = npc:clsid()
|
||
if cls == clsid.burer_s then
|
||
return npc:center()
|
||
elseif cls == clsid.gigant_s then
|
||
return npc:center()
|
||
elseif cls == clsid.chimera_s then
|
||
return npc:bone_position("neck_r")
|
||
else
|
||
return npc:bone_position(bone or get_fire_bone(npc:section(),"torso"))
|
||
end
|
||
end
|
||
|
||
local gfb_torso,gfb_head,gfb_fire = {},{},{}
|
||
function get_fire_bone(sec,part)
|
||
if part == "head" then
|
||
if not gfb_head[sec] then
|
||
gfb_head[sec] = read_from_ini(nil,sec,"bone_head","bip01_head",1)
|
||
end
|
||
return gfb_head[sec]
|
||
elseif part == "torso" then
|
||
if not gfb_torso[sec] then
|
||
gfb_torso[sec] = read_from_ini(nil,sec,"bone_torso",nil,1) or read_from_ini(nil,sec,"bone_spin","bip01_spine",1)
|
||
end
|
||
return gfb_torso[sec]
|
||
end
|
||
if not gfb_fire[sec] then
|
||
gfb_fire[sec] = read_from_ini(nil,sec,"bone_fire","bip01_head",1)
|
||
end
|
||
return gfb_fire[sec]
|
||
end
|
||
|
||
--------------------------------------switch---------------------------------------
|
||
function switch_online(id)
|
||
if id == -1 then return end
|
||
local sim = alife()
|
||
if sim then
|
||
sim:set_switch_online(id,true)
|
||
sim:set_switch_offline(id,false)
|
||
end
|
||
end
|
||
|
||
function switch_offline(id)
|
||
local sim = alife()
|
||
if sim then
|
||
sim:set_switch_online(id,false)
|
||
sim:set_switch_offline(id,true)
|
||
end
|
||
end
|
||
|
||
--------------------------------------output---------------------------------------
|
||
function printf(str,...)
|
||
get_console():execute("load ~#I#:"..format_safe(str,...))
|
||
-- log(format_safe(str,...))
|
||
-- get_console():execute("flush")
|
||
end
|
||
|
||
function prints(str)
|
||
get_console():execute("load ~#I#:"..str)
|
||
-- log(str)
|
||
end
|
||
|
||
function give_game_news(str,time,...)
|
||
if db.actor then
|
||
db.actor:give_game_news("",format_safe(str,...),"ui_iconsTotal_grouping",0,time,0)
|
||
end
|
||
end
|
||
|
||
function ABORT(s,...)
|
||
printf("rx_utils.abort: "..s,...)
|
||
sys_ini:r_bool("___aborting","a")
|
||
end
|
||
_G['ABORTX'] = ABORT
|
||
|
||
function ASSERT(o,s,...)
|
||
if not o then
|
||
ABORT(s,...)
|
||
end
|
||
end
|
||
_G['ASSERTX'] = ASSERT
|
||
|
||
function print_table(t,name)
|
||
local print_r_cache={}
|
||
local function sub_print_r(t,indent)
|
||
if (type(t)~="userdata" and print_r_cache[tostring(t)]) then
|
||
prints(indent.."*"..tostring(t))
|
||
else
|
||
if type(t)~="userdata" then
|
||
print_r_cache[tostring(t)]=true
|
||
end
|
||
if (type(t)=="table") then
|
||
for pos,val in pairs(t) do
|
||
if (type(val)=="table") then
|
||
prints(indent.."["..pos.."] => "..tostring(t).." {")
|
||
sub_print_r(val,indent..string.rep(" ",string.len(pos)+8))
|
||
prints(indent..string.rep(" ",string.len(pos)+6).."}")
|
||
elseif (type(val)=="string") then
|
||
prints(indent.."["..pos..'] => "'..val..'"')
|
||
elseif(type(val)=="userdata") then
|
||
prints(indent.."["..pos..'] => "userdata"')
|
||
else
|
||
prints(indent.."["..pos.."] => "..tostring(val))
|
||
end
|
||
end
|
||
elseif(type(t)=="userdata") then
|
||
prints(indent.."userdata")
|
||
else
|
||
prints(indent..tostring(t))
|
||
end
|
||
end
|
||
end
|
||
if (type(t)=="table") then
|
||
printf("print_table %s: %s {",(name or 'unnamed'),tostring(t))
|
||
sub_print_r(t," ")
|
||
prints("}")
|
||
else
|
||
printf("print_table %s: %s(%s) is not table!",(name or 'unnamed'),type(t),t)
|
||
end
|
||
end
|
||
|
||
--------------------------------------spy------------------------------------------
|
||
|
||
class "prof_spy"
|
||
function prof_spy:__init()
|
||
self.store = {}
|
||
self.global_timer = time_global()
|
||
end
|
||
function prof_spy:__finalize()
|
||
end
|
||
|
||
function prof_spy:start(name)
|
||
if not self.store[name] then
|
||
self.store[name] = {timer = profile_timer(),count = 0,time = 0,min_time = 0,max_time = 0,prev_ptime = 0}
|
||
end
|
||
local st = self.store[name]
|
||
st.timer:start()
|
||
end
|
||
|
||
function prof_spy:finish(name)
|
||
local st = self.store[name]
|
||
ASSERTX(st,"spy finish %s",name)
|
||
st.timer:stop()
|
||
local ptime = st.timer:time()
|
||
local rtime = ptime-st.prev_ptime
|
||
if rtime == 0 then
|
||
return
|
||
end
|
||
st.prev_ptime = ptime
|
||
st.time = st.time+rtime
|
||
st.count = st.count+1
|
||
st.min_time = (st.min_time == 0 or rtime < st.min_time) and rtime or st.min_time
|
||
st.max_time = rtime > st.max_time and rtime or st.max_time
|
||
end
|
||
|
||
function prof_spy:get_stat(name)
|
||
if name then
|
||
local st = self.store[name]
|
||
if not st then
|
||
return "nil"
|
||
end
|
||
local global_time = time_global()-self.global_timer
|
||
local exec_ms_in_sec = st.time/global_time
|
||
local str = string.format("\n[%s]: cnt=[%s] time=[%s] min=[%s] max=[%s] prd=[%s] ret=[%s] insec=[%s]",name,st.count,st.time,st.min_time,st.max_time,global_time/st.count,st.time/st.count,exec_ms_in_sec)
|
||
return str
|
||
else
|
||
local tt = {}
|
||
for name,st in pairs(self.store) do
|
||
local global_time = time_global()-self.global_timer
|
||
local exec_ms_in_sec = st.time/global_time
|
||
local str = string.format("\n[%s]: cnt=[%s] time=[%s] min=[%s] max=[%s] prd=[%s] ret=[%s] insec=[%s]",name,st.count,st.time,st.min_time,st.max_time,global_time/st.count,st.time/st.count,exec_ms_in_sec)
|
||
table.insert(tt,str)
|
||
end
|
||
return tt
|
||
end
|
||
end
|