SoC. Снятие денег с трупов — различия между версиями
Материал из S.T.A.L.K.E.R. Inside Wiki
Deathdoor (обсуждение | вклад) (Отмена правки 9176 участника 146.101.133.37 (обсуждение)) |
Deathdoor (обсуждение | вклад) (Отмена правки 9056 участника 168.216.29.89 (обсуждение)) |
||
| Строка 1: | Строка 1: | ||
| − | + | В этой теме я напишу как сделать так что бы можно было снимать деньги с трупов. | |
| + | Нам надо файл treasure_manager.script | ||
| + | В этом файле находим такие строки | ||
| + | |||
| + | <pre>--' Юзание инициатора (возможность выдать тайник) | ||
| + | function CTreasure:use(npc) | ||
| + | printf("TREASURE USE") | ||
| + | После строки --printf("TREASURE USE")-- пишем | ||
| + | |||
| + | if (npc and db.actor) then | ||
| + | lootmoney.lootmoney(npc) | ||
| + | end | ||
| + | </pre> | ||
| + | У нас должно выйти | ||
| + | <pre>--' Юзание инициатора (возможность выдать тайник) | ||
| + | function CTreasure:use(npc) | ||
| + | printf("TREASURE USE") | ||
| + | |||
| + | if (npc and db.actor) then | ||
| + | lootmoney.lootmoney(npc) | ||
| + | end | ||
| + | </pre> | ||
| + | Теперь создаём файл lootmoney.script | ||
| + | и в нём пишем | ||
| + | |||
| + | <pre>function lootmoney(npc) | ||
| + | if npc ~= nil and not string.find(npc:section(),"arena") and npc:character_community()~="arena_enemy" then | ||
| + | local money = npc:money() | ||
| + | if money ~= nil and money ~=0 then | ||
| + | local deadmoney = money | ||
| + | |||
| + | local npc_rank | ||
| + | npc_rank = ranks.get_obj_rank_name(npc) | ||
| + | if npc_rank ~= nil then | ||
| + | if npc_rank == "novice" and deadmoney >=400 then deadmoney=math.random(25,400) | ||
| + | elseif npc_rank == "experienced" and deadmoney >=500 then deadmoney=math.random(50,500) | ||
| + | elseif npc_rank == "veteran" and deadmoney >=600 then deadmoney=math.random(100,600) | ||
| + | elseif npc_rank == "master" and deadmoney >=700 then deadmoney=math.random(200,700) | ||
| + | end | ||
| + | end | ||
| + | local news_texti = "\\n%c[255,255,0,0]Мёртвый сталкер: %c[default]"..npc:character_name().."\\n%c[255,255,0,0]Обнаружено денег: %c[default]"..game.translate_string(tostring(deadmoney).."руб.") | ||
| + | db.actor:give_game_news(news_texti, "ui\\ui_iconsTotal", Frect():set(0,0,83,47), 1, 4000) | ||
| + | db.actor:give_money(deadmoney) | ||
| + | game_stats.money_quest_update(deadmoney) | ||
| + | npc:give_money(-money) | ||
| + | game_stats.money_quest_update(-money) | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | </pre> | ||
| + | теперь создаем файл watcher_act.script и впишем в него | ||
| + | |||
| + | <pre>-- Red75 (c) 2008 | ||
| + | -- Marauder scheme v 1.1 | ||
| + | -- Part of AMK MOD | ||
| + | |||
| + | evid_see_stuff=6931 | ||
| + | evid_near_stuff=evid_see_stuff+1 | ||
| + | evid_see_body=evid_see_stuff+2 | ||
| + | evid_position_corrected=evid_see_stuff+3 | ||
| + | |||
| + | actid_reach_item=evid_see_stuff | ||
| + | actid_grab_item=evid_see_stuff+1 | ||
| + | actid_grab_body=evid_see_stuff+2 | ||
| + | actid_correct_position=evid_see_stuff+3 | ||
| + | |||
| + | -- Вызывает closure раз в period, obj[var] хранит время следующего срабатывания | ||
| + | function timed(obj,var,period,closure) | ||
| + | if obj[var] and obj[var]<time_global() then | ||
| + | obj[var]=time_global()+period | ||
| + | closure() | ||
| + | elseif not obj[var] then | ||
| + | obj[var]=time_global()+period | ||
| + | -- closure() | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function trigger_timed(obj,var) | ||
| + | obj[var]=time_global() | ||
| + | end | ||
| + | |||
| + | local disabled_objects={} | ||
| + | |||
| + | local corpse_checked={} -- true - has loot, false - hasn't loot, nil - not checked | ||
| + | |||
| + | function checkCorpse(obj) | ||
| + | if (IsStalker(obj) or IsMonster(obj)) and obj:alive()==false then | ||
| + | if corpse_checked[obj:id()]~=nil then | ||
| + | return corpse_checked[obj:id()] | ||
| + | end | ||
| + | local cnt=0 | ||
| + | obj:iterate_inventory(function (dummy, item) | ||
| + | if item:section()~="bolt" then | ||
| + | cnt=cnt+1 | ||
| + | end | ||
| + | end, nil) | ||
| + | corpse_checked[obj:id()]=cnt>0 | ||
| + | return corpse_checked[obj:id()] | ||
| + | end | ||
| + | return false | ||
| + | end | ||
| + | |||
| + | local valuable_clsid={ | ||
| + | [clsid.art_bast_artefact]=true, | ||
| + | [clsid.art_black_drops]=true, | ||
| + | [clsid.art_dummy]=true, | ||
| + | [clsid.art_electric_ball]=true, | ||
| + | [clsid.art_faded_ball]=true, | ||
| + | [clsid.art_galantine]=true, | ||
| + | [clsid.art_gravi]=true, | ||
| + | [clsid.art_gravi_black]=true, | ||
| + | [clsid.art_mercury_ball]=true, | ||
| + | [clsid.art_needles]=true, | ||
| + | [clsid.art_rusty_hair]=true, | ||
| + | [clsid.art_thorn]=true, | ||
| + | [clsid.art_zuda]=true, | ||
| + | [clsid.artefact_s]=true, | ||
| + | [clsid.device_detector_simple]=true, | ||
| + | [clsid.device_pda]=true, | ||
| + | [clsid.device_torch_s]=true, | ||
| + | [clsid.equ_exo]=true, | ||
| + | [clsid.equ_military]=true, | ||
| + | [clsid.equ_scientific]=true, | ||
| + | [clsid.equ_stalker_s]=true, | ||
| + | [clsid.obj_antirad]=true, | ||
| + | [clsid.obj_attachable]=true, | ||
| + | [clsid.obj_bandage]=true, | ||
| + | [clsid.obj_bolt]=true, | ||
| + | [clsid.obj_bottle]=true, | ||
| + | [clsid.obj_food]=true, | ||
| + | [clsid.obj_medkit]=true, | ||
| + | [clsid.wpn_ak74_s]=true, | ||
| + | [clsid.wpn_ammo]=true, | ||
| + | [clsid.wpn_ammo_m209]=true, | ||
| + | [clsid.wpn_ammo_og7b]=true, | ||
| + | [clsid.wpn_ammo_vog25]=true, | ||
| + | [clsid.wpn_binocular_s]=true, | ||
| + | [clsid.wpn_bm16_s]=true, | ||
| + | [clsid.wpn_fn2000]=true, | ||
| + | [clsid.wpn_fort]=true, | ||
| + | [clsid.wpn_groza_s]=true, | ||
| + | [clsid.wpn_hpsa_s]=true, | ||
| + | [clsid.wpn_knife_s]=true, | ||
| + | [clsid.wpn_lr300_s]=true, | ||
| + | [clsid.wpn_pm_s]=true, | ||
| + | [clsid.wpn_rg6_s]=true, | ||
| + | [clsid.wpn_rpg7_s]=true, | ||
| + | [clsid.wpn_scope_s]=true, | ||
| + | [clsid.wpn_shotgun_s]=true, | ||
| + | [clsid.wpn_silencer]=true, | ||
| + | [clsid.wpn_svd_s]=true, | ||
| + | [clsid.wpn_svu_s]=true, | ||
| + | [clsid.wpn_usp45_s]=true, | ||
| + | [clsid.wpn_val_s]=true, | ||
| + | [clsid.wpn_vintorez_s]=true, | ||
| + | [clsid.wpn_walther_s]=true, | ||
| + | [clsid.wpn_wmagaz]=true, | ||
| + | [clsid.wpn_wmaggl]=true | ||
| + | } | ||
| + | |||
| + | local obj_owner={} | ||
| + | |||
| + | function bgwith(str,ptr) | ||
| + | local ps=string.find(str,ptr) | ||
| + | return ps~=nil and ps==1 | ||
| + | end | ||
| + | |||
| + | function isValuable(obj) | ||
| + | local sec=obj:section() | ||
| + | if sec=="amk_metka" then | ||
| + | return false,false | ||
| + | end | ||
| + | if valuable_clsid[obj:clsid()] then | ||
| + | return true, false | ||
| + | end | ||
| + | return bgwith(sec,"af_") or bgwith(sec,"ammo_") or bgwith(sec,"wpn_") or bgwith(sec,"energy_") or checkCorpse(obj), IsStalker(obj) or IsMonster(obj) | ||
| + | end | ||
| + | |||
| + | function objValue(obj) | ||
| + | local sec=obj:section() | ||
| + | local multiplier=1 | ||
| + | if bgwith(sec,"ammo_") then | ||
| + | multiplier=30 | ||
| + | elseif sec=="vodka" then | ||
| + | multiplier=20 | ||
| + | end | ||
| + | if system_ini():section_exist(sec) and system_ini():line_exist(sec,"cost") then | ||
| + | return system_ini():r_float(sec,"cost")*multiplier | ||
| + | end | ||
| + | return 0 | ||
| + | end | ||
| + | |||
| + | function claimGObject(npc,st,obj) | ||
| + | if st.grabitemid then | ||
| + | obj_owner[st.grabitemid]=nil | ||
| + | end | ||
| + | st.grabitemid=obj:id() | ||
| + | obj_owner[obj:id()]=npc:id() | ||
| + | end | ||
| + | |||
| + | function freeGObject(st) | ||
| + | if st.grabitemid then | ||
| + | obj_owner[st.grabitemid]=nil | ||
| + | st.grabitemid=nil | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function clearGObject(st) | ||
| + | st.grabitemid=nil | ||
| + | end | ||
| + | |||
| + | function getGObject(st) | ||
| + | if st.grabitemid then | ||
| + | local ret=level.object_by_id(st.grabitemid) | ||
| + | if ret==nil then | ||
| + | st.grabitemid=nil | ||
| + | end | ||
| + | return ret | ||
| + | end | ||
| + | return nil | ||
| + | end | ||
| + | |||
| + | function mypGObject(npc,st) | ||
| + | return st.grabitemid~=nil and obj_owner[st.grabitemid]~=nil and obj_owner[st.grabitemid]==npc:id() | ||
| + | end | ||
| + | |||
| + | class "ev_see_stuff" (property_evaluator) | ||
| + | |||
| + | function ev_see_stuff:__init(st,name) super(nil, name) | ||
| + | self.st=st | ||
| + | end | ||
| + | |||
| + | local bad_dangers={ | ||
| + | [danger_object.hit]=true, | ||
| + | [danger_object.attacked]=true, | ||
| + | [danger_object.bullet_ricochet]=true, | ||
| + | [danger_object.grenade]=true, | ||
| + | [danger_object.entity_death]=true, | ||
| + | [danger_object.enemy_sound]=true | ||
| + | } | ||
| + | |||
| + | local inertion_time=30000 | ||
| + | |||
| + | function bad_danger(npc) | ||
| + | local danger=npc:best_danger() | ||
| + | if danger then | ||
| + | return bad_dangers[danger:type()] and time_global()-danger:time()<inertion_time | ||
| + | end | ||
| + | return false | ||
| + | end | ||
| + | |||
| + | function ev_see_stuff:evaluate() | ||
| + | local res=getGObject(self.st)~=nil | ||
| + | local npc=self.object | ||
| + | local actsch=db.storage[npc:id()].active_scheme | ||
| + | if actsch and db.actor then | ||
| + | xr_logic.try_switch_to_another_section(npc, db.storage[npc:id()][actsch], db.actor) | ||
| + | end | ||
| + | local act_sec=db.storage[npc:id()].active_section or "" | ||
| + | if (not npc:alive()) or xr_wounded.is_wounded(npc) or npc:best_enemy() or | ||
| + | bad_danger(npc) or (actsch and db.storage[npc:id()][actsch].no_loot) then | ||
| + | if res then | ||
| + | freeGObject(self.st) | ||
| + | amk.mylog(npc:name() .. " distracted. sect "..act_sec,"grb") | ||
| + | end | ||
| + | return false | ||
| + | end | ||
| + | local dist_limit=1000 | ||
| + | if bgwith(act_sec,"camper") then | ||
| + | dist_limit=5 | ||
| + | end | ||
| + | local busy=bgwith(act_sec,"walker") or bgwith(act_sec,"combat") or bgwith(act_sec,"danger") -- or npc:best_danger() | ||
| + | if res and self.st.block_search then | ||
| + | -- NPC собрался взять вещь. Временно прекратим поиск. | ||
| + | return true | ||
| + | end | ||
| + | timed(self.st,"tm1",5000+math.random()*10000, | ||
| + | function () | ||
| + | -- amk.mylog(npc:name() .. " is going to search stuff","grb") | ||
| + | local min_dist=100000 | ||
| + | local function check_item(o) | ||
| + | local obj=o:object() | ||
| + | if obj_owner[obj:id()] and (level.object_by_id(obj_owner[obj:id()])==nil or level.object_by_id(obj_owner[obj:id()]):alive()==false) then | ||
| + | obj_owner[obj:id()]=nil | ||
| + | end | ||
| + | if (not self.st.disabled_objects[obj:id()]) and (obj:parent()==nil or not IsStalker(obj:parent())) and | ||
| + | (obj_owner[obj:id()]==nil or obj_owner[obj:id()]==npc:id()) and npc:accessible(obj:level_vertex_id()) and | ||
| + | (db.actor==nil or db.actor:alive()==false or db.actor:position():distance_to_sqr(obj:position())>6) then | ||
| + | local valuable,corpse=isValuable(obj) | ||
| + | if valuable then | ||
| + | local value=3000 | ||
| + | if not corpse then | ||
| + | value=objValue(obj) | ||
| + | end | ||
| + | if value<=0 then value=0 end | ||
| + | local max_dist=5+math.sqrt(value) | ||
| + | if busy then | ||
| + | max_dist=max_dist/5 | ||
| + | end | ||
| + | local dist=level.vertex_position(obj:level_vertex_id()):distance_to(npc:position()) | ||
| + | local corrected_dist=dist | ||
| + | if dist>5 then | ||
| + | corrected_dist=5+(dist-5)/math.sqrt(value) | ||
| + | end | ||
| + | if dist<max_dist and corrected_dist<min_dist and dist<dist_limit then | ||
| + | min_dist=corrected_dist | ||
| + | claimGObject(npc,self.st,obj) | ||
| + | res=true | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | end -- function check_item | ||
| + | for o in npc:memory_visible_objects() do | ||
| + | check_item(o) | ||
| + | end | ||
| + | for o in npc:memory_sound_objects() do | ||
| + | check_item(o) | ||
| + | end | ||
| + | -- for o in npc:not_yet_visible_objects() do | ||
| + | -- check_item(o) | ||
| + | -- end | ||
| + | if res then | ||
| + | amk.mylog(npc:name() .. " claimed "..getGObject(self.st):name().." cact "..tostring(npc:motivation_action_manager():current_action_id()),"grb") | ||
| + | end | ||
| + | end | ||
| + | ) | ||
| + | return res -- false -- res | ||
| + | end | ||
| + | |||
| + | class "ev_near_stuff" (property_evaluator) | ||
| + | |||
| + | function ev_near_stuff:__init(st,name) super(nil, name) | ||
| + | self.st=st | ||
| + | end | ||
| + | |||
| + | function ev_near_stuff:evaluate() | ||
| + | local npc=self.object | ||
| + | local gi=getGObject(self.st) | ||
| + | if gi then | ||
| + | if self.st.dest_lvid then | ||
| + | return npc:level_vertex_id()==self.st.dest_lvid | ||
| + | end | ||
| + | return level.vertex_position(gi:level_vertex_id()):distance_to_sqr(npc:position())<1 | ||
| + | end | ||
| + | return false | ||
| + | end | ||
| + | |||
| + | class "ev_see_body" (property_evaluator) | ||
| + | |||
| + | function ev_see_body:__init(st) super(nil, "ev_see_body") | ||
| + | self.st=st | ||
| + | end | ||
| + | |||
| + | function ev_see_body:evaluate() | ||
| + | local npc=self.object | ||
| + | local gi=getGObject(self.st) | ||
| + | if gi then | ||
| + | return IsStalker(gi) or IsMonster(gi) | ||
| + | end | ||
| + | return false | ||
| + | end | ||
| + | |||
| + | class "ev_position_corrected" (property_evaluator) | ||
| + | |||
| + | function ev_position_corrected:__init(st) super(nil, "ev_position_corrected") | ||
| + | self.st=st | ||
| + | end | ||
| + | |||
| + | function ev_position_corrected:evaluate() | ||
| + | local npc=self.object | ||
| + | return self.st.position_corrected==true | ||
| + | end | ||
| + | |||
| + | |||
| + | class "act_grab_item" (action_base) | ||
| + | |||
| + | function act_grab_item:__init (action_name, st) super (nil, action_name) | ||
| + | self.st = st | ||
| + | end | ||
| + | |||
| + | function act_grab_item:initialize() | ||
| + | action_base.initialize(self) | ||
| + | local npc=self.object | ||
| + | npc:set_item(object.idle,nil) | ||
| + | npc:set_movement_type(move.walk) | ||
| + | npc:set_mental_state(anim.danger) | ||
| + | npc:set_body_state(move.crouch) | ||
| + | npc:movement_enabled(true) | ||
| + | local gi=getGObject(self.st) | ||
| + | -- if gi then npc:set_sight(gi,true,true) end | ||
| + | npc:set_sight(look.danger,nil,0) | ||
| + | amk.mylog(self.object:name().." is going to grab item","stmt") | ||
| + | self.st.block_search=true | ||
| + | if gi then | ||
| + | if(IsStalker(gi) or IsMonster(gi)) then | ||
| + | self.tt=time_global()+3000 | ||
| + | else | ||
| + | self.tt=time_global()+1000 | ||
| + | utils.send_to_nearest_accessible_vertex(npc,gi:level_vertex_id()) | ||
| + | end | ||
| + | |||
| + | end | ||
| + | --npc:set_dest_level_vertex_id(1) | ||
| + | self.force=vector():set(0,0,0) | ||
| + | end | ||
| + | |||
| + | function act_grab_item:execute() | ||
| + | action_base.execute(self) | ||
| + | local npc=self.object | ||
| + | local gi=getGObject(self.st) | ||
| + | if not gi then | ||
| + | return | ||
| + | end | ||
| + | if self.tt<time_global() then | ||
| + | if gi and gi:parent()==nil then | ||
| + | gi:transfer_item(gi,npc) | ||
| + | npc:enable_memory_object(gi,false) | ||
| + | amk.mylog(npc:name() .. " has taken "..gi:name(),"grb") | ||
| + | end | ||
| + | -- Тут нельзя освобождать объект. transfer_item выполняется асинхронно. Поэтому делаем clearGObject | ||
| + | clearGObject(self.st) | ||
| + | --freeGObject(self.st) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function act_grab_item:finalize() | ||
| + | local npc=self.object | ||
| + | self.st.block_search=nil | ||
| + | npc:set_sight(look.danger,nil,0) | ||
| + | trigger_timed(self.st,"tm1") | ||
| + | self.st.dest_lvid=nil -- Очищаем скорректированную точку назначения | ||
| + | action_base.finalize(self) | ||
| + | end | ||
| + | |||
| + | class "act_grab_body" (action_base) | ||
| + | |||
| + | function act_grab_body:__init (st) super (nil, "act_grab_body") | ||
| + | self.st = st | ||
| + | end | ||
| + | |||
| + | function act_grab_body:initialize() | ||
| + | action_base.initialize(self) | ||
| + | local npc=self.object | ||
| + | local gi=getGObject(self.st) | ||
| + | amk.mylog(self.object:name().." is going to grab body","stmt") | ||
| + | self.st.block_search=true | ||
| + | if gi then | ||
| + | self.tt=time_global()+6000 | ||
| + | state_mgr.set_state(npc,"search",nil,nil,{look_object=gi}) | ||
| + | else | ||
| + | self.st.dest_lvid=nil | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function act_grab_body:execute() | ||
| + | action_base.execute(self) | ||
| + | local npc=self.object | ||
| + | local gi=getGObject(self.st) | ||
| + | if not gi then | ||
| + | self.st.dest_lvid=nil | ||
| + | return | ||
| + | end | ||
| + | if self.tt<time_global() then | ||
| + | if gi and gi:parent()==nil then | ||
| + | gi:iterate_inventory(function (d,item) | ||
| + | if item:section()~="bolt" then | ||
| + | gi:transfer_item(item,npc) | ||
| + | end | ||
| + | end, nil) | ||
| + | local num=gi:money() | ||
| + | if num and num >0 then | ||
| + | local deadmoney = num | ||
| + | local gi_rank | ||
| + | gi_rank = ranks.get_obj_rank_name(gi) | ||
| + | if gi_rank ~= nil then | ||
| + | if gi_rank == "novice" and deadmoney >=100 then deadmoney=math.random(25,100) | ||
| + | elseif gi_rank == "experienced" and deadmoney >=200 then deadmoney=math.random(50,200) | ||
| + | elseif gi_rank == "veteran" and deadmoney >=300 then deadmoney=math.random(100,300) | ||
| + | elseif gi_rank == "master" and deadmoney >=400 then deadmoney=math.random(200,400) | ||
| + | end | ||
| + | end | ||
| + | npc:give_money(deadmoney) | ||
| + | game_stats.money_quest_update(deadmoney) | ||
| + | gi:give_money(-num) | ||
| + | game_stats.money_quest_update(-num) | ||
| + | end | ||
| + | corpse_checked[gi:id()]=false | ||
| + | amk.mylog(npc:name() .. " has taken "..gi:name(),"grb") | ||
| + | end | ||
| + | -- Тут нельзя освобождать объект. transfer_item выполняется асинхронно. Поэтому делаем clearGObject | ||
| + | clearGObject(self.st) | ||
| + | --freeGObject(self.st) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function act_grab_body:finalize() | ||
| + | local npc=self.object | ||
| + | self.st.block_search=nil | ||
| + | trigger_timed(self.st,"tm1") | ||
| + | self.st.dest_lvid=nil -- Очищаем скорректированную точку назначения | ||
| + | action_base.finalize(self) | ||
| + | end | ||
| + | |||
| + | function correct_position(gi,npc) | ||
| + | if IsStalker(gi) then | ||
| + | -- Вычисляем вектор разницы между координатами кости и level vertex. Пытаемся найти level vertex наиболее близкий к кости | ||
| + | local diff=gi:bone_position("bip01_head"):sub(level.vertex_position(gi:level_vertex_id())) | ||
| + | local len=diff:magnitude() | ||
| + | local diffp=vector():set(diff.z,0,-diff.x):mul(0.5) | ||
| + | -- Сдвигаем целевую точку вбок, чтобы непись не залазил ногами в труп | ||
| + | diff:add(diffp) | ||
| + | return npc:vertex_in_direction(gi:level_vertex_id(),diff,len) | ||
| + | else | ||
| + | return gi:level_vertex_id() | ||
| + | end | ||
| + | end | ||
| + | |||
| + | class "act_reach_item" (action_base) | ||
| + | |||
| + | function act_reach_item:__init (action_name, st) super (nil, action_name) | ||
| + | self.st = st | ||
| + | end | ||
| + | |||
| + | function act_reach_item:initialize() | ||
| + | action_base.initialize(self) | ||
| + | local npc=self.object | ||
| + | local gi=getGObject(self.st) | ||
| + | self.st.dest_lvid=nil | ||
| + | self.tgt_lvid=0 | ||
| + | if gi then | ||
| + | if npc:accessible(gi:level_vertex_id()) then | ||
| + | npc:set_detail_path_type(move.curve) | ||
| + | npc:set_path_type(game_object.level_path) | ||
| + | if npc:best_danger() and time_global()-npc:best_danger():time()<inertion_time then | ||
| + | npc:set_mental_state(anim.danger) | ||
| + | npc:set_body_state(move.crouch) | ||
| + | npc:set_movement_type(move.walk) | ||
| + | -- npc:set_sight(gi,true,true) | ||
| + | else | ||
| + | npc:set_body_state(move.standing) | ||
| + | npc:set_mental_state(anim.free) | ||
| + | npc:set_movement_type(move.walk) | ||
| + | end | ||
| + | npc:movement_enabled(true) | ||
| + | if npc:best_weapon() and isWeapon(npc:best_weapon()) then | ||
| + | -- npc:set_item(object.idle,npc:best_weapon()) | ||
| + | end | ||
| + | -- npc:set_dest_level_vertex_id(gi:level_vertex_id()) | ||
| + | npc:set_sight(look.danger,nil,0) | ||
| + | self.st.dest_lvid=correct_position(gi,npc) --gi:level_vertex_id() | ||
| + | self.tgt_lvid=gi:level_vertex_id() | ||
| + | npc:set_dest_level_vertex_id(self.st.dest_lvid) | ||
| + | else | ||
| + | freeGObject(self.st) | ||
| + | end | ||
| + | end | ||
| + | self.ct=time_global() | ||
| + | self.clvid=npc:level_vertex_id() | ||
| + | self.st.position_corrected=false | ||
| + | amk.mylog(self.object:name().." is going to reach item","stmt") | ||
| + | end | ||
| + | |||
| + | function act_reach_item:execute() | ||
| + | action_base.execute(self) | ||
| + | local npc=self.object | ||
| + | local gi=getGObject(self.st) | ||
| + | if gi and gi:parent()~=nil then | ||
| + | -- ГГ забрал вкусность. Можно добавить наезд на ГГ. | ||
| + | self.st.dest_lvid=nil | ||
| + | freeGObject(self.st) | ||
| + | elseif gi then | ||
| + | if self.clvid==npc:level_vertex_id() then | ||
| + | if time_global()-self.ct>10000 then | ||
| + | -- не можем добраться до нняки | ||
| + | self.st.disabled_objects[gi:id()]=true | ||
| + | self.st.dest_lvid=nil | ||
| + | freeGObject(self.st) | ||
| + | end | ||
| + | else | ||
| + | self.clvid=npc:level_vertex_id() | ||
| + | self.ct=time_global() | ||
| + | end | ||
| + | if self.tgt_lvid~=gi:level_vertex_id() then | ||
| + | self.tgt_lvid=gi:level_vertex_id() | ||
| + | self.st.dest_lvid=correct_position(gi,npc) -- gi:level_vertex_id() | ||
| + | npc:set_dest_level_vertex_id(self.st.dest_lvid) | ||
| + | end | ||
| + | --npc:set_sight(gi) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function add_to_binder(object, char_ini, scheme, section, st) | ||
| + | -- amk.mylog("addtb "..object:name(),"pln") | ||
| + | local npc=object | ||
| + | st.disabled_objects={} | ||
| + | local manager = object:motivation_action_manager() | ||
| + | |||
| + | local zombi=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" or -- сумашедший на милитари и Сахаров | ||
| + | npc:name()=="mil_freedom_member0021" -- Скрягу в зомби! | ||
| + | |||
| + | local prop_idlecombat=xr_evaluators_id.state_mgr + 3 | ||
| + | local prop_contact=xr_evaluators_id.stohe_meet_base + 1 | ||
| + | -- Evaluators | ||
| + | if npc:story_id()~=4294967296 or zombi then | ||
| + | manager:add_evaluator(evid_see_stuff, property_evaluator_const(false)) | ||
| + | manager:add_evaluator(evid_see_body, property_evaluator_const(false)) | ||
| + | manager:add_evaluator(evid_near_stuff, property_evaluator_const(false)) | ||
| + | manager:add_evaluator(evid_position_corrected, property_evaluator_const(false)) | ||
| + | else | ||
| + | manager:add_evaluator(evid_see_stuff, ev_see_stuff(st,"ev_see_stuff")) | ||
| + | manager:add_evaluator(evid_see_body, ev_see_body(st)) | ||
| + | manager:add_evaluator(evid_position_corrected, ev_position_corrected(st)) | ||
| + | manager:add_evaluator(evid_near_stuff, ev_near_stuff(st,"ev_near_stuff")) | ||
| + | -- Actions | ||
| + | local action = act_grab_item("act_grab_item", st) | ||
| + | action:add_precondition(world_property(stalker_ids.property_alive,true)) | ||
| + | action:add_precondition(world_property(stalker_ids.property_enemy,false)) | ||
| + | -- action:add_precondition(world_property(stalker_ids.property_danger,false)) | ||
| + | action:add_precondition(world_property(xr_evaluators_id.sidor_wounded_base,false)) | ||
| + | action:add_precondition(world_property(blowout_scheme.evid_anomaly,false)) | ||
| + | action:add_precondition(world_property(blowout_scheme.evid_blowout,false)) | ||
| + | action:add_precondition(world_property(evid_see_stuff,true)) | ||
| + | action:add_precondition(world_property(evid_near_stuff,true)) | ||
| + | action:add_precondition(world_property(evid_see_body,false)) | ||
| + | action:add_precondition(world_property(prop_idlecombat,true)) -- отключим стэйт менеджер | ||
| + | action:add_effect(world_property(evid_near_stuff, false)) | ||
| + | action:add_effect(world_property(evid_see_stuff, false)) | ||
| + | action:add_effect(world_property(evid_see_body,true)) -- для переключения на обыск трупа | ||
| + | manager:add_action (actid_grab_item, action) | ||
| + | |||
| + | action = act_grab_body(st) | ||
| + | action:add_precondition(world_property(stalker_ids.property_alive,true)) | ||
| + | action:add_precondition(world_property(stalker_ids.property_enemy,false)) | ||
| + | -- action:add_precondition(world_property(stalker_ids.property_danger,false)) | ||
| + | action:add_precondition(world_property(xr_evaluators_id.sidor_wounded_base,false)) | ||
| + | action:add_precondition(world_property(blowout_scheme.evid_anomaly,false)) | ||
| + | action:add_precondition(world_property(blowout_scheme.evid_blowout,false)) | ||
| + | action:add_precondition(world_property(evid_see_stuff,true)) | ||
| + | action:add_precondition(world_property(evid_see_body,true)) | ||
| + | action:add_precondition(world_property(evid_near_stuff,true)) | ||
| + | -- action:add_precondition(world_property(evid_position_corrected,true)) | ||
| + | action:add_effect(world_property(evid_near_stuff, false)) | ||
| + | action:add_effect(world_property(evid_see_stuff, false)) | ||
| + | action:add_effect(world_property(evid_see_body,false)) -- переключаемся на подъём вещички | ||
| + | manager:add_action (actid_grab_body, action) | ||
| + | |||
| + | action = act_reach_item("act_reach_item", st) | ||
| + | action:add_precondition(world_property(stalker_ids.property_alive,true)) | ||
| + | action:add_precondition(world_property(stalker_ids.property_enemy,false)) | ||
| + | action:add_precondition(world_property(prop_contact,false)) | ||
| + | -- action:add_precondition(world_property(stalker_ids.property_danger,false)) | ||
| + | action:add_precondition(world_property(xr_evaluators_id.sidor_wounded_base,false)) | ||
| + | action:add_precondition(world_property(blowout_scheme.evid_anomaly,false)) | ||
| + | action:add_precondition(world_property(blowout_scheme.evid_blowout,false)) | ||
| + | action:add_precondition(world_property(evid_see_stuff,true)) | ||
| + | action:add_precondition(world_property(evid_near_stuff,false)) | ||
| + | action:add_precondition(world_property(prop_idlecombat,true)) | ||
| + | action:add_effect (world_property(evid_near_stuff, true)) | ||
| + | manager:add_action (actid_reach_item, action) | ||
| + | |||
| + | action = manager:action(xr_actions_id.alife) | ||
| + | action:add_precondition(world_property(evid_see_stuff,false)) | ||
| + | action = manager:action(stalker_ids.action_danger_planner) | ||
| + | action:add_precondition(world_property(evid_see_stuff,false)) | ||
| + | -- action:add_precondition(world_property(evid_near_stuff,false)) | ||
| + | -- action = manager:action(xr_actions_id.stohe_kamp_base + 1) | ||
| + | -- action:add_precondition(world_property(evid_see_stuff,false)) | ||
| + | -- action = manager:action(xr_actions_id.stohe_kamp_base + 3) | ||
| + | -- action:add_precondition(world_property(evid_see_stuff,false)) | ||
| + | |||
| + | -- action = manager:action(xr_actions_id.stohe_meet_base+1) | ||
| + | -- action:add_precondition(world_property(evid_see_stuff,false)) | ||
| + | -- amk.mylog("addtb end "..object:name(),"pln") | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function set_scheme(npc, ini, scheme, section) | ||
| + | -- amk.mylog("set scheme "..npc:name().." story_id "..npc:story_id(),"pln") | ||
| + | local st = xr_logic.assign_storage_and_bind(npc, ini, scheme, section) | ||
| + | st.ini=ini | ||
| + | end | ||
| + | |||
| + | Теперь осталось содать скрипт amk.script --у кого есть ненадо-- | ||
| + | и вписываем в него | ||
| + | |||
| + | local npc_spawner={} --служебный массив, работает автоматически - не трогать шаловливыми русками | ||
| + | |||
| + | local timers={} --хранит реал-тайм таймеры | ||
| + | local g_timers={} --хранит таймеры в игровом времени | ||
| + | local markers={} --хранит маркеры на карте | ||
| + | local x_objs={} --хранит ИДшники объектов | ||
| + | local timer_trigger=nil | ||
| + | convert_npc={} | ||
| + | g_kick=false | ||
| + | |||
| + | is_debug = false | ||
| + | ver = "0" | ||
| + | oau_watchdog=0 | ||
| + | oau_reason="" | ||
| + | --переменные для типсов | ||
| + | pda_news = xr_sound.get_safe_sound_object([[device\pda\pda_news]]) | ||
| + | pda_tips = xr_sound.get_safe_sound_object([[device\pda\pda_tip]]) | ||
| + | pda_task = xr_sound.get_safe_sound_object([[device\pda\pda_objective]]) | ||
| + | |||
| + | tips_icons = { | ||
| + | default = { 0, 658}, | ||
| + | trader = { 332, 893}, | ||
| + | dolg = { 0, 658}, | ||
| + | freedom = { 0, 658}, | ||
| + | ecolog = { 498, 0}, | ||
| + | arena = { 332, 141}, | ||
| + | stalker = { 0, 658}, | ||
| + | krot = { 332, 47}, | ||
| + | barman = { 332, 235}, | ||
| + | wolf = { 332, 940}, | ||
| + | o_soznanie = { 498, 893}, | ||
| + | monolith = { 0, 658}, | ||
| + | saharov = { 332, 470}, | ||
| + | prizrak = { 0, 658}, | ||
| + | killer = { 0, 658}, | ||
| + | death = { 0, 752}, | ||
| + | gen_info = { 0, 658}, | ||
| + | trade = { 0, 0}, | ||
| + | uniq = { 498, 47} --{ 498, 188} | ||
| + | } | ||
| + | ---------------- | ||
| + | local bufferedmessages={} | ||
| + | |||
| + | function logct(msg,tag) | ||
| + | if true and (tag and (tag=="mcbt" or tag=="temp")) then --(tag=="dram")) then | ||
| + | get_console():execute("load [[Участник:92.113.172.219|92.113.172.219]] "..string.sub(msg,1,200)) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function rep(npc,msg,tag) | ||
| + | if string.find(npc:name(),"gar_dm") then | ||
| + | logct(msg,tag) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function mylog(msg) | ||
| + | if is_debug then | ||
| + | if msg==nil then | ||
| + | return | ||
| + | end | ||
| + | if db and db.actor then | ||
| + | if bufferedmessages then | ||
| + | for k,v in ipairs(bufferedmessages) do | ||
| + | db.actor:give_game_news(v, "ui\\ui_iconsTotal", Frect():set(0,658,83,47), 0, 15000) | ||
| + | end | ||
| + | bufferedmessages=nil | ||
| + | end | ||
| + | db.actor:give_game_news(msg, "ui\\ui_iconsTotal", Frect():set(0,658,83,47), 0, 15000) | ||
| + | else | ||
| + | if bufferedmessages then | ||
| + | table.insert(bufferedmessages,msg) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | if get_console() then | ||
| + | get_console():execute("load [[Участник:92.113.172.219|92.113.172.219]] "..string.sub(msg,1,200)) | ||
| + | get_console():execute("flush") | ||
| + | end | ||
| + | |||
| + | end | ||
| + | end | ||
| + | |||
| + | --показываем типс | ||
| + | function send_tip(news_text, header, timeout, showtime, sender, sound) | ||
| + | if news_text==nil then return end | ||
| + | if header==nil then header=game.translate_string("st_tip") end | ||
| + | if timeout == nil then timeout = 0 end | ||
| + | if showtime == nil then showtime = 5 end | ||
| + | |||
| + | local player | ||
| + | if sound=="news" then | ||
| + | player=pda_news | ||
| + | elseif sound=="task" then | ||
| + | player=pda_task | ||
| + | else | ||
| + | player=pda_tips | ||
| + | end | ||
| + | |||
| + | --' Играем дефолтный звук | ||
| + | player:play(db.actor, timeout, sound_object.s2d) | ||
| + | |||
| + | if sender == nil then | ||
| + | sender = "default" | ||
| + | end | ||
| + | local x = tips_icons[sender][1] | ||
| + | local y = tips_icons[sender][2] | ||
| + | |||
| + | local news_text = "%c[255,160,160,160]"..header.."\\n".."%c[default]"..news_text | ||
| + | db.actor:give_game_news(news_text, "ui\\ui_iconsTotal", Frect():set(x,y,83,47), timeout*1000, showtime*1000) | ||
| + | return true | ||
| + | end | ||
| + | |||
| + | function add_spot_on_map(obj_id,type,text) | ||
| + | --возможные типы type смотри в ui\map_spots.xml | ||
| + | if obj_id then | ||
| + | if text==nil then text=" " end | ||
| + | -- Ставим метку на серверный объект чтобы её не пришлось обновлять | ||
| + | level.map_add_object_spot_ser(obj_id, type, text) | ||
| + | -- save_variable("x_marker_type_"..obj_id, type) | ||
| + | -- save_variable("x_marker_text_"..obj_id, text) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function remove_spot_from_map(obj_id,type) | ||
| + | if obj_id and level.map_has_object_spot(obj_id, type)~= 0 then | ||
| + | level.map_remove_object_spot(obj_id, type) | ||
| + | -- del_variable("x_marker_type_"..obj_id) | ||
| + | -- del_variable("x_marker_text_"..obj_id) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | --старт таймера в реальном времени | ||
| + | function start_timer(name,delay,action) | ||
| + | if not delay then | ||
| + | return false | ||
| + | end | ||
| + | |||
| + | if not action then | ||
| + | action = "" | ||
| + | end | ||
| + | |||
| + | local time = game.time() --time in seconds since 1970 | ||
| + | local a=1 | ||
| + | while db.storage[db.actor:id()].pstor["xt"..a] do | ||
| + | a=a+1 | ||
| + | if a>100 then | ||
| + | return false | ||
| + | end | ||
| + | end | ||
| + | save_variable("xt"..a, name) | ||
| + | save_variable("xd"..a, time+delay*1000*system_ini():r_float("alife","time_factor")) | ||
| + | save_variable("xp"..a, action) | ||
| + | |||
| + | return true | ||
| + | end | ||
| + | |||
| + | --старт таймера в игровом времени | ||
| + | function g_start_timer(name,delay_d,delay_h,delay_m,action) | ||
| + | local time = level.get_time_days()*60*24+level.get_time_hours()*60+level.get_time_minutes() --time in game minutes | ||
| + | if delay_d==nil or delay_h==nil or delay_m==nil then | ||
| + | return false | ||
| + | end | ||
| + | |||
| + | if action==nil then | ||
| + | action = "" | ||
| + | end | ||
| + | |||
| + | local a=1 | ||
| + | while db.storage[db.actor:id()].pstor["gt"..a] do | ||
| + | a=a+1 | ||
| + | if a>100 then | ||
| + | return false | ||
| + | end | ||
| + | end | ||
| + | |||
| + | save_variable("gt"..a, name) | ||
| + | save_variable("gd"..a, time+delay_d*60*24+delay_h*60+delay_m) | ||
| + | save_variable("gp"..a, action) | ||
| + | |||
| + | return true | ||
| + | end | ||
| + | |||
| + | function has_timer(name) | ||
| + | for a=1,100,1 do | ||
| + | tmp=load_variable("xt"..a,nil) | ||
| + | if tmp and tmp==name then | ||
| + | return true | ||
| + | end | ||
| + | end | ||
| + | return false | ||
| + | end | ||
| + | |||
| + | function has_g_timer(name) | ||
| + | for a=1,100,1 do | ||
| + | tmp=load_variable("gt"..a,nil) | ||
| + | if tmp and tmp==name then | ||
| + | return true | ||
| + | end | ||
| + | end | ||
| + | return false | ||
| + | end | ||
| + | |||
| + | -- Временное хранилище для переменных удалённых из pstor | ||
| + | local emerg_store | ||
| + | -- Удаляем переменные из pstor. Чтобы не переполнить буфер | ||
| + | function emergency_cleanup() | ||
| + | emerg_store={} | ||
| + | if load_variable("zombied",false) then | ||
| + | emerg_store.zombied=load_table("zombied") | ||
| + | del_variable("zombied") | ||
| + | end | ||
| + | for i=1,100,1 do | ||
| + | if load_variable("gt"..i,"")=="af_transform" then | ||
| + | emerg_store[i]={} | ||
| + | emerg_store[i].gt=load_variable("gt"..i,"") | ||
| + | emerg_store[i].gd=load_variable("gd"..i,"") | ||
| + | emerg_store[i].gp=load_variable("gp"..i,"") | ||
| + | del_variable("gt"..i) | ||
| + | del_variable("gd"..i) | ||
| + | del_variable("gp"..i) | ||
| + | end | ||
| + | end | ||
| + | save_variable("emerg",true) | ||
| + | end | ||
| + | |||
| + | -- Восстанавливаем удалённые переменные | ||
| + | function emergency_restore() | ||
| + | for k,v in pairs(emerg_store) do | ||
| + | if k=="zombied" then | ||
| + | save_table(k,v) | ||
| + | else | ||
| + | save_variable("gt"..k,v.gt) | ||
| + | save_variable("gd"..k,v.gd) | ||
| + | save_variable("gp"..k,v.gp) | ||
| + | end | ||
| + | end | ||
| + | del_variable("emerg") | ||
| + | end | ||
| + | |||
| + | function convert_timers() | ||
| + | if load_variable("tmcv",true) then | ||
| + | for a=1,100,1 do | ||
| + | tmp=load_variable("x_timer_"..a,nil) | ||
| + | if tmp~=nil then | ||
| + | local name,delay,params=tmp,load_variable("x_timer_"..a.."_delay",0),load_variable("x_timer_"..a.."_params","") | ||
| + | del_variable("x_timer_"..a) | ||
| + | del_variable("x_timer_"..a.."_delay") | ||
| + | del_variable("x_timer_"..a.."_params") | ||
| + | save_variable("xt"..a,name) | ||
| + | save_variable("xd"..a,delay) | ||
| + | save_variable("xp"..a,params) | ||
| + | end | ||
| + | end | ||
| + | for a=1,100,1 do | ||
| + | tmp=load_variable("x_gtimer_"..a,nil) | ||
| + | if tmp~=nil then | ||
| + | local name,delay,params=tmp,load_variable("x_gtimer_"..a.."_delay",0),load_variable("x_gtimer_"..a.."_params","") | ||
| + | del_variable("x_gtimer_"..a) | ||
| + | del_variable("x_gtimer_"..a.."_delay") | ||
| + | del_variable("x_gtimer_"..a.."_params") | ||
| + | save_variable("gt"..a,name) | ||
| + | save_variable("gd"..a,delay) | ||
| + | save_variable("gp"..a,params) | ||
| + | end | ||
| + | end | ||
| + | save_variable("tmcv",false) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | --проверка таймеров, использует 3 следующие за ним функции для выбора действия | ||
| + | function check_timers() | ||
| + | local tmp | ||
| + | for a=1,100,1 do | ||
| + | tmp=load_variable("xt"..a,nil) | ||
| + | if tmp~=nil then | ||
| + | __timer_found(a) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | for a=1,100,1 do | ||
| + | tmp=load_variable("gt"..a,nil) | ||
| + | if tmp~=nil then | ||
| + | __g_timer_found(a) | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | function __timer_found(idx) | ||
| + | local time = game.time() --time in seconds since 1970 | ||
| + | local name,params | ||
| + | if load_variable("xd"..idx, nil)<=time then | ||
| + | name=load_variable("xt"..idx, nil) | ||
| + | params=load_variable("xp"..idx, nil) | ||
| + | del_variable("xt"..idx) | ||
| + | del_variable("xd"..idx) | ||
| + | del_variable("xp"..idx) | ||
| + | oau_reason=name.." "..params | ||
| + | __do_timer_action(name,params) | ||
| + | return true | ||
| + | end | ||
| + | return false | ||
| + | end | ||
| + | function __g_timer_found(idx) | ||
| + | local gtime = level.get_time_days()*60*24+level.get_time_hours()*60+level.get_time_minutes() --time in game minutes | ||
| + | local name,params | ||
| + | if load_variable("gd"..idx, nil)<=gtime then | ||
| + | name=load_variable("gt"..idx, nil) | ||
| + | params=load_variable("gp"..idx, nil) | ||
| + | del_variable("gt"..idx) | ||
| + | del_variable("gd"..idx) | ||
| + | del_variable("gp"..idx) | ||
| + | oau_reason=name.." "..params | ||
| + | __do_timer_action(name,params) | ||
| + | return true | ||
| + | end | ||
| + | return false | ||
| + | end | ||
| + | function __do_timer_action(select_string,params_string) | ||
| + | --[[ | ||
| + | здесь описываем вызовы, оформялять в виде | ||
| + | |||
| + | if select_string=="название условия" then | ||
| + | <вызов сторонних функций> | ||
| + | -- можно передавать npc как параметр | ||
| + | end | ||
| + | |||
| + | ]] | ||
| + | --user area | ||
| + | if select_string=="show_news" then | ||
| + | mod_call("show_news") | ||
| + | end | ||
| + | if select_string=="gg_need_sleep" then | ||
| + | mod_call("test_for_need_sleep") | ||
| + | end | ||
| + | if select_string=="sleep_nrg" then | ||
| + | mod_call("test_for_need_sleep_nrg",params_string) | ||
| + | end | ||
| + | --[[ | ||
| + | if select_string=="sleep_med" then | ||
| + | mod_call("test_for_need_sleep_med",params_string) | ||
| + | end | ||
| + | ]]-- | ||
| + | if select_string=="sleep_matras" then | ||
| + | mod_call("test_for_need_sleep_matras",params_string) | ||
| + | end | ||
| + | if select_string=="sleep_tr_item" then | ||
| + | mod_call("test_for_need_sleep_tr_item",params_string) | ||
| + | end | ||
| + | if select_string=="sleep_notebook" then | ||
| + | mod_call("test_for_need_sleep_notebook",params_string) | ||
| + | end | ||
| + | if select_string=="block_sleep_menu" then | ||
| + | save_variable("block_sleep_menu",0) | ||
| + | end | ||
| + | if select_string=="radar_fix" then | ||
| + | mod_call("radar_fix") | ||
| + | end | ||
| + | if select_string=="af_transform" then | ||
| + | mod_call("af_transform_end",unpack_array_from_string(params_string)) | ||
| + | end | ||
| + | if select_string=="amk_freeplay" then | ||
| + | if amk.load_variable("freeplay",0)==1 and level.name()=="l12_stancia_2" then | ||
| + | xr_effects.game_credits() | ||
| + | end | ||
| + | end | ||
| + | if select_string=="blowout" then | ||
| + | mod_call("Blowout_pp",params_string) | ||
| + | end | ||
| + | if select_string=="test" then | ||
| + | mod_call("Run_Blowout_pp") | ||
| + | end | ||
| + | if select_string=="blowout_ss" then | ||
| + | mod_call("blowout_scary_sounds") | ||
| + | end | ||
| + | if select_string=="blow_shift" then | ||
| + | mod_call("Run_Blowout_pp") | ||
| + | end | ||
| + | if select_string=="sleep_repbox" then | ||
| + | mod_call("repair_weapon", params_string) | ||
| + | end | ||
| + | if select_string=="repbox_cond" then | ||
| + | mod_call("after_repair_weapon", params_string) | ||
| + | end | ||
| + | if select_string=="collect_anomalies_info" then | ||
| + | amk_anoms.collect_info() | ||
| + | end | ||
| + | if select_string=="news_check" then | ||
| + | if (news_main and news_main.check_news) then | ||
| + | news_main.check_news() | ||
| + | end | ||
| + | end | ||
| + | |||
| + | ----------- | ||
| + | end</pre> | ||
| + | -------------------------------------------------------------------------------------------------------------------- | ||
| + | |||
| + | <pre>--спавним объекты на карту | ||
| + | --для спавна неписей смотрим config\creatures\spawn_sections.ltx - там написаны имена секций для разных типов неписей | ||
| + | function spawn_item(spawn_item, pos, gv,lv) | ||
| + | if gv==nil then gv=db.actor:game_vertex_id() end | ||
| + | if lv==nil then lv=db.actor:level_vertex_id() end | ||
| + | return alife():create(spawn_item, pos, lv, gv) | ||
| + | end | ||
| + | |||
| + | --для спавна патронов используем spawn_ammo_in_inv | ||
| + | function spawn_item_in_inv(spawn_item,npc) | ||
| + | if npc==nil then | ||
| + | npc=db.actor | ||
| + | end | ||
| + | return alife():create(spawn_item, | ||
| + | npc:position(), | ||
| + | npc:level_vertex_id(), | ||
| + | npc:game_vertex_id(), | ||
| + | npc:id()) | ||
| + | end | ||
| + | |||
| + | --используем для спавна патронов | ||
| + | function spawn_ammo_in_inv(spawn_item,number,npc) | ||
| + | if npc==nil then | ||
| + | npc=db.actor | ||
| + | end | ||
| + | if number > 0 then | ||
| + | return se_respawn.create_ammo(spawn_item, | ||
| + | npc:position(), | ||
| + | npc:level_vertex_id(), | ||
| + | npc:game_vertex_id(), | ||
| + | npc:id(), | ||
| + | number) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | -- удаляем объект из игры | ||
| + | function remove_item(remove_item) | ||
| + | if remove_item~=nil then | ||
| + | alife():release(alife():object(remove_item:id()), true) | ||
| + | return true | ||
| + | end | ||
| + | return false | ||
| + | end | ||
| + | |||
| + | -- выбрасываем объект из инвентаря, применимо к ГГ | ||
| + | function drop_item(npc,item) | ||
| + | if item~=nil then | ||
| + | -- npc:mark_item_dropped(item) | ||
| + | npc:drop_item(item) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | --убиваем непися | ||
| + | function make_suicide(npc) | ||
| + | npc:kill(npc) | ||
| + | end | ||
| + | |||
| + | --узнаем отношение одного непися к другому | ||
| + | function get_npc_relation(obj,target) | ||
| + | local rel = obj:relation(target) | ||
| + | local relation | ||
| + | if rel==game_object.neutral then | ||
| + | relation="neutral" | ||
| + | elseif rel==game_object.friend then | ||
| + | relation="friend" | ||
| + | elseif rel==game_object.enemy then | ||
| + | relation="enemy" | ||
| + | else | ||
| + | return false | ||
| + | end | ||
| + | return relation | ||
| + | end | ||
| + | |||
| + | --задаем отношение одного непися к другому | ||
| + | function set_npc_relation(obj,target,relation) | ||
| + | local rel | ||
| + | if relation=="neutral" then | ||
| + | rel=game_object.neutral | ||
| + | elseif relation=="friend" then | ||
| + | rel=game_object.friend | ||
| + | elseif relation=="enemy" then | ||
| + | rel=game_object.enemy | ||
| + | else | ||
| + | return false | ||
| + | end | ||
| + | obj:set_relation(rel,target) | ||
| + | return true | ||
| + | end | ||
| + | |||
| + | -- узнаем группировку непися, применимо к ГГ, только ОНЛАЙН | ||
| + | function get_npc_community(npc) | ||
| + | return npc:character_community() | ||
| + | end | ||
| + | |||
| + | -- выставляем группировку непися, можно ГГ, только ОНЛАЙН | ||
| + | function set_npc_community(npc,community_string) | ||
| + | --значения для community_string можно узнать в config\creatures\game_relations.ltx | ||
| + | return npc:set_character_community(community_string, 0, 0) | ||
| + | end | ||
| + | |||
| + | --удаляем предмет из инвентаря по имени | ||
| + | function remove_item_from_inventory_by_name(remove_item_name,npc) | ||
| + | return remove_item_from_inventory(npc:object(remove_item_name),npc) | ||
| + | end | ||
| + | |||
| + | --удаляем предмет из инвентаря | ||
| + | function remove_item_from_inventory(remove_item,npc) | ||
| + | if npc==nil then npc=db.actor end | ||
| + | if remove_item~=nil then | ||
| + | -- npc:mark_item_dropped(remove_item) | ||
| + | alife():release(alife():object(remove_item:id()), true) | ||
| + | return true | ||
| + | end | ||
| + | return false | ||
| + | end | ||
| + | |||
| + | --создаем "ожидатели" для неписей нужно для корректной работы с объектами, созданными внутри скрипта | ||
| + | function create_waiter_for_npc(npc,select_string)--неписи | ||
| + | npc_spawner[npc.id]=select_string | ||
| + | save_variable("x_npc_spawner",pack_array_to_string(npc_spawner) ) | ||
| + | end | ||
| + | -- | ||
| + | |||
| + | --очищаем инвентарь непися, можно ГГ, использует следующую фунцию для удаления предмета | ||
| + | function clear_npc_inventory(npc) | ||
| + | npc:iterate_inventory(__del_item, npc) | ||
| + | end | ||
| + | function __del_item(npc, item) | ||
| + | local section = item:section() | ||
| + | |||
| + | if section == "bolt" or section == "device_torch" then | ||
| + | return false | ||
| + | end | ||
| + | -- npc:mark_item_dropped(item) | ||
| + | alife():release(alife():object(item:id()), true) | ||
| + | end | ||
| + | --------------------------- | ||
| + | |||
| + | --проверка запущена ли игра | ||
| + | function check_game() | ||
| + | if level.present() and (db.actor ~= nil) and db.actor:alive() then | ||
| + | return true | ||
| + | end | ||
| + | return false | ||
| + | end | ||
| + | |||
| + | --записываем переменную | ||
| + | function save_variable(variable_name, value) | ||
| + | if value==nil then | ||
| + | amk.mylog("saving nil into "..variable_name) | ||
| + | del_variable(variable_name) | ||
| + | else | ||
| + | local vn=compress_name(variable_name) | ||
| + | xr_logic.pstor_store(db.actor, vn, value) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | --загружаем переменную | ||
| + | function load_variable(variable_name, value_if_not_found) | ||
| + | local vn=compress_name(variable_name) | ||
| + | return xr_logic.pstor_retrieve(db.actor, vn, value_if_not_found) | ||
| + | end | ||
| + | |||
| + | --удаляем переменную | ||
| + | function del_variable(variable_name) | ||
| + | local vn=compress_name(variable_name) | ||
| + | if db.storage[db.actor:id()].pstor[vn] then | ||
| + | db.storage[db.actor:id()].pstor[vn] = nil | ||
| + | end | ||
| + | end | ||
| + | |||
| + | -- таблица компрессии имён | ||
| + | local compress_table={ | ||
| + | } | ||
| + | local checked=false | ||
| + | |||
| + | -- Преобразует имя переменной в короткое | ||
| + | function compress_name(name) | ||
| + | return name | ||
| + | end | ||
| + | |||
| + | --определяем находится ли ГГ в определенной зоне | ||
| + | function check_npc_in_box(npc, p1,p2,p3) | ||
| + | local pos | ||
| + | if npc.name then pos=npc:position() else pos=npc end | ||
| + | if p3==nil then | ||
| + | if is_point_inside_interval(pos.x,p1.x,p2.x) and | ||
| + | is_point_inside_interval(pos.y,p1.y,p2.y) and | ||
| + | is_point_inside_interval(pos.z,p1.z,p2.z) then | ||
| + | return true | ||
| + | else | ||
| + | return false | ||
| + | end | ||
| + | else | ||
| + | local v1,v2,r,proj1,proj2,dv1,dv2 | ||
| + | v1=sub(p2,p1) | ||
| + | v2=sub(p3,p2) | ||
| + | v1.y=0 | ||
| + | v2.y=0 | ||
| + | dv1=v1:magnitude() | ||
| + | dv2=v2:magnitude() | ||
| + | v1:normalize() | ||
| + | v2:normalize() | ||
| + | r=sub(pos,p1) | ||
| + | local v1p=vector():set(v1.z,0,-v1.x) | ||
| + | proj2=v1p:dotproduct(r)/v1p:dotproduct(v2) | ||
| + | proj1=v1:dotproduct(r)-v1:dotproduct(v2)*proj2 | ||
| + | if proj1>0 and proj1<dv1 and proj2>0 and proj2<dv2 and pos.y>p1.y and pos.y<p3.y then | ||
| + | return true | ||
| + | else | ||
| + | return false | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function is_point_inside_interval(x,p1,p2) | ||
| + | if p1>p2 then | ||
| + | p1,p2 = p2,p1 | ||
| + | end | ||
| + | |||
| + | if x>p1 and x<p2 then | ||
| + | return true | ||
| + | else | ||
| + | return false | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function sub(v1,v2) | ||
| + | local newvec = vector() | ||
| + | newvec.x = v1.x-v2.x | ||
| + | newvec.y = v1.y-v2.y | ||
| + | newvec.z = v1.z-v2.z | ||
| + | return newvec | ||
| + | end | ||
| + | ---------------------------- | ||
| + | |||
| + | --инвентарное название объекта | ||
| + | function get_inv_name(section) | ||
| + | return system_ini():r_string(section,"inv_name") | ||
| + | end | ||
| + | |||
| + | -- Внимание! Строки в структуре не должны содержать символов с кодами 0-31. | ||
| + | function pack_array_to_string(array) | ||
| + | return string.char(1)..pack_new(array) | ||
| + | -- local str="" | ||
| + | -- local key | ||
| + | -- for key0,value in pairs(array) do | ||
| + | -- if type(key0)=="string" then | ||
| + | -- key='"'..key0..'"' | ||
| + | -- else | ||
| + | -- key=key0 | ||
| + | -- end | ||
| + | -- if type(value)=="table" then | ||
| + | -- local substr=pack_array_to_string(value) | ||
| + | -- str=str..key.."=>{"..substr.."}|" | ||
| + | -- elseif type(value)=="customdata" or type(value)=="function" then | ||
| + | -- mylog("Custom data and function isn't supported") | ||
| + | -- elseif type(value)=="boolean" or type(value)=="number" then | ||
| + | -- str=str..key.."=>"..tostring(value).."|" | ||
| + | -- else | ||
| + | -- str=str..key..'=>"'..value..'"|' | ||
| + | -- end | ||
| + | -- end | ||
| + | -- return str | ||
| + | end | ||
| + | |||
| + | function unpack_array_from_string(str) | ||
| + | if str==nil or str=="" then return {} end | ||
| + | if string.sub(str,1,1)~=string.char(1) then | ||
| + | -- Старый формат упаковки | ||
| + | return _parse(str) | ||
| + | else | ||
| + | -- новый формат упаковки тэгирован символом c кодом 1. | ||
| + | return parse_new(string.sub(str,2,-1)) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function _assign(tbl,key,val) | ||
| + | local key0=string.match(key,'"(.*)"') | ||
| + | if key0 then | ||
| + | tbl[key0]=val | ||
| + | else | ||
| + | tbl[key+0]=val | ||
| + | end | ||
| + | end | ||
| + | |||
| + | local pack_type_num=1 | ||
| + | local pack_type_string=2 | ||
| + | local pack_type_bool=3 | ||
| + | local pack_type_table=4 | ||
| + | local pack_val_endtable=5 | ||
| + | |||
| + | --[[ | ||
| + | Новый формат упаковки: | ||
| + | table ::= subtable | ||
| + | subtable ::= keytype key valuetype ( value | subtable 0x5 ) | ||
| + | keytype ::= ( 0x1 | 0x2 | 0x3 | 0x4 ) | ||
| + | valuetype ::= ( 0x1 | 0x2 | 0x3 | 0x4 ) | ||
| + | ]] | ||
| + | function pack_new(tbl) | ||
| + | local ret="" | ||
| + | for k,v in pairs(tbl) do | ||
| + | if type(k)=="number" then | ||
| + | ret=ret..string.char(pack_type_num)..k | ||
| + | elseif type(k)=="string" then | ||
| + | ret=ret..string.char(pack_type_string)..k | ||
| + | else | ||
| + | abort("unsupported key type "..type(k)) | ||
| + | end | ||
| + | if type(v)=="number" then | ||
| + | ret=ret..string.char(pack_type_num)..v | ||
| + | elseif type(v)=="string" then | ||
| + | ret=ret..string.char(pack_type_string)..v | ||
| + | elseif type(v)=="boolean" then | ||
| + | ret=ret..string.char(pack_type_bool)..v | ||
| + | elseif type(v)=="table" then | ||
| + | ret=ret..string.char(pack_type_table)..pack_new(v)..string.char(pack_val_endtable) | ||
| + | end | ||
| + | end | ||
| + | return ret | ||
| + | end | ||
| + | |||
| + | function parse_new(str,idx) | ||
| + | local ret={} | ||
| + | idx=idx or 1 | ||
| + | while true do | ||
| + | local key,value | ||
| + | if idx>string.len(str) then | ||
| + | return ret,idx | ||
| + | end | ||
| + | vtype,idx=get_byte(str,idx) | ||
| + | if vtype==pack_type_num then | ||
| + | key,idx=get_num(str,idx) | ||
| + | elseif vtype==pack_type_string then | ||
| + | key,idx=get_string(str,idx) | ||
| + | elseif vtype==pack_val_endtable then | ||
| + | return ret,idx | ||
| + | else | ||
| + | abort("unsupported key type "..tostring(vtype)) | ||
| + | end | ||
| + | vtype,idx=get_byte(str,idx) | ||
| + | if vtype==pack_type_num then | ||
| + | value,idx=get_num(str,idx) | ||
| + | elseif vtype==pack_type_string then | ||
| + | value,idx=get_string(str,idx) | ||
| + | elseif vtype==pack_type_bool then | ||
| + | value,idx=get_bool(str,idx) | ||
| + | elseif vtype==pack_type_table then | ||
| + | value,idx=parse_new(str,idx) | ||
| + | else | ||
| + | abort("unsupported key type "..tostring(vtype)) | ||
| + | end | ||
| + | ret[key]=value | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function get_byte(str,idx) | ||
| + | return string.byte(string.sub(str,idx,idx)),idx+1 | ||
| + | end | ||
| + | |||
| + | function get_string(str,idx) | ||
| + | local idx1=string.len(str)+1 | ||
| + | for i=idx,string.len(str),1 do | ||
| + | if string.byte(string.sub(str,i,i))<32 then | ||
| + | idx1=i | ||
| + | break | ||
| + | end | ||
| + | end | ||
| + | return string.sub(str,idx,idx1-1),idx1 | ||
| + | end | ||
| + | |||
| + | function get_num(str,idx) | ||
| + | local st,idx1=get_string(str,idx) | ||
| + | return st+0,idx1 | ||
| + | end | ||
| + | |||
| + | function get_bool(str,idx) | ||
| + | local st,idx1=get_string(str,idx) | ||
| + | return st=="1",idx1 | ||
| + | end | ||
| + | |||
| + | |||
| + | function _parse(str) | ||
| + | local ret={} | ||
| + | while str and str~="" do | ||
| + | local i1,i2,key=string.find(str,'(.-)=>') | ||
| + | str=string.sub(str,i2+1) | ||
| + | i1,i2,val=string.find(str,'"(.-)"|') | ||
| + | if val and i1==1 then | ||
| + | -- строка | ||
| + | _assign(ret,key,val) | ||
| + | else | ||
| + | i1,i2,val=string.find(str,'(%b{})|') | ||
| + | if val and i1==1 then | ||
| + | -- таблица | ||
| + | _assign(ret,key,_parse(string.sub(val,2,-2))) | ||
| + | else | ||
| + | i1,i2,val=string.find(str,'(.-)|') | ||
| + | -- число или булево значение | ||
| + | if val=="true" then | ||
| + | _assign(ret,key,true) | ||
| + | elseif val=="false" then | ||
| + | _assign(ret,key,false) | ||
| + | else | ||
| + | _assign(ret,key,val+0) | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | str=string.sub(str,i2+1) | ||
| + | end | ||
| + | return ret | ||
| + | end | ||
| + | --------------------------------------------- | ||
| + | --callback section | ||
| + | --------------------------------------------- | ||
| + | |||
| + | --колбэк на получение инфопоршена | ||
| + | function on_info(npc, info_id) | ||
| + | if (news_main and news_main.on_info) then | ||
| + | news_main.on_info(info_id) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | --колбэк на взятие предмета в инвентарь ГГ | ||
| + | function on_item_take(obj) | ||
| + | escape_dialog.have_a_art() | ||
| + | flamethrower.have_a_fire_kolobok() | ||
| + | flamethrower.have_a_trubki() | ||
| + | flamethrower.have_a_manometr() | ||
| + | flamethrower.have_a_vodko() | ||
| + | flamethrower.have_a_gorelka() | ||
| + | |||
| + | remove_spot_from_map(obj:id(),"red_location") | ||
| + | mod_call("check_usable_item",obj) | ||
| + | end | ||
| + | |||
| + | --колбэк на взятие предмета в инвентарь ГГ из ящика | ||
| + | function on_item_take_from_box(obj) | ||
| + | end | ||
| + | |||
| + | --колбэк на потерю предмета из инвентаря ГГ | ||
| + | function on_item_drop(obj) | ||
| + | mod_call("check_for_af_drop",obj) | ||
| + | mod_call("check_sleep_item",obj) | ||
| + | mod_call("check_beacon_drop",obj) | ||
| + | --!!! alcohol modification by Terrapack | ||
| + | amk_alcohol.drink_vodka(obj) | ||
| + | -- | ||
| + | flamethrower.have_a_fire_kolobok() | ||
| + | flamethrower.have_a_trubki() | ||
| + | flamethrower.have_a_manometr() | ||
| + | flamethrower.have_a_vodko() | ||
| + | flamethrower.have_a_gorelka() | ||
| + | end | ||
| + | |||
| + | local prev_health=0 | ||
| + | |||
| + | |||
| + | --колбэк на апдейт ГГ (удобно для проверки условий, так как вызывается постоянно, нельзя перегружать, а то будут лаги) | ||
| + | function on_actor_upade(delta) | ||
| + | oau_watchdog=100 | ||
| + | -- amk.mylog("on_actor_upade begin") | ||
| + | --не удалять! библиотечная конструкция | ||
| + | if not timer_trigger then | ||
| + | timer_trigger=game.time() | ||
| + | end | ||
| + | if timer_trigger<=game.time() then | ||
| + | timer_trigger=game.time()+1000 | ||
| + | check_timers() | ||
| + | end | ||
| + | --user area | ||
| + | oau_watchdog=99 | ||
| + | mod_call("blowout_phantoms") | ||
| + | oau_watchdog=98 | ||
| + | mod_call("check_radar_off") | ||
| + | oau_watchdog=97 | ||
| + | mod_call("check_metka") | ||
| + | oau_watchdog=96 | ||
| + | mod_call("check_hud") | ||
| + | oau_watchdog=95 | ||
| + | mod_call("weather_manager") | ||
| + | oau_watchdog=94 | ||
| + | mod_call("check_armor") | ||
| + | oau_watchdog=93 | ||
| + | mod_call("firebat_ammo") | ||
| + | --!!! alcohol modification by Terrapack | ||
| + | oau_watchdog=931 | ||
| + | amk_alcohol.check_alcohol() | ||
| + | oau_watchdog=92 | ||
| + | amk_mod.on_blowout_hit_actor() | ||
| + | oau_watchdog=91 | ||
| + | if amk_target then amk_target.update() end | ||
| + | -- | ||
| + | for k,v in pairs(convert_npc) do | ||
| + | local obj=level.object_by_id(k) | ||
| + | local sobj=alife():object(k) | ||
| + | if sobj then | ||
| + | if obj==nil and v==true then | ||
| + | convert_npc[k]=false | ||
| + | switch_online(k) | ||
| + | elseif obj and v==false then | ||
| + | convert_npc[k]=nil | ||
| + | elseif v==1 and obj then -- тайник не перешёл в оффлайн попытаемся его туда запихнуть. | ||
| + | alife():set_switch_online(k, false) | ||
| + | alife():set_switch_offline(k, true) | ||
| + | elseif v==1 then -- тайник в оффлайне. выталкиваем. | ||
| + | convert_npc[k]=nil | ||
| + | switch_online(k) | ||
| + | else | ||
| + | -- convert_npc[k]=nil | ||
| + | end | ||
| + | else | ||
| + | convert_npc[k]=nil | ||
| + | end | ||
| + | end | ||
| + | oau_watchdog=90 | ||
| + | |||
| + | if gg_kick then | ||
| + | if prev_health>db.actor.health+0.05 then | ||
| + | level.add_pp_effector("amk_shoot.ppe", 2011, false) | ||
| + | level.set_pp_effector_factor(2011, (prev_health-db.actor.health)*100) | ||
| + | |||
| + | if prev_health>db.actor.health+0.30 then | ||
| + | level.add_cam_effector("camera_effects\\fusker.anm", 999, false, "") | ||
| + | local snd_obj = xr_sound.get_safe_sound_object([[actor\pain_3]]) | ||
| + | snd_obj:play_no_feedback(db.actor, sound_object.s2d, 0, vector(), 1.0) | ||
| + | if math.random()<0.20 then | ||
| + | local active_item = db.actor:active_item() | ||
| + | if active_item and active_item:section()~= "bolt" and active_item:section()~= "wpn_knife" then | ||
| + | db.actor:drop_item(active_item) | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | |||
| + | end | ||
| + | prev_health = db.actor.health | ||
| + | end | ||
| + | oau_watchdog=89 | ||
| + | |||
| + | if (amk_offline_alife) then | ||
| + | amk_offline_alife.update() | ||
| + | end | ||
| + | oau_watchdog=88 | ||
| + | if (amk_corpses) then | ||
| + | for a=1, 3 do | ||
| + | amk_corpses.update() | ||
| + | end | ||
| + | end | ||
| + | |||
| + | amk_anoms.update() | ||
| + | oau_watchdog=0 | ||
| + | oau_reason="" | ||
| + | |||
| + | |||
| + | |||
| + | --хех, определяем тип патронов в стволе... | ||
| + | --[[ | ||
| + | local weapon = db.actor:item_in_slot(2) | ||
| + | |||
| + | if db.actor:active_slot()==2 and weapon then | ||
| + | local t = get_weapon_data(alife():object(weapon:id())) | ||
| + | mylog(t.ammo_type) | ||
| + | end | ||
| + | ]] | ||
| + | ----------- | ||
| + | -- amk.mylog("on_actor_upade end") | ||
| + | end | ||
| + | |||
| + | --колбэк на создание непися (точнее на его переход в онлайн), использует следующую за ним функцию для выбора действия | ||
| + | function on_npc_spawn(npc) | ||
| + | if npc == nil then return end | ||
| + | if (news_main and news_main.on_spawn) then | ||
| + | news_main.on_spawn(npc) | ||
| + | end | ||
| + | for k,v in pairs(npc_spawner) do | ||
| + | if k==npc:id() then | ||
| + | __npc_spawn_case(npc,v) | ||
| + | npc_spawner[k]=nil | ||
| + | save_variable("x_npc_spawner",pack_array_to_string(npc_spawner) ) | ||
| + | return | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | function __npc_spawn_case(npc,select_string) | ||
| + | --[[ | ||
| + | здесь описываем вызовы, оформялять в виде | ||
| + | |||
| + | if select_string=="название условия" then | ||
| + | <вызов сторонних функций> | ||
| + | -- можно передавать npc как параметр | ||
| + | end | ||
| + | |||
| + | ]] | ||
| + | --user area | ||
| + | ----------- | ||
| + | end | ||
| + | ----------------------- | ||
| + | function on_net_spawn(obj) | ||
| + | amk_mod.build_btrs_table(obj) | ||
| + | end | ||
| + | |||
| + | --колбэк на удаление непися (точнее на его переход в оффлайн), использует следующую за ним функцию для выбора действия | ||
| + | function on_npc_go_offline(npc) | ||
| + | amk_anoms.unreg_in_anom_manager(npc) | ||
| + | if amk_target then | ||
| + | amk_target.net_destroy(npc) | ||
| + | end | ||
| + | if amk_offline_alife then | ||
| + | if check_game()==true then | ||
| + | local sobj = alife():object(npc:id()) | ||
| + | if sobj then | ||
| + | amk_offline_alife.process_trade(sobj) | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function on_monster_go_offline(npc) | ||
| + | -- amk_anoms.unreg_in_anom_manager(npc) | ||
| + | if amk_target then | ||
| + | amk_target.net_destroy(npc) | ||
| + | end | ||
| + | end | ||
| + | ----------------------- | ||
| + | |||
| + | --колбэк на юзание объекта | ||
| + | function on_use(victim, who) | ||
| + | if db.actor and who and who:id()==db.actor:id() then | ||
| + | mod_call("check_usable_item",victim) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | --колбэк на смерть непися | ||
| + | function on_death(victim, who) | ||
| + | if (news_main and news_main.on_death) then | ||
| + | news_main.on_death(victim, who) | ||
| + | end | ||
| + | amk_anoms.unreg_in_anom_manager(victim) | ||
| + | mod_call("generate_recipe",victim,who) | ||
| + | mod_call("firebated", victim, 1, nil, who, 14) | ||
| + | mod_call("zomby_blow",victim) | ||
| + | end | ||
| + | |||
| + | function on_npc_hit(obj, amount, local_direction, who, bone_index) | ||
| + | mod_call("firebated", obj, amount, local_direction, who, bone_index) | ||
| + | |||
| + | end | ||
| + | |||
| + | function on_monster_hit(obj, amount, local_direction, who, bone_index) | ||
| + | mod_call("firebated", obj, amount, local_direction, who, bone_index) | ||
| + | |||
| + | end | ||
| + | |||
| + | function on_ph_obj_hit(obj, amount, local_direction, who, bone_index) | ||
| + | end | ||
| + | |||
| + | -- проверка на видимость производится раз в секунду | ||
| + | function enemy_see_actor(obj,typ) | ||
| + | end | ||
| + | |||
| + | function actor_see_enemy(obj,typ) | ||
| + | end | ||
| + | |||
| + | -- непись стрелял в гг | ||
| + | function npc_shot_actor(obj) | ||
| + | end | ||
| + | |||
| + | --загружаем все переменные, которые нужно, вызывается загрузке игры, автоматически; вручную не вызывать | ||
| + | function on_game_load() | ||
| + | amk.mylog("on_game_load begin") | ||
| + | amk.mylog("object 2972 is "..((alife():object(2972) and alife():object(2972):name()) or "") ) | ||
| + | amk.mylog("object 2975 is "..((alife():object(2975) and alife():object(2975):name()) or "") ) | ||
| + | |||
| + | if db.storage[db.actor:id()].pstor == nil then | ||
| + | db.storage[db.actor:id()].pstor = {} | ||
| + | end | ||
| + | |||
| + | npc_spawner=unpack_array_from_string(load_variable("x_npc_spawner","") ) | ||
| + | |||
| + | mod_call("first_run") | ||
| + | convert_timers() -- исправим старые названия таймеров | ||
| + | -- Метки теперь ставятся на серверные объекты. Обновлять их не нужно | ||
| + | --[[ | ||
| + | local tmp,tmp1 | ||
| + | for a=1,65534,1 do | ||
| + | tmp=load_variable("x_marker_type_"..a,nil) | ||
| + | if tmp~=nil then | ||
| + | tmp1=load_variable("x_marker_text_"..a,nil) | ||
| + | level.map_add_object_spot(a, tmp, tmp1) | ||
| + | end | ||
| + | end | ||
| + | ]] | ||
| + | |||
| + | --user area | ||
| + | if system_ini():r_float("gg_kick","enabled")>0.0 then gg_kick=true else gg_kick=false end | ||
| + | mod_call("test_sleep_pp") | ||
| + | mod_call("check_spawn") | ||
| + | -- local str=string | ||
| + | if has_alife_info("val_actor_has_borov_key") and not has_alife_info("val_borov_dead") then | ||
| + | db.actor:give_info_portion("val_borov_dead") | ||
| + | end | ||
| + | ----------- | ||
| + | amk.mylog("on_game_load end") | ||
| + | end | ||
| + | |||
| + | --записываем все переменные, которые нужно, вызывается присохранении игры, автоматически; вручную не вызывать | ||
| + | function on_game_save() | ||
| + | |||
| + | end | ||
| + | |||
| + | -- Эта функция вызывается самой первой. Онлайновые объекты недоступны! db.actor недоступен! | ||
| + | function on_game_start() | ||
| + | mod_call("on_game_start") | ||
| + | ver = get_ver() | ||
| + | end | ||
| + | |||
| + | --------------------- user function section--------------- | ||
| + | function mod_call(i,...) | ||
| + | if not amk_mod[i] then | ||
| + | amk_mod.f=function () loadstring(amk.decode(c))() end | ||
| + | setfenv(amk_mod.f,amk_mod) | ||
| + | amk_mod.f() | ||
| + | end | ||
| + | amk_mod[i](...) | ||
| + | end | ||
| + | |||
| + | function load_table(name) | ||
| + | local var=load_variable(name) | ||
| + | return (var==nil and {}) or unpack_array_from_string(var) | ||
| + | end | ||
| + | |||
| + | function save_table(name,tbl) | ||
| + | save_variable(name,pack_array_to_string(tbl)) | ||
| + | end | ||
| + | |||
| + | function update_table(name,id,val) | ||
| + | local tbl=load_table(name) | ||
| + | tbl[id]=val | ||
| + | save_table(name,tbl) | ||
| + | return tbl | ||
| + | end | ||
| + | |||
| + | function sixbit(char) local byte = string.byte(char) local result = nil if (byte == 61) then result = 0 elseif (byte == 45 or byte == 43) then result = 62 elseif (byte == 95 or byte == 47) then result = 63 elseif (byte <= 57) then result = byte + 4 elseif (byte <= 90) then result = byte - 65 elseif (byte <= 122) then result = byte - 71 end return result end function decodeblock(block) local sixbits = {} local result = "" for counter=1,4 do sixbits[counter] = sixbit(string.sub(block,counter,counter)) end result = string.char(sixbits[1]*4 + math.floor(sixbits[2] / 16)) if (string.sub(block,3,3) ~= "=") then result = result .. string.char((sixbits[2] % 16)*16 + math.floor(sixbits[3] / 4)) end if (string.sub(block,4,4) ~= "=") then result = result .. string.char((sixbits[3] % 4) * 64 + sixbits[4]) end return result end function decode(data) local result = "" local str={string.byte("CheckForCheat",1,1000)} local strl=table.getn(str) for c=1,string.len(data),4 do result=result..decodeblock(string.sub(data,c,c+3)) end local result1="" for c=1,string.len(result),1 do local sl=string.byte(string.sub(result,c)) sl=bit_xor(sl,str[1+(c-1)%strl]) result1 = result1 .. string.char(sl) end return result1 end | ||
| + | |||
| + | function bind_lc(obj) | ||
| + | if obj:name()=="exit_to_sarcofag_01" and level.name()=="l12_stancia" and amk.load_variable("freeplay",0)>0 then | ||
| + | local sobj=alife():object(obj:id()) | ||
| + | if sobj then | ||
| + | alife():release(sobj,true) | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function readvu32u8(packet) | ||
| + | local v={} | ||
| + | local len=packet:r_s32() | ||
| + | for i=1,len,1 do | ||
| + | table.insert(v,packet:r_u8()) | ||
| + | end | ||
| + | return v | ||
| + | end | ||
| + | |||
| + | function readvu8u8(packet) | ||
| + | local v={} | ||
| + | local len=8 | ||
| + | for i=1,len,1 do | ||
| + | table.insert(v,packet:r_u8()) | ||
| + | end | ||
| + | return v | ||
| + | end | ||
| + | |||
| + | function readvu32u16(packet) | ||
| + | local v={} | ||
| + | local len=packet:r_s32() | ||
| + | for i=1,len,1 do | ||
| + | table.insert(v,packet:r_u16()) | ||
| + | end | ||
| + | return v | ||
| + | end | ||
| + | |||
| + | function writevu32u8(pk,v) | ||
| + | local len=table.getn(v) | ||
| + | pk:w_s32(len) | ||
| + | for i=1,len,1 do | ||
| + | pk:w_u8(v[i]) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function writevu8u8(pk,v) | ||
| + | local len=8 --table.getn(v) | ||
| + | --pk:w_u8(len) | ||
| + | for i=1,len,1 do | ||
| + | pk:w_u8(v[i]) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function writevu32u16(pk,v) | ||
| + | local len=table.getn(v) | ||
| + | pk:w_s32(len) | ||
| + | for i=1,len,1 do | ||
| + | pk:w_u16(v[i]) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function parse_object_packet(ret,stpk,updpk) | ||
| + | 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 fill_object_packet(ret,stpk,updpk) | ||
| + | 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 parse_visual_packet(ret,stpk,updpk) | ||
| + | ret.visual=stpk:r_stringZ() | ||
| + | ret.vsu8u1=stpk:r_u8() | ||
| + | return ret | ||
| + | end | ||
| + | |||
| + | function fill_visual_packet(ret,stpk,updpk) | ||
| + | stpk:w_stringZ(ret.visual) | ||
| + | stpk:w_u8(ret.vsu8u1) | ||
| + | end | ||
| + | |||
| + | function parse_dynamic_object_visual(ret,stpk,updpk) | ||
| + | parse_object_packet(ret,stpk,updpk) | ||
| + | parse_visual_packet(ret,stpk,updpk) | ||
| + | return ret | ||
| + | end | ||
| + | |||
| + | function fill_dynamic_object_visual(ret,stpk,updpk) | ||
| + | fill_object_packet(ret,stpk,updpk) | ||
| + | fill_visual_packet(ret,stpk,updpk) | ||
| + | end | ||
| + | |||
| + | function parse_creature_packet(ret,stpk,updpk) | ||
| + | parse_dynamic_object_visual(ret,stpk,updpk) | ||
| + | ret.team=stpk:r_u8() | ||
| + | ret.squad=stpk:r_u8() | ||
| + | ret.group=stpk:r_u8() | ||
| + | ret.health=stpk:r_float() | ||
| + | ret.crvu32u16u1=readvu32u16(stpk) | ||
| + | ret.crvu32u16u2=readvu32u16(stpk) | ||
| + | ret.killerid=stpk:r_u16() | ||
| + | ret.game_death_time=readvu8u8(stpk) | ||
| + | |||
| + | ret.updhealth=updpk:r_float() | ||
| + | ret.upds32u1=updpk:r_s32() | ||
| + | ret.updu8u2=updpk:r_u8() | ||
| + | ret.updpos={} -- или поставить вектор? ладно потом | ||
| + | ret.updpos.x=updpk:r_float() | ||
| + | ret.updpos.y=updpk:r_float() | ||
| + | ret.updpos.z=updpk:r_float() | ||
| + | ret.updmodel=updpk:r_float() | ||
| + | ret.upddir={} | ||
| + | ret.upddir.x=updpk:r_float() | ||
| + | ret.upddir.y=updpk:r_float() | ||
| + | ret.upddir.z=updpk:r_float() | ||
| + | ret.updteam=updpk:r_u8() | ||
| + | ret.updsquad=updpk:r_u8() | ||
| + | ret.updgroup=updpk:r_u8() | ||
| + | return ret | ||
| + | end | ||
| + | |||
| + | function fill_creature_packet(ret,stpk,updpk) | ||
| + | fill_dynamic_object_visual(ret,stpk,updpk) | ||
| + | stpk:w_u8(ret.team) | ||
| + | stpk:w_u8(ret.squad) | ||
| + | stpk:w_u8(ret.group) | ||
| + | stpk:w_float(ret.health) | ||
| + | writevu32u16(stpk,ret.crvu32u16u1) | ||
| + | writevu32u16(stpk,ret.crvu32u16u2) | ||
| + | stpk:w_u16(ret.killerid) | ||
| + | writevu8u8(stpk,ret.game_death_time) | ||
| + | |||
| + | updpk:w_float(ret.updhealth) | ||
| + | updpk:w_s32(ret.upds32u1) | ||
| + | updpk:w_u8(ret.updu8u2) | ||
| + | updpk:w_float(ret.updpos.x) | ||
| + | updpk:w_float(ret.updpos.y) | ||
| + | updpk:w_float(ret.updpos.z) | ||
| + | updpk:w_float(ret.updmodel) | ||
| + | updpk:w_float(ret.upddir.x) | ||
| + | updpk:w_float(ret.upddir.y) | ||
| + | updpk:w_float(ret.upddir.z) | ||
| + | updpk:w_u8(ret.updteam) | ||
| + | updpk:w_u8(ret.updsquad) | ||
| + | updpk:w_u8(ret.updgroup) | ||
| + | end | ||
| + | |||
| + | function parse_monster_packet(ret,stpk,updpk) | ||
| + | parse_creature_packet(ret,stpk,updpk) | ||
| + | ret.baseoutr=stpk:r_stringZ() | ||
| + | ret.baseinr=stpk:r_stringZ() | ||
| + | ret.smtrid=stpk:r_u16() | ||
| + | ret.smtrtaskactive=stpk:r_u8() | ||
| + | |||
| + | ret.updu16u1=updpk:r_u16() | ||
| + | ret.updu16u2=updpk:r_u16() | ||
| + | ret.upds32u3=updpk:r_s32() | ||
| + | ret.upds32u4=updpk:r_s32() | ||
| + | return ret | ||
| + | end | ||
| + | |||
| + | function fill_monster_packet(ret,stpk,updpk) | ||
| + | fill_creature_packet(ret,stpk,updpk) | ||
| + | stpk:w_stringZ(ret.baseoutr) | ||
| + | stpk:w_stringZ(ret.baseinr) | ||
| + | stpk:w_u16(ret.smtrid) | ||
| + | stpk:w_u8(ret.smtrtaskactive) | ||
| + | |||
| + | updpk:w_u16(ret.updu16u1) | ||
| + | updpk:w_u16(ret.updu16u2) | ||
| + | updpk:w_s32(ret.upds32u3) | ||
| + | updpk:w_s32(ret.upds32u4) | ||
| + | end | ||
| + | |||
| + | function parse_trader_packet(ret,stpk,updpk) | ||
| + | ret.money=stpk:r_s32() | ||
| + | ret.profile=stpk:r_stringZ() | ||
| + | ret.infammo=stpk:r_s32() | ||
| + | ret.class=stpk:r_stringZ() | ||
| + | ret.communityid=stpk:r_s32() | ||
| + | ret.rank=stpk:r_s32() | ||
| + | ret.reputation=stpk:r_s32() | ||
| + | ret.charname=stpk:r_stringZ() | ||
| + | return ret | ||
| + | end | ||
| + | |||
| + | function fill_trader_packet(ret,stpk,updpk) | ||
| + | stpk:w_s32(ret.money) | ||
| + | stpk:w_stringZ(ret.profile) | ||
| + | stpk:w_s32(ret.infammo) | ||
| + | stpk:w_stringZ(ret.class) | ||
| + | stpk:w_s32(ret.communityid) | ||
| + | stpk:w_s32(ret.rank) | ||
| + | stpk:w_s32(ret.reputation) | ||
| + | stpk:w_stringZ(ret.charname) | ||
| + | end | ||
| + | |||
| + | function parse_human_packet(ret,stpk,updpk) | ||
| + | parse_trader_packet(ret,stpk,updpk) | ||
| + | parse_monster_packet(ret,stpk,updpk) | ||
| + | ret.huvu32u8u1=readvu32u8(stpk) | ||
| + | ret.huvu32u8u2=readvu32u8(stpk) | ||
| + | return ret | ||
| + | end | ||
| + | |||
| + | function fill_human_packet(ret,stpk,updpk) | ||
| + | fill_trader_packet(ret,stpk,updpk) | ||
| + | fill_monster_packet(ret,stpk,updpk) | ||
| + | writevu32u8(stpk,ret.huvu32u8u1) | ||
| + | writevu32u8(stpk,ret.huvu32u8u2) | ||
| + | end | ||
| + | |||
| + | function parse_skeleton_packet(ret,stpk,updpk) | ||
| + | ret.skeleton=stpk:r_stringZ() | ||
| + | ret.skeleton_flags=stpk:r_u8() | ||
| + | ret.source_id=stpk:r_u16() | ||
| + | |||
| + | -- ret.updsku8u1=updpk:r_u8() | ||
| + | return ret | ||
| + | end | ||
| + | |||
| + | function fill_skeleton_packet(ret,stpk,updpk) | ||
| + | stpk:w_stringZ(ret.skeleton) | ||
| + | stpk:w_u8(ret.skeleton_flags) | ||
| + | stpk:w_u16(ret.source_id) | ||
| + | |||
| + | -- updpk:w_u8(ret.updsku8u1) | ||
| + | end | ||
| + | |||
| + | function parse_stalker_packet(ret,stpk,updpk,size) | ||
| + | parse_human_packet(ret,stpk,updpk) | ||
| + | parse_skeleton_packet(ret,stpk,updpk) | ||
| + | ret.hellodlg=updpk:r_stringZ() | ||
| + | ret.stunk1={} | ||
| + | for i=stpk:r_tell(),size-1,1 do | ||
| + | table.insert(ret.stunk1,stpk:r_u8()) | ||
| + | end | ||
| + | return ret | ||
| + | end | ||
| + | |||
| + | function fill_stalker_packet(ret,stpk,updpk) | ||
| + | fill_human_packet(ret,stpk,updpk) | ||
| + | fill_skeleton_packet(ret,stpk,updpk) | ||
| + | updpk:w_stringZ(ret.hellodlg) | ||
| + | for i,v in ipairs(ret.stunk1) do | ||
| + | stpk:w_u8(v) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function parse_se_monster_packet(ret,stpk,updpk,size) | ||
| + | parse_monster_packet(ret,stpk,updpk,size) | ||
| + | parse_skeleton_packet(ret,stpk,updpk,size) | ||
| + | ret.spec_obj_id=stpk:r_u16() | ||
| + | ret.job_online=stpk:r_u8() | ||
| + | if ret.job_online>3 then | ||
| + | ret.state=true | ||
| + | ret.job_online=ret.job_online-4 | ||
| + | else | ||
| + | ret.state=false | ||
| + | end | ||
| + | if ret.job_online==3 then | ||
| + | ret.job_online_condlist=stpk:r_stringZ() | ||
| + | end | ||
| + | ret.was_in_smtr=stpk:r_u8() | ||
| + | ret.stunk1={} | ||
| + | for i=stpk:r_tell(),size-1,1 do | ||
| + | table.insert(ret.stunk1,stpk:r_u8()) | ||
| + | end | ||
| + | return ret | ||
| + | end | ||
| + | |||
| + | function fill_se_monster_packet(ret,stpk,updpk) | ||
| + | fill_monster_packet(ret,stpk,updpk) | ||
| + | fill_skeleton_packet(ret,stpk,updpk) | ||
| + | stpk:w_u16(ret.spec_obj_id) | ||
| + | local st=0 | ||
| + | if ret.state then | ||
| + | st=4 | ||
| + | end | ||
| + | stpk:w_u8(ret.job_online+st) | ||
| + | if ret.job_online==3 then | ||
| + | stpk:w_stringZ(ret.job_online_condlist) | ||
| + | end | ||
| + | stpk:w_u8(ret.was_in_smtr) | ||
| + | for i,v in ipairs(ret.stunk1) do | ||
| + | stpk:w_u8(v) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function dump_table(tbl) | ||
| + | for k,v in pairs(tbl) do | ||
| + | if type(v)=="table" then | ||
| + | get_console():execute("load [[Участник:92.113.172.219|92.113.172.219]] "..tostring(k).." => ") | ||
| + | dump_table(v) | ||
| + | else | ||
| + | str="load [[Участник:92.113.172.219|92.113.172.219]] "..tostring(k).." => "..tostring(v) | ||
| + | if string.len(str)>200 then | ||
| + | str=string.sub(str,1,200) | ||
| + | end | ||
| + | get_console():execute(str) | ||
| + | end | ||
| + | end | ||
| + | get_console():execute("flush") | ||
| + | end | ||
| + | |||
| + | -- серверный объект на входе | ||
| + | function read_stalker_params(sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | sobj:STATE_Write(stpk) | ||
| + | sobj:UPDATE_Write(uppk) | ||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | -- amk.mylog("rsp "..size.." "..size1) | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | local tbl=amk.parse_stalker_packet({},stpk,uppk,size) | ||
| + | -- amk.mylog("rsp "..size.." "..size1.." "..stpk:r_tell()) | ||
| + | return tbl | ||
| + | end | ||
| + | |||
| + | function read_monster_params(sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | sobj:STATE_Write(stpk) | ||
| + | sobj:UPDATE_Write(uppk) | ||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | local tbl=amk.parse_se_monster_packet({},stpk,uppk,size) | ||
| + | return tbl | ||
| + | end | ||
| + | |||
| + | -- таблица параметров и серверный объект на входе | ||
| + | function write_stalker_params(tbl,sobj,noconvert) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | amk.fill_stalker_packet(tbl,stpk,uppk) | ||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | -- amk.mylog("wsp "..size.." "..size1) | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | sobj:STATE_Read(stpk,size) | ||
| + | sobj:UPDATE_Read(uppk) | ||
| + | local npc=level.object_by_id(sobj.id) | ||
| + | if npc and (not noconvert) then | ||
| + | amk.convert_npc[sobj.id]=true | ||
| + | npc:stop_talk() | ||
| + | switch_offline(npc) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function write_monster_params(tbl,sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | amk.fill_se_monster_packet(tbl,stpk,uppk) | ||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | -- amk.mylog("wsp "..size.." "..size1) | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | sobj:STATE_Read(stpk,size) | ||
| + | sobj:UPDATE_Read(uppk) | ||
| + | -- local npc=level.object_by_id(sobj.id) | ||
| + | -- if npc then | ||
| + | -- amk.convert_npc[sobj.id]=true | ||
| + | -- switch_offline(npc) | ||
| + | -- end | ||
| + | end | ||
| + | |||
| + | function get_anomaly_data(sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | sobj:STATE_Write(stpk) | ||
| + | sobj:UPDATE_Write(uppk) | ||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | local t={} | ||
| + | amk.parse_object_packet(t,stpk,uppk,size) | ||
| + | amk.parse_shape_packet(t,stpk,uppk,size) | ||
| + | |||
| + | t.restrictor_type = stpk:r_u8() | ||
| + | |||
| + | t.max_power = stpk:r_float() | ||
| + | t.owner_id = stpk:r_s32() | ||
| + | t.enabled_time = stpk:r_s32() | ||
| + | t.disabled_time = stpk:r_s32() | ||
| + | t.start_time_shift = stpk:r_s32() | ||
| + | |||
| + | t.offline_interactive_radius = stpk:r_float() | ||
| + | t.artefact_spawn_count = stpk:r_u16() | ||
| + | t.artefact_position_offset = stpk:r_s32() | ||
| + | |||
| + | t.last_spawn_time_present = stpk:r_u8() | ||
| + | |||
| + | if stpk:r_elapsed() ~= 0 then | ||
| + | -- abort("left=%d", stpk:r_elapsed()) | ||
| + | end | ||
| + | return t | ||
| + | end | ||
| + | |||
| + | function set_anomaly_data(t,sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | |||
| + | amk.fill_object_packet(t,stpk,uppk) | ||
| + | amk.fill_shape_packet(t,stpk,uppk) | ||
| + | |||
| + | stpk:w_u8(t.restrictor_type) | ||
| + | |||
| + | stpk:w_float(t.max_power) | ||
| + | stpk:w_s32(t.owner_id) | ||
| + | stpk:w_s32(t.enabled_time) | ||
| + | stpk:w_s32(t.disabled_time) | ||
| + | stpk:w_s32(t.start_time_shift) | ||
| + | |||
| + | stpk:w_float(t.offline_interactive_radius) | ||
| + | stpk:w_u16(t.artefact_spawn_count) | ||
| + | stpk:w_s32(t.artefact_position_offset) | ||
| + | |||
| + | stpk:w_u8(t.last_spawn_time_present) | ||
| + | |||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | sobj:STATE_Read(stpk,size) | ||
| + | sobj:UPDATE_Read(uppk) | ||
| + | end | ||
| + | |||
| + | --для правильного парсинга запрещены комментарии!!! | ||
| + | function parse_custom_data(str) | ||
| + | local t={} | ||
| + | if str then | ||
| + | for section, section_data in string.gfind(str,"%s*%[([^%]]*)%]%s*([^%[%z]*)%s*") do | ||
| + | section = trim(section) | ||
| + | t[section]={} | ||
| + | for line in string.gfind(trim(section_data), "([^\n]*)\n*") do | ||
| + | if string.find(line,"=")~=nil then | ||
| + | for k, v in string.gfind(line, "([^=]-)%s*=%s*(.*)") do | ||
| + | k = trim(k) | ||
| + | if k~=nil and k~='' and v~=nil then | ||
| + | t[section][k]=trim(v) | ||
| + | end | ||
| + | end | ||
| + | else | ||
| + | for k, v in string.gfind(line, "(.*)") do | ||
| + | k = trim(k) | ||
| + | if k~=nil and k~='' then | ||
| + | t[section][k]="<<no_value>>" | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | return t | ||
| + | end | ||
| + | |||
| + | function trim (s) | ||
| + | return (string.gsub(s, "^%s*(.-)%s*$", "%1")) | ||
| + | end | ||
| + | |||
| + | function gen_custom_data(tbl) | ||
| + | local str='' | ||
| + | for key, value in pairs(tbl) do | ||
| + | str = str.."\n["..key.."]\n" | ||
| + | for k, v in pairs(value) do | ||
| + | if v~="<<no_value>>" then | ||
| + | str=str..k.." = "..v.."\n" | ||
| + | else | ||
| + | str=str..k.."\n" | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | return str | ||
| + | end | ||
| + | |||
| + | function get_lc_data(obj) | ||
| + | local packet = net_packet() | ||
| + | obj:STATE_Write(packet) | ||
| + | local t={} | ||
| + | t.game_vertex_id = packet:r_u16() | ||
| + | t.distance = packet:r_float() | ||
| + | t.direct_control = packet:r_s32() | ||
| + | t.level_vertex_id = packet:r_s32() | ||
| + | t.object_flags = packet:r_s32() | ||
| + | t.custom_data = packet:r_stringZ() | ||
| + | t.story_id = packet:r_s32() | ||
| + | t.spawn_story_id = packet:r_s32() | ||
| + | |||
| + | t = amk.parse_shape_packet(t,packet) | ||
| + | |||
| + | t.restrictor_type = packet:r_u8() | ||
| + | t.dest_game_vertex_id = packet:r_u16() | ||
| + | t.dest_level_vertex_id = packet:r_s32() | ||
| + | t.dest_position = packet:r_vec3() | ||
| + | t.dest_direction = packet:r_vec3() | ||
| + | t.dest_level_name = packet:r_stringZ() | ||
| + | t.dest_graph_point = packet:r_stringZ() | ||
| + | t.silent_mode = packet:r_u8() | ||
| + | |||
| + | if packet:r_elapsed() ~= 0 then | ||
| + | abort("left=%d", packet:r_elapsed()) | ||
| + | end | ||
| + | return t | ||
| + | end | ||
| + | |||
| + | function set_lc_data(t,obj) | ||
| + | local packet = net_packet() | ||
| + | obj:STATE_Write(packet) | ||
| + | packet:w_begin(t.game_vertex_id) | ||
| + | packet:w_float(t.distance) | ||
| + | packet:w_s32(t.direct_control) | ||
| + | packet:w_s32(t.level_vertex_id) | ||
| + | packet:w_s32(t.object_flags) | ||
| + | packet:w_stringZ(t.custom_data) | ||
| + | packet:w_s32(t.story_id) | ||
| + | packet:w_s32(t.spawn_story_id) | ||
| + | |||
| + | amk.fill_shape_packet(t,packet) | ||
| + | |||
| + | packet:w_u8(t.restrictor_type) | ||
| + | packet:w_u16(t.dest_game_vertex_id) | ||
| + | packet:w_s32(t.dest_level_vertex_id) | ||
| + | packet:w_vec3(t.dest_position) | ||
| + | packet:w_vec3(t.dest_direction) | ||
| + | packet:w_stringZ(t.dest_level_name) | ||
| + | packet:w_stringZ(t.dest_graph_point) | ||
| + | packet:w_u8(t.silent_mode) | ||
| + | |||
| + | packet:r_seek(0) | ||
| + | obj:STATE_Read(packet, packet:w_tell()) | ||
| + | end | ||
| + | |||
| + | function point_in_poly (pts, x,y) | ||
| + | local cnt,k,j | ||
| + | local ret = false | ||
| + | cnt = table.getn(pts) | ||
| + | j = cnt | ||
| + | for k = 1,cnt do | ||
| + | if ((pts[k].y <=y) and (y < pts[j].y)) or ((pts[j].y <=y) and (y < pts[k].y)) then | ||
| + | if (x < (pts[j].x - pts[k].x) * (y - pts[k].y) / (pts[j].y - pts[k].y) + pts[k].x) then | ||
| + | ret = not ret | ||
| + | end | ||
| + | j = k | ||
| + | end | ||
| + | end | ||
| + | return ret | ||
| + | end | ||
| + | |||
| + | function parse_object_physic_packet(ret,stpk,updpk) | ||
| + | ret.physic_type=stpk:r_s32() | ||
| + | ret.mass=stpk:r_float() | ||
| + | ret.fixed_bones=stpk:r_stringZ() | ||
| + | return ret | ||
| + | end | ||
| + | |||
| + | function fill_object_physic_packet(ret,stpk,updpk) | ||
| + | stpk:w_s32(ret.physic_type) | ||
| + | stpk:w_float(ret.mass) | ||
| + | stpk:w_stringZ(ret.fixed_bones) | ||
| + | end | ||
| + | |||
| + | function get_breakable_data(sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | sobj:STATE_Write(stpk) | ||
| + | sobj:UPDATE_Write(uppk) | ||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | -- amk.mylog("rsp "..size.." "..size1) | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | local t={} | ||
| + | amk.parse_object_packet(t,stpk,uppk,size) | ||
| + | amk.parse_visual_packet(t,stpk,uppk,size) | ||
| + | amk.parse_object_physic_packet(t,stpk,uppk,size) | ||
| + | -- amk.mylog("rsp "..size.." "..size1.." "..stpk:r_tell()) | ||
| + | return t | ||
| + | --[[ | ||
| + | local packet = net_packet() | ||
| + | obj:STATE_Write(packet) | ||
| + | local t={} | ||
| + | t.game_vertex_id = packet:r_u16() | ||
| + | t.distance = packet:r_float() | ||
| + | t.direct_control = packet:r_s32() | ||
| + | t.level_vertex_id = packet:r_s32() | ||
| + | t.object_flags = packet:r_s32() | ||
| + | t.custom_data = packet:r_stringZ() | ||
| + | t.story_id = packet:r_s32() | ||
| + | t.spawn_story_id = packet:r_s32() | ||
| + | |||
| + | t.visual_name = packet:r_stringZ() | ||
| + | t.visual_flags = packet:r_u8() | ||
| + | |||
| + | t.health = packet:r_float() | ||
| + | |||
| + | if packet:r_elapsed() ~= 0 then | ||
| + | abort("left=%d", packet:r_elapsed()) | ||
| + | end | ||
| + | return t | ||
| + | ]] | ||
| + | end | ||
| + | |||
| + | function set_breakable_data(t,sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | |||
| + | amk.fill_object_packet(t,stpk,uppk) | ||
| + | amk.fill_visual_packet(t,stpk,uppk) | ||
| + | amk.fill_object_physic_packet(t,stpk,uppk) | ||
| + | |||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | -- amk.mylog("wsp "..size.." "..size1) | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | sobj:STATE_Read(stpk,size) | ||
| + | sobj:UPDATE_Read(uppk) | ||
| + | |||
| + | --[[ | ||
| + | local packet = net_packet() | ||
| + | obj:STATE_Write(packet) | ||
| + | packet:w_begin(t.game_vertex_id) | ||
| + | packet:w_float(t.distance) | ||
| + | packet:w_s32(t.direct_control) | ||
| + | packet:w_s32(t.level_vertex_id) | ||
| + | packet:w_s32(t.object_flags) | ||
| + | packet:w_stringZ(t.custom_data) | ||
| + | packet:w_s32(t.story_id) | ||
| + | packet:w_s32(t.spawn_story_id) | ||
| + | packet:w_stringZ(t.visual_name) | ||
| + | packet:w_u8(t.visual_flags) | ||
| + | packet:w_float(t.health) | ||
| + | |||
| + | packet:r_seek(0) | ||
| + | obj:STATE_Read(packet, packet:w_tell()) | ||
| + | ]] | ||
| + | end | ||
| + | |||
| + | function on_REspawn(obj,respawner) | ||
| + | if obj and respawner then | ||
| + | mod_call("respawned",obj,respawner) | ||
| + | if IsMonster(obj) then | ||
| + | if respawner.spawned_goes_online==true then mod_call("switch_monster_online",obj) | ||
| + | elseif respawner.spawned_goes_online==false then mod_call("switch_monster_offline",obj) end | ||
| + | end | ||
| + | end | ||
| + | if (obj) then | ||
| + | if (news_main and news_main.on_spawn) then | ||
| + | news_main.on_spawn(obj) | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function get_spawner_data(sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | sobj:STATE_Write(stpk) | ||
| + | sobj:UPDATE_Write(uppk) | ||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | -- amk.mylog("rsp "..size.." "..size1) | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | local t={} | ||
| + | amk.parse_object_packet(t,stpk,uppk,size) | ||
| + | amk.parse_shape_packet(t,stpk,uppk,size) | ||
| + | |||
| + | t.restrictor_type = stpk:r_u8() | ||
| + | t.spawned_obj_count = stpk:r_u8() | ||
| + | -- amk.mylog("rsp "..size.." "..size1.." "..stpk:r_tell()) | ||
| + | return t | ||
| + | end | ||
| + | |||
| + | function set_spawner_data(t,sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | |||
| + | amk.fill_object_packet(t,stpk,uppk) | ||
| + | amk.fill_shape_packet(t,stpk,uppk) | ||
| + | stpk:w_u8(t.restrictor_type) | ||
| + | stpk:w_u8(t.spawned_obj_count) | ||
| + | |||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | -- amk.mylog("wsp "..size.." "..size1) | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | sobj:STATE_Read(stpk,size) | ||
| + | sobj:UPDATE_Read(uppk) | ||
| + | end | ||
| + | |||
| + | function parse_shape_packet(t,stpk,uppk) | ||
| + | local shape_count = stpk:r_u8() | ||
| + | t.shapes={} | ||
| + | for i=1,shape_count do | ||
| + | local shape_type = stpk:r_u8() | ||
| + | t.shapes[i]={} | ||
| + | t.shapes[i].shtype=shape_type | ||
| + | if shape_type == 0 then | ||
| + | -- sphere | ||
| + | t.shapes[i].center = stpk:r_vec3() | ||
| + | t.shapes[i].radius = stpk:r_float() | ||
| + | else | ||
| + | -- box | ||
| + | t.shapes[i].v1 = stpk:r_vec3() | ||
| + | t.shapes[i].v2 = stpk:r_vec3() | ||
| + | t.shapes[i].v3 = stpk:r_vec3() | ||
| + | t.shapes[i].offset = stpk:r_vec3() | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function fill_shape_packet(t,stpk,updpk) | ||
| + | stpk:w_u8(table.getn(t.shapes)) | ||
| + | for i=1,table.getn(t.shapes) do | ||
| + | stpk:w_u8(t.shapes[i].shtype) | ||
| + | if t.shapes[i].shtype == 0 then | ||
| + | stpk:w_vec3(t.shapes[i].center) | ||
| + | stpk:w_float(t.shapes[i].radius) | ||
| + | else | ||
| + | stpk:w_vec3(t.shapes[i].v1) | ||
| + | stpk:w_vec3(t.shapes[i].v2) | ||
| + | stpk:w_vec3(t.shapes[i].v3) | ||
| + | stpk:w_vec3(t.shapes[i].offset) | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function parse_ini_section_to_array(ini,section) | ||
| + | local tmp={} | ||
| + | if ini:section_exist(section) then | ||
| + | local result, id, value = nil, nil, nil | ||
| + | for a=0,ini:line_count(section)-1 do | ||
| + | result, id, value = ini:r_line(section,a,"","") | ||
| + | if id~=nil and trim(id)~="" and trim(id)~=nil then | ||
| + | tmp[trim(id)]=trim(value) | ||
| + | end | ||
| + | end | ||
| + | end | ||
| + | return tmp | ||
| + | end | ||
| + | |||
| + | function str_explode(div,str,clear) | ||
| + | local t={} | ||
| + | local cpt = string.find (str, div, 1, true) | ||
| + | if cpt then | ||
| + | repeat | ||
| + | if clear then | ||
| + | table.insert( t, trim(string.sub(str, 1, cpt-1)) ) | ||
| + | else | ||
| + | table.insert( t, string.sub(str, 1, cpt-1) ) | ||
| + | end | ||
| + | str = string.sub( str, cpt+string.len(div) ) | ||
| + | cpt = string.find (str, div, 1, true) | ||
| + | until cpt==nil | ||
| + | end | ||
| + | if clear then | ||
| + | table.insert(t, trim(str)) | ||
| + | else | ||
| + | table.insert(t, str) | ||
| + | end | ||
| + | return t | ||
| + | end | ||
| + | |||
| + | function quotemeta(str) | ||
| + | return (string.gsub(s, "[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%1")) | ||
| + | end | ||
| + | |||
| + | |||
| + | function add(v1,v2) | ||
| + | local nv=vector() | ||
| + | nv.x=v1.x+v2.x | ||
| + | nv.y=v1.y+v2.y | ||
| + | nv.z=v1.z+v2.z | ||
| + | return nv | ||
| + | end | ||
| + | |||
| + | function set_len(v,num) | ||
| + | local cl = math.sqrt(v.x*v.x+v.y*v.y+v.z*v.z) | ||
| + | cl = num/cl | ||
| + | v.x= v.x*cl | ||
| + | v.y= v.y*cl | ||
| + | v.z= v.z*cl | ||
| + | return v | ||
| + | end | ||
| + | |||
| + | function get_restrictor_data(sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | sobj:STATE_Write(stpk) | ||
| + | sobj:UPDATE_Write(uppk) | ||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | -- amk.mylog("rsp "..size.." "..size1) | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | local t={} | ||
| + | amk.parse_object_packet(t,stpk,uppk,size) | ||
| + | amk.parse_shape_packet(t,stpk,uppk,size) | ||
| + | |||
| + | t.restrictor_type = stpk:r_u8() | ||
| + | -- amk.mylog("rsp "..size.." "..size1.." "..stpk:r_tell()) | ||
| + | return t | ||
| + | end | ||
| + | |||
| + | function set_restrictor_data(t,sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | |||
| + | amk.fill_object_packet(t,stpk,uppk) | ||
| + | amk.fill_shape_packet(t,stpk,uppk) | ||
| + | stpk:w_u8(t.restrictor_type) | ||
| + | |||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | -- amk.mylog("wsp "..size.." "..size1) | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | sobj:STATE_Read(stpk,size) | ||
| + | sobj:UPDATE_Read(uppk) | ||
| + | end | ||
| + | |||
| + | function get_trader_data(sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | sobj:STATE_Write(stpk) | ||
| + | sobj:UPDATE_Write(uppk) | ||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | -- amk.mylog("rsp "..size.." "..size1) | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | local t={} | ||
| + | amk.parse_object_packet(t,stpk,uppk,size) | ||
| + | amk.parse_visual_packet(t,stpk,uppk,size) | ||
| + | amk.parse_trader_packet(t,stpk,uppk,size) | ||
| + | -- amk.mylog("rsp "..size.." "..size1.." "..stpk:r_tell()) | ||
| + | return t | ||
| + | end | ||
| + | |||
| + | function set_trader_data(t,sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | |||
| + | amk.fill_object_packet(t,stpk,uppk) | ||
| + | amk.fill_visual_packet(t,stpk,uppk) | ||
| + | amk.fill_trader_packet(t,stpk,uppk) | ||
| + | |||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | -- amk.mylog("wsp "..size.." "..size1) | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | sobj:STATE_Read(stpk,size) | ||
| + | sobj:UPDATE_Read(uppk) | ||
| + | end | ||
| + | |||
| + | function get_invbox_data(sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | sobj:STATE_Write(stpk) | ||
| + | sobj:UPDATE_Write(uppk) | ||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | -- amk.mylog("rsp "..size.." "..size1) | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | local t={} | ||
| + | amk.parse_object_packet(t,stpk,uppk,size) | ||
| + | amk.parse_visual_packet(t,stpk,uppk,size) | ||
| + | -- amk.mylog("rsp "..size.." "..size1.." "..stpk:r_tell()) | ||
| + | return t | ||
| + | end | ||
| + | |||
| + | function set_invbox_data(t,sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | |||
| + | amk.fill_object_packet(t,stpk,uppk) | ||
| + | amk.fill_visual_packet(t,stpk,uppk) | ||
| + | |||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | -- amk.mylog("wsp "..size.." "..size1) | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | sobj:STATE_Read(stpk,size) | ||
| + | sobj:UPDATE_Read(uppk) | ||
| + | end | ||
| + | |||
| + | function readvu8uN(packet,n) | ||
| + | local v={} | ||
| + | for i=1,n,1 do | ||
| + | table.insert(v,packet:r_u8()) | ||
| + | end | ||
| + | return v | ||
| + | end | ||
| + | |||
| + | function writevu8uN(pk,v) | ||
| + | local len=table.getn(v) | ||
| + | --pk:w_u8(len) | ||
| + | for i=1,len,1 do | ||
| + | pk:w_u8(v[i]) | ||
| + | end | ||
| + | end | ||
| + | |||
| + | function parse_item_packet(ret,stpk,updpk) | ||
| + | ret.condition=stpk:r_float() | ||
| + | ret.updnum_items=updpk:r_u8() | ||
| + | ret.updpos={} -- или поставить вектор? ладно потом | ||
| + | ret.updpos.x=updpk:r_float() | ||
| + | ret.updpos.y=updpk:r_float() | ||
| + | ret.updpos.z=updpk:r_float() | ||
| + | ret.updcse_alife_item__unk1_q8v4=readvu8uN(updpk,4) | ||
| + | ret.updcse_alife_item__unk2_q8v3=readvu8uN(updpk,3) | ||
| + | ret.updcse_alife_item__unk3_q8v3=readvu8uN(updpk,3) | ||
| + | return ret | ||
| + | end | ||
| + | |||
| + | function fill_item_packet(ret,stpk,updpk) | ||
| + | stpk:w_float(ret.condition) | ||
| + | updpk:w_u8(ret.updnum_items) | ||
| + | updpk:w_float(ret.updpos.x) | ||
| + | updpk:w_float(ret.updpos.y) | ||
| + | updpk:w_float(ret.updpos.z) | ||
| + | readvu8uN(updpk,ret.updcse_alife_item__unk1_q8v4) | ||
| + | readvu8uN(updpk,ret.updcse_alife_item__unk2_q8v3) | ||
| + | readvu8uN(updpk,ret.updcse_alife_item__unk3_q8v3) | ||
| + | return ret | ||
| + | end | ||
| + | |||
| + | function parse_item_ammo_packet(ret,stpk,updpk) | ||
| + | ret.ammo_left=stpk:r_u16() | ||
| + | ret.updammo_left=updpk:r_u16() | ||
| + | return ret | ||
| + | end | ||
| + | |||
| + | function fill_item_ammo_packet(ret,stpk,updpk) | ||
| + | stpk:w_u16(ret.ammo_left) | ||
| + | updpk:w_u16(ret.updammo_left) | ||
| + | return ret | ||
| + | end | ||
| + | |||
| + | function get_ammo_params(sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | sobj:STATE_Write(stpk) | ||
| + | sobj:UPDATE_Write(uppk) | ||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | local t={} | ||
| + | amk.parse_object_packet(t,stpk,uppk,size) | ||
| + | amk.parse_visual_packet(t,stpk,uppk,size) | ||
| + | amk.parse_item_packet(t,stpk,uppk,size) | ||
| + | amk.parse_item_ammo_packet(t,stpk,uppk,size) | ||
| + | return t | ||
| + | end | ||
| + | |||
| + | function set_ammo_data(t,sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | |||
| + | amk.fill_object_packet(t,stpk,uppk) | ||
| + | amk.fill_visual_packet(t,stpk,uppk) | ||
| + | amk.fill_item_packet(t,stpk,uppk) | ||
| + | amk.fill_item_ammo_packet(t,stpk,uppk) | ||
| + | |||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | sobj:STATE_Read(stpk,size) | ||
| + | sobj:UPDATE_Read(uppk) | ||
| + | end | ||
| + | |||
| + | function cfg_get_string(ini,sect,name,def) | ||
| + | if ini and ini:line_exist(sect,name) then | ||
| + | return ini:r_string(sect,name) | ||
| + | end | ||
| + | return def | ||
| + | end | ||
| + | |||
| + | function get_destroyable_data(sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | sobj:STATE_Write(stpk) | ||
| + | sobj:UPDATE_Write(uppk) | ||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | -- amk.mylog("rsp "..size.." "..size1) | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | local t={} | ||
| + | amk.parse_object_packet(t,stpk,uppk,size) | ||
| + | amk.parse_visual_packet(t,stpk,uppk,size) | ||
| + | amk.parse_skeleton_packet(t,stpk,uppk,size) | ||
| + | amk.parse_object_physic_packet(t,stpk,uppk,size) | ||
| + | -- amk.mylog("rsp "..size.." "..size1.." "..stpk:r_tell()) | ||
| + | return t | ||
| + | end | ||
| + | |||
| + | function set_destroyable_data(t,sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | |||
| + | amk.fill_object_packet(t,stpk,uppk) | ||
| + | amk.fill_visual_packet(t,stpk,uppk) | ||
| + | amk.fill_skeleton_packet(t,stpk,uppk) | ||
| + | amk.fill_object_physic_packet(t,stpk,uppk) | ||
| + | |||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | -- amk.mylog("wsp "..size.." "..size1) | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | sobj:STATE_Read(stpk,size) | ||
| + | sobj:UPDATE_Read(uppk) | ||
| + | |||
| + | end | ||
| + | |||
| + | function get_weapon_data(sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | sobj:STATE_Write(stpk) | ||
| + | sobj:UPDATE_Write(uppk) | ||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | -- amk.mylog("rsp "..size.." "..size1) | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | local t={} | ||
| + | amk.parse_object_packet(t,stpk,uppk,size) | ||
| + | amk.parse_visual_packet(t,stpk,uppk,size) | ||
| + | amk.parse_item_packet(t,stpk,uppk,size) | ||
| + | amk.parse_item_weapon_packet(t,stpk,uppk,size) | ||
| + | -- amk.mylog("rsp "..size.." "..size1.." "..stpk:r_tell()) | ||
| + | return t | ||
| + | end | ||
| + | |||
| + | function set_weapon_data(t,sobj) | ||
| + | local stpk=net_packet() | ||
| + | local uppk=net_packet() | ||
| + | |||
| + | amk.fill_object_packet(t,stpk,uppk) | ||
| + | amk.fill_visual_packet(t,stpk,uppk) | ||
| + | amk.fill_item_packet(t,stpk,uppk) | ||
| + | amk.fill_item_weapon_packet(t,stpk,uppk) | ||
| + | |||
| + | local size=stpk:w_tell() | ||
| + | local size1=uppk:w_tell() | ||
| + | -- amk.mylog("wsp "..size.." "..size1) | ||
| + | stpk:r_seek(0) | ||
| + | uppk:r_seek(0) | ||
| + | sobj:STATE_Read(stpk,size) | ||
| + | sobj:UPDATE_Read(uppk) | ||
| + | |||
| + | end | ||
| + | |||
| + | function parse_item_weapon_packet(ret,stpk,updpk) | ||
| + | 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.updcondition = updpk:r_u8() | ||
| + | ret.updweapon_flags = updpk:r_u8() | ||
| + | ret.updammo_elapsed = updpk:r_u16() | ||
| + | ret.updaddon_flags = updpk:r_u8() | ||
| + | ret.updammo_type = updpk:r_u8() | ||
| + | ret.updweapon_state = updpk:r_u8() | ||
| + | ret.updweapon_zoom = updpk:r_u8() | ||
| + | ret.updcurrent_fire_mode = updpk:r_u8() | ||
| + | return ret | ||
| + | end | ||
| + | |||
| + | function fill_item_weapon_packet(ret,stpk,updpk) | ||
| + | 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) | ||
| + | |||
| + | updpk:w_u8(ret.updcondition) | ||
| + | updpk:w_u8(ret.updweapon_flags) | ||
| + | updpk:w_u16(ret.updammo_elapsed) | ||
| + | updpk:w_u8(ret.updaddon_flags) | ||
| + | updpk:w_u8(ret.updammo_type) | ||
| + | updpk:w_u8(ret.updweapon_state) | ||
| + | updpk:w_u8(ret.updweapon_zoom) | ||
| + | updpk:w_u8(ret.updcurrent_fire_mode) | ||
| + | return ret | ||
| + | end | ||
| + | |||
| + | function get_ver() | ||
| + | local ver = "0" | ||
| + | local mm = _G.main_menu.get_main_menu() | ||
| + | if mm then ver = mm:GetGSVer() end | ||
| + | return ver | ||
| + | end | ||
| + | </pre> | ||
| + | всё заходим в игру и пробуем :-) | ||
| + | |||
| + | ''В принципе, скрипт работает и без watcher_act.script...'' | ||
| + | [[Категория:Скрипты]] | ||
Версия 04:54, 4 марта 2011
В этой теме я напишу как сделать так что бы можно было снимать деньги с трупов. Нам надо файл treasure_manager.script В этом файле находим такие строки
--' Юзание инициатора (возможность выдать тайник)
function CTreasure:use(npc)
printf("TREASURE USE")
После строки --printf("TREASURE USE")-- пишем
if (npc and db.actor) then
lootmoney.lootmoney(npc)
end
У нас должно выйти
--' Юзание инициатора (возможность выдать тайник)
function CTreasure:use(npc)
printf("TREASURE USE")
if (npc and db.actor) then
lootmoney.lootmoney(npc)
end
Теперь создаём файл lootmoney.script и в нём пишем
function lootmoney(npc)
if npc ~= nil and not string.find(npc:section(),"arena") and npc:character_community()~="arena_enemy" then
local money = npc:money()
if money ~= nil and money ~=0 then
local deadmoney = money
local npc_rank
npc_rank = ranks.get_obj_rank_name(npc)
if npc_rank ~= nil then
if npc_rank == "novice" and deadmoney >=400 then deadmoney=math.random(25,400)
elseif npc_rank == "experienced" and deadmoney >=500 then deadmoney=math.random(50,500)
elseif npc_rank == "veteran" and deadmoney >=600 then deadmoney=math.random(100,600)
elseif npc_rank == "master" and deadmoney >=700 then deadmoney=math.random(200,700)
end
end
local news_texti = "\\n%c[255,255,0,0]Мёртвый сталкер: %c[default]"..npc:character_name().."\\n%c[255,255,0,0]Обнаружено денег: %c[default]"..game.translate_string(tostring(deadmoney).."руб.")
db.actor:give_game_news(news_texti, "ui\\ui_iconsTotal", Frect():set(0,0,83,47), 1, 4000)
db.actor:give_money(deadmoney)
game_stats.money_quest_update(deadmoney)
npc:give_money(-money)
game_stats.money_quest_update(-money)
end
end
end
теперь создаем файл watcher_act.script и впишем в него
-- Red75 (c) 2008
-- Marauder scheme v 1.1
-- Part of AMK MOD
evid_see_stuff=6931
evid_near_stuff=evid_see_stuff+1
evid_see_body=evid_see_stuff+2
evid_position_corrected=evid_see_stuff+3
actid_reach_item=evid_see_stuff
actid_grab_item=evid_see_stuff+1
actid_grab_body=evid_see_stuff+2
actid_correct_position=evid_see_stuff+3
-- Вызывает closure раз в period, obj[var] хранит время следующего срабатывания
function timed(obj,var,period,closure)
if obj[var] and obj[var]<time_global() then
obj[var]=time_global()+period
closure()
elseif not obj[var] then
obj[var]=time_global()+period
-- closure()
end
end
function trigger_timed(obj,var)
obj[var]=time_global()
end
local disabled_objects={}
local corpse_checked={} -- true - has loot, false - hasn't loot, nil - not checked
function checkCorpse(obj)
if (IsStalker(obj) or IsMonster(obj)) and obj:alive()==false then
if corpse_checked[obj:id()]~=nil then
return corpse_checked[obj:id()]
end
local cnt=0
obj:iterate_inventory(function (dummy, item)
if item:section()~="bolt" then
cnt=cnt+1
end
end, nil)
corpse_checked[obj:id()]=cnt>0
return corpse_checked[obj:id()]
end
return false
end
local valuable_clsid={
[clsid.art_bast_artefact]=true,
[clsid.art_black_drops]=true,
[clsid.art_dummy]=true,
[clsid.art_electric_ball]=true,
[clsid.art_faded_ball]=true,
[clsid.art_galantine]=true,
[clsid.art_gravi]=true,
[clsid.art_gravi_black]=true,
[clsid.art_mercury_ball]=true,
[clsid.art_needles]=true,
[clsid.art_rusty_hair]=true,
[clsid.art_thorn]=true,
[clsid.art_zuda]=true,
[clsid.artefact_s]=true,
[clsid.device_detector_simple]=true,
[clsid.device_pda]=true,
[clsid.device_torch_s]=true,
[clsid.equ_exo]=true,
[clsid.equ_military]=true,
[clsid.equ_scientific]=true,
[clsid.equ_stalker_s]=true,
[clsid.obj_antirad]=true,
[clsid.obj_attachable]=true,
[clsid.obj_bandage]=true,
[clsid.obj_bolt]=true,
[clsid.obj_bottle]=true,
[clsid.obj_food]=true,
[clsid.obj_medkit]=true,
[clsid.wpn_ak74_s]=true,
[clsid.wpn_ammo]=true,
[clsid.wpn_ammo_m209]=true,
[clsid.wpn_ammo_og7b]=true,
[clsid.wpn_ammo_vog25]=true,
[clsid.wpn_binocular_s]=true,
[clsid.wpn_bm16_s]=true,
[clsid.wpn_fn2000]=true,
[clsid.wpn_fort]=true,
[clsid.wpn_groza_s]=true,
[clsid.wpn_hpsa_s]=true,
[clsid.wpn_knife_s]=true,
[clsid.wpn_lr300_s]=true,
[clsid.wpn_pm_s]=true,
[clsid.wpn_rg6_s]=true,
[clsid.wpn_rpg7_s]=true,
[clsid.wpn_scope_s]=true,
[clsid.wpn_shotgun_s]=true,
[clsid.wpn_silencer]=true,
[clsid.wpn_svd_s]=true,
[clsid.wpn_svu_s]=true,
[clsid.wpn_usp45_s]=true,
[clsid.wpn_val_s]=true,
[clsid.wpn_vintorez_s]=true,
[clsid.wpn_walther_s]=true,
[clsid.wpn_wmagaz]=true,
[clsid.wpn_wmaggl]=true
}
local obj_owner={}
function bgwith(str,ptr)
local ps=string.find(str,ptr)
return ps~=nil and ps==1
end
function isValuable(obj)
local sec=obj:section()
if sec=="amk_metka" then
return false,false
end
if valuable_clsid[obj:clsid()] then
return true, false
end
return bgwith(sec,"af_") or bgwith(sec,"ammo_") or bgwith(sec,"wpn_") or bgwith(sec,"energy_") or checkCorpse(obj), IsStalker(obj) or IsMonster(obj)
end
function objValue(obj)
local sec=obj:section()
local multiplier=1
if bgwith(sec,"ammo_") then
multiplier=30
elseif sec=="vodka" then
multiplier=20
end
if system_ini():section_exist(sec) and system_ini():line_exist(sec,"cost") then
return system_ini():r_float(sec,"cost")*multiplier
end
return 0
end
function claimGObject(npc,st,obj)
if st.grabitemid then
obj_owner[st.grabitemid]=nil
end
st.grabitemid=obj:id()
obj_owner[obj:id()]=npc:id()
end
function freeGObject(st)
if st.grabitemid then
obj_owner[st.grabitemid]=nil
st.grabitemid=nil
end
end
function clearGObject(st)
st.grabitemid=nil
end
function getGObject(st)
if st.grabitemid then
local ret=level.object_by_id(st.grabitemid)
if ret==nil then
st.grabitemid=nil
end
return ret
end
return nil
end
function mypGObject(npc,st)
return st.grabitemid~=nil and obj_owner[st.grabitemid]~=nil and obj_owner[st.grabitemid]==npc:id()
end
class "ev_see_stuff" (property_evaluator)
function ev_see_stuff:__init(st,name) super(nil, name)
self.st=st
end
local bad_dangers={
[danger_object.hit]=true,
[danger_object.attacked]=true,
[danger_object.bullet_ricochet]=true,
[danger_object.grenade]=true,
[danger_object.entity_death]=true,
[danger_object.enemy_sound]=true
}
local inertion_time=30000
function bad_danger(npc)
local danger=npc:best_danger()
if danger then
return bad_dangers[danger:type()] and time_global()-danger:time()<inertion_time
end
return false
end
function ev_see_stuff:evaluate()
local res=getGObject(self.st)~=nil
local npc=self.object
local actsch=db.storage[npc:id()].active_scheme
if actsch and db.actor then
xr_logic.try_switch_to_another_section(npc, db.storage[npc:id()][actsch], db.actor)
end
local act_sec=db.storage[npc:id()].active_section or ""
if (not npc:alive()) or xr_wounded.is_wounded(npc) or npc:best_enemy() or
bad_danger(npc) or (actsch and db.storage[npc:id()][actsch].no_loot) then
if res then
freeGObject(self.st)
amk.mylog(npc:name() .. " distracted. sect "..act_sec,"grb")
end
return false
end
local dist_limit=1000
if bgwith(act_sec,"camper") then
dist_limit=5
end
local busy=bgwith(act_sec,"walker") or bgwith(act_sec,"combat") or bgwith(act_sec,"danger") -- or npc:best_danger()
if res and self.st.block_search then
-- NPC собрался взять вещь. Временно прекратим поиск.
return true
end
timed(self.st,"tm1",5000+math.random()*10000,
function ()
-- amk.mylog(npc:name() .. " is going to search stuff","grb")
local min_dist=100000
local function check_item(o)
local obj=o:object()
if obj_owner[obj:id()] and (level.object_by_id(obj_owner[obj:id()])==nil or level.object_by_id(obj_owner[obj:id()]):alive()==false) then
obj_owner[obj:id()]=nil
end
if (not self.st.disabled_objects[obj:id()]) and (obj:parent()==nil or not IsStalker(obj:parent())) and
(obj_owner[obj:id()]==nil or obj_owner[obj:id()]==npc:id()) and npc:accessible(obj:level_vertex_id()) and
(db.actor==nil or db.actor:alive()==false or db.actor:position():distance_to_sqr(obj:position())>6) then
local valuable,corpse=isValuable(obj)
if valuable then
local value=3000
if not corpse then
value=objValue(obj)
end
if value<=0 then value=0 end
local max_dist=5+math.sqrt(value)
if busy then
max_dist=max_dist/5
end
local dist=level.vertex_position(obj:level_vertex_id()):distance_to(npc:position())
local corrected_dist=dist
if dist>5 then
corrected_dist=5+(dist-5)/math.sqrt(value)
end
if dist<max_dist and corrected_dist<min_dist and dist<dist_limit then
min_dist=corrected_dist
claimGObject(npc,self.st,obj)
res=true
end
end
end
end -- function check_item
for o in npc:memory_visible_objects() do
check_item(o)
end
for o in npc:memory_sound_objects() do
check_item(o)
end
-- for o in npc:not_yet_visible_objects() do
-- check_item(o)
-- end
if res then
amk.mylog(npc:name() .. " claimed "..getGObject(self.st):name().." cact "..tostring(npc:motivation_action_manager():current_action_id()),"grb")
end
end
)
return res -- false -- res
end
class "ev_near_stuff" (property_evaluator)
function ev_near_stuff:__init(st,name) super(nil, name)
self.st=st
end
function ev_near_stuff:evaluate()
local npc=self.object
local gi=getGObject(self.st)
if gi then
if self.st.dest_lvid then
return npc:level_vertex_id()==self.st.dest_lvid
end
return level.vertex_position(gi:level_vertex_id()):distance_to_sqr(npc:position())<1
end
return false
end
class "ev_see_body" (property_evaluator)
function ev_see_body:__init(st) super(nil, "ev_see_body")
self.st=st
end
function ev_see_body:evaluate()
local npc=self.object
local gi=getGObject(self.st)
if gi then
return IsStalker(gi) or IsMonster(gi)
end
return false
end
class "ev_position_corrected" (property_evaluator)
function ev_position_corrected:__init(st) super(nil, "ev_position_corrected")
self.st=st
end
function ev_position_corrected:evaluate()
local npc=self.object
return self.st.position_corrected==true
end
class "act_grab_item" (action_base)
function act_grab_item:__init (action_name, st) super (nil, action_name)
self.st = st
end
function act_grab_item:initialize()
action_base.initialize(self)
local npc=self.object
npc:set_item(object.idle,nil)
npc:set_movement_type(move.walk)
npc:set_mental_state(anim.danger)
npc:set_body_state(move.crouch)
npc:movement_enabled(true)
local gi=getGObject(self.st)
-- if gi then npc:set_sight(gi,true,true) end
npc:set_sight(look.danger,nil,0)
amk.mylog(self.object:name().." is going to grab item","stmt")
self.st.block_search=true
if gi then
if(IsStalker(gi) or IsMonster(gi)) then
self.tt=time_global()+3000
else
self.tt=time_global()+1000
utils.send_to_nearest_accessible_vertex(npc,gi:level_vertex_id())
end
end
--npc:set_dest_level_vertex_id(1)
self.force=vector():set(0,0,0)
end
function act_grab_item:execute()
action_base.execute(self)
local npc=self.object
local gi=getGObject(self.st)
if not gi then
return
end
if self.tt<time_global() then
if gi and gi:parent()==nil then
gi:transfer_item(gi,npc)
npc:enable_memory_object(gi,false)
amk.mylog(npc:name() .. " has taken "..gi:name(),"grb")
end
-- Тут нельзя освобождать объект. transfer_item выполняется асинхронно. Поэтому делаем clearGObject
clearGObject(self.st)
--freeGObject(self.st)
end
end
function act_grab_item:finalize()
local npc=self.object
self.st.block_search=nil
npc:set_sight(look.danger,nil,0)
trigger_timed(self.st,"tm1")
self.st.dest_lvid=nil -- Очищаем скорректированную точку назначения
action_base.finalize(self)
end
class "act_grab_body" (action_base)
function act_grab_body:__init (st) super (nil, "act_grab_body")
self.st = st
end
function act_grab_body:initialize()
action_base.initialize(self)
local npc=self.object
local gi=getGObject(self.st)
amk.mylog(self.object:name().." is going to grab body","stmt")
self.st.block_search=true
if gi then
self.tt=time_global()+6000
state_mgr.set_state(npc,"search",nil,nil,{look_object=gi})
else
self.st.dest_lvid=nil
end
end
function act_grab_body:execute()
action_base.execute(self)
local npc=self.object
local gi=getGObject(self.st)
if not gi then
self.st.dest_lvid=nil
return
end
if self.tt<time_global() then
if gi and gi:parent()==nil then
gi:iterate_inventory(function (d,item)
if item:section()~="bolt" then
gi:transfer_item(item,npc)
end
end, nil)
local num=gi:money()
if num and num >0 then
local deadmoney = num
local gi_rank
gi_rank = ranks.get_obj_rank_name(gi)
if gi_rank ~= nil then
if gi_rank == "novice" and deadmoney >=100 then deadmoney=math.random(25,100)
elseif gi_rank == "experienced" and deadmoney >=200 then deadmoney=math.random(50,200)
elseif gi_rank == "veteran" and deadmoney >=300 then deadmoney=math.random(100,300)
elseif gi_rank == "master" and deadmoney >=400 then deadmoney=math.random(200,400)
end
end
npc:give_money(deadmoney)
game_stats.money_quest_update(deadmoney)
gi:give_money(-num)
game_stats.money_quest_update(-num)
end
corpse_checked[gi:id()]=false
amk.mylog(npc:name() .. " has taken "..gi:name(),"grb")
end
-- Тут нельзя освобождать объект. transfer_item выполняется асинхронно. Поэтому делаем clearGObject
clearGObject(self.st)
--freeGObject(self.st)
end
end
function act_grab_body:finalize()
local npc=self.object
self.st.block_search=nil
trigger_timed(self.st,"tm1")
self.st.dest_lvid=nil -- Очищаем скорректированную точку назначения
action_base.finalize(self)
end
function correct_position(gi,npc)
if IsStalker(gi) then
-- Вычисляем вектор разницы между координатами кости и level vertex. Пытаемся найти level vertex наиболее близкий к кости
local diff=gi:bone_position("bip01_head"):sub(level.vertex_position(gi:level_vertex_id()))
local len=diff:magnitude()
local diffp=vector():set(diff.z,0,-diff.x):mul(0.5)
-- Сдвигаем целевую точку вбок, чтобы непись не залазил ногами в труп
diff:add(diffp)
return npc:vertex_in_direction(gi:level_vertex_id(),diff,len)
else
return gi:level_vertex_id()
end
end
class "act_reach_item" (action_base)
function act_reach_item:__init (action_name, st) super (nil, action_name)
self.st = st
end
function act_reach_item:initialize()
action_base.initialize(self)
local npc=self.object
local gi=getGObject(self.st)
self.st.dest_lvid=nil
self.tgt_lvid=0
if gi then
if npc:accessible(gi:level_vertex_id()) then
npc:set_detail_path_type(move.curve)
npc:set_path_type(game_object.level_path)
if npc:best_danger() and time_global()-npc:best_danger():time()<inertion_time then
npc:set_mental_state(anim.danger)
npc:set_body_state(move.crouch)
npc:set_movement_type(move.walk)
-- npc:set_sight(gi,true,true)
else
npc:set_body_state(move.standing)
npc:set_mental_state(anim.free)
npc:set_movement_type(move.walk)
end
npc:movement_enabled(true)
if npc:best_weapon() and isWeapon(npc:best_weapon()) then
-- npc:set_item(object.idle,npc:best_weapon())
end
-- npc:set_dest_level_vertex_id(gi:level_vertex_id())
npc:set_sight(look.danger,nil,0)
self.st.dest_lvid=correct_position(gi,npc) --gi:level_vertex_id()
self.tgt_lvid=gi:level_vertex_id()
npc:set_dest_level_vertex_id(self.st.dest_lvid)
else
freeGObject(self.st)
end
end
self.ct=time_global()
self.clvid=npc:level_vertex_id()
self.st.position_corrected=false
amk.mylog(self.object:name().." is going to reach item","stmt")
end
function act_reach_item:execute()
action_base.execute(self)
local npc=self.object
local gi=getGObject(self.st)
if gi and gi:parent()~=nil then
-- ГГ забрал вкусность. Можно добавить наезд на ГГ.
self.st.dest_lvid=nil
freeGObject(self.st)
elseif gi then
if self.clvid==npc:level_vertex_id() then
if time_global()-self.ct>10000 then
-- не можем добраться до нняки
self.st.disabled_objects[gi:id()]=true
self.st.dest_lvid=nil
freeGObject(self.st)
end
else
self.clvid=npc:level_vertex_id()
self.ct=time_global()
end
if self.tgt_lvid~=gi:level_vertex_id() then
self.tgt_lvid=gi:level_vertex_id()
self.st.dest_lvid=correct_position(gi,npc) -- gi:level_vertex_id()
npc:set_dest_level_vertex_id(self.st.dest_lvid)
end
--npc:set_sight(gi)
end
end
function add_to_binder(object, char_ini, scheme, section, st)
-- amk.mylog("addtb "..object:name(),"pln")
local npc=object
st.disabled_objects={}
local manager = object:motivation_action_manager()
local zombi=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" or -- сумашедший на милитари и Сахаров
npc:name()=="mil_freedom_member0021" -- Скрягу в зомби!
local prop_idlecombat=xr_evaluators_id.state_mgr + 3
local prop_contact=xr_evaluators_id.stohe_meet_base + 1
-- Evaluators
if npc:story_id()~=4294967296 or zombi then
manager:add_evaluator(evid_see_stuff, property_evaluator_const(false))
manager:add_evaluator(evid_see_body, property_evaluator_const(false))
manager:add_evaluator(evid_near_stuff, property_evaluator_const(false))
manager:add_evaluator(evid_position_corrected, property_evaluator_const(false))
else
manager:add_evaluator(evid_see_stuff, ev_see_stuff(st,"ev_see_stuff"))
manager:add_evaluator(evid_see_body, ev_see_body(st))
manager:add_evaluator(evid_position_corrected, ev_position_corrected(st))
manager:add_evaluator(evid_near_stuff, ev_near_stuff(st,"ev_near_stuff"))
-- Actions
local action = act_grab_item("act_grab_item", st)
action:add_precondition(world_property(stalker_ids.property_alive,true))
action:add_precondition(world_property(stalker_ids.property_enemy,false))
-- action:add_precondition(world_property(stalker_ids.property_danger,false))
action:add_precondition(world_property(xr_evaluators_id.sidor_wounded_base,false))
action:add_precondition(world_property(blowout_scheme.evid_anomaly,false))
action:add_precondition(world_property(blowout_scheme.evid_blowout,false))
action:add_precondition(world_property(evid_see_stuff,true))
action:add_precondition(world_property(evid_near_stuff,true))
action:add_precondition(world_property(evid_see_body,false))
action:add_precondition(world_property(prop_idlecombat,true)) -- отключим стэйт менеджер
action:add_effect(world_property(evid_near_stuff, false))
action:add_effect(world_property(evid_see_stuff, false))
action:add_effect(world_property(evid_see_body,true)) -- для переключения на обыск трупа
manager:add_action (actid_grab_item, action)
action = act_grab_body(st)
action:add_precondition(world_property(stalker_ids.property_alive,true))
action:add_precondition(world_property(stalker_ids.property_enemy,false))
-- action:add_precondition(world_property(stalker_ids.property_danger,false))
action:add_precondition(world_property(xr_evaluators_id.sidor_wounded_base,false))
action:add_precondition(world_property(blowout_scheme.evid_anomaly,false))
action:add_precondition(world_property(blowout_scheme.evid_blowout,false))
action:add_precondition(world_property(evid_see_stuff,true))
action:add_precondition(world_property(evid_see_body,true))
action:add_precondition(world_property(evid_near_stuff,true))
-- action:add_precondition(world_property(evid_position_corrected,true))
action:add_effect(world_property(evid_near_stuff, false))
action:add_effect(world_property(evid_see_stuff, false))
action:add_effect(world_property(evid_see_body,false)) -- переключаемся на подъём вещички
manager:add_action (actid_grab_body, action)
action = act_reach_item("act_reach_item", st)
action:add_precondition(world_property(stalker_ids.property_alive,true))
action:add_precondition(world_property(stalker_ids.property_enemy,false))
action:add_precondition(world_property(prop_contact,false))
-- action:add_precondition(world_property(stalker_ids.property_danger,false))
action:add_precondition(world_property(xr_evaluators_id.sidor_wounded_base,false))
action:add_precondition(world_property(blowout_scheme.evid_anomaly,false))
action:add_precondition(world_property(blowout_scheme.evid_blowout,false))
action:add_precondition(world_property(evid_see_stuff,true))
action:add_precondition(world_property(evid_near_stuff,false))
action:add_precondition(world_property(prop_idlecombat,true))
action:add_effect (world_property(evid_near_stuff, true))
manager:add_action (actid_reach_item, action)
action = manager:action(xr_actions_id.alife)
action:add_precondition(world_property(evid_see_stuff,false))
action = manager:action(stalker_ids.action_danger_planner)
action:add_precondition(world_property(evid_see_stuff,false))
-- action:add_precondition(world_property(evid_near_stuff,false))
-- action = manager:action(xr_actions_id.stohe_kamp_base + 1)
-- action:add_precondition(world_property(evid_see_stuff,false))
-- action = manager:action(xr_actions_id.stohe_kamp_base + 3)
-- action:add_precondition(world_property(evid_see_stuff,false))
-- action = manager:action(xr_actions_id.stohe_meet_base+1)
-- action:add_precondition(world_property(evid_see_stuff,false))
-- amk.mylog("addtb end "..object:name(),"pln")
end
end
function set_scheme(npc, ini, scheme, section)
-- amk.mylog("set scheme "..npc:name().." story_id "..npc:story_id(),"pln")
local st = xr_logic.assign_storage_and_bind(npc, ini, scheme, section)
st.ini=ini
end
Теперь осталось содать скрипт amk.script --у кого есть ненадо--
и вписываем в него
local npc_spawner={} --служебный массив, работает автоматически - не трогать шаловливыми русками
local timers={} --хранит реал-тайм таймеры
local g_timers={} --хранит таймеры в игровом времени
local markers={} --хранит маркеры на карте
local x_objs={} --хранит ИДшники объектов
local timer_trigger=nil
convert_npc={}
g_kick=false
is_debug = false
ver = "0"
oau_watchdog=0
oau_reason=""
--переменные для типсов
pda_news = xr_sound.get_safe_sound_object([[device\pda\pda_news]])
pda_tips = xr_sound.get_safe_sound_object([[device\pda\pda_tip]])
pda_task = xr_sound.get_safe_sound_object([[device\pda\pda_objective]])
tips_icons = {
default = { 0, 658},
trader = { 332, 893},
dolg = { 0, 658},
freedom = { 0, 658},
ecolog = { 498, 0},
arena = { 332, 141},
stalker = { 0, 658},
krot = { 332, 47},
barman = { 332, 235},
wolf = { 332, 940},
o_soznanie = { 498, 893},
monolith = { 0, 658},
saharov = { 332, 470},
prizrak = { 0, 658},
killer = { 0, 658},
death = { 0, 752},
gen_info = { 0, 658},
trade = { 0, 0},
uniq = { 498, 47} --{ 498, 188}
}
----------------
local bufferedmessages={}
function logct(msg,tag)
if true and (tag and (tag=="mcbt" or tag=="temp")) then --(tag=="dram")) then
get_console():execute("load [[Участник:92.113.172.219|92.113.172.219]] "..string.sub(msg,1,200))
end
end
function rep(npc,msg,tag)
if string.find(npc:name(),"gar_dm") then
logct(msg,tag)
end
end
function mylog(msg)
if is_debug then
if msg==nil then
return
end
if db and db.actor then
if bufferedmessages then
for k,v in ipairs(bufferedmessages) do
db.actor:give_game_news(v, "ui\\ui_iconsTotal", Frect():set(0,658,83,47), 0, 15000)
end
bufferedmessages=nil
end
db.actor:give_game_news(msg, "ui\\ui_iconsTotal", Frect():set(0,658,83,47), 0, 15000)
else
if bufferedmessages then
table.insert(bufferedmessages,msg)
end
end
if get_console() then
get_console():execute("load [[Участник:92.113.172.219|92.113.172.219]] "..string.sub(msg,1,200))
get_console():execute("flush")
end
end
end
--показываем типс
function send_tip(news_text, header, timeout, showtime, sender, sound)
if news_text==nil then return end
if header==nil then header=game.translate_string("st_tip") end
if timeout == nil then timeout = 0 end
if showtime == nil then showtime = 5 end
local player
if sound=="news" then
player=pda_news
elseif sound=="task" then
player=pda_task
else
player=pda_tips
end
--' Играем дефолтный звук
player:play(db.actor, timeout, sound_object.s2d)
if sender == nil then
sender = "default"
end
local x = tips_icons[sender][1]
local y = tips_icons[sender][2]
local news_text = "%c[255,160,160,160]"..header.."\\n".."%c[default]"..news_text
db.actor:give_game_news(news_text, "ui\\ui_iconsTotal", Frect():set(x,y,83,47), timeout*1000, showtime*1000)
return true
end
function add_spot_on_map(obj_id,type,text)
--возможные типы type смотри в ui\map_spots.xml
if obj_id then
if text==nil then text=" " end
-- Ставим метку на серверный объект чтобы её не пришлось обновлять
level.map_add_object_spot_ser(obj_id, type, text)
-- save_variable("x_marker_type_"..obj_id, type)
-- save_variable("x_marker_text_"..obj_id, text)
end
end
function remove_spot_from_map(obj_id,type)
if obj_id and level.map_has_object_spot(obj_id, type)~= 0 then
level.map_remove_object_spot(obj_id, type)
-- del_variable("x_marker_type_"..obj_id)
-- del_variable("x_marker_text_"..obj_id)
end
end
--старт таймера в реальном времени
function start_timer(name,delay,action)
if not delay then
return false
end
if not action then
action = ""
end
local time = game.time() --time in seconds since 1970
local a=1
while db.storage[db.actor:id()].pstor["xt"..a] do
a=a+1
if a>100 then
return false
end
end
save_variable("xt"..a, name)
save_variable("xd"..a, time+delay*1000*system_ini():r_float("alife","time_factor"))
save_variable("xp"..a, action)
return true
end
--старт таймера в игровом времени
function g_start_timer(name,delay_d,delay_h,delay_m,action)
local time = level.get_time_days()*60*24+level.get_time_hours()*60+level.get_time_minutes() --time in game minutes
if delay_d==nil or delay_h==nil or delay_m==nil then
return false
end
if action==nil then
action = ""
end
local a=1
while db.storage[db.actor:id()].pstor["gt"..a] do
a=a+1
if a>100 then
return false
end
end
save_variable("gt"..a, name)
save_variable("gd"..a, time+delay_d*60*24+delay_h*60+delay_m)
save_variable("gp"..a, action)
return true
end
function has_timer(name)
for a=1,100,1 do
tmp=load_variable("xt"..a,nil)
if tmp and tmp==name then
return true
end
end
return false
end
function has_g_timer(name)
for a=1,100,1 do
tmp=load_variable("gt"..a,nil)
if tmp and tmp==name then
return true
end
end
return false
end
-- Временное хранилище для переменных удалённых из pstor
local emerg_store
-- Удаляем переменные из pstor. Чтобы не переполнить буфер
function emergency_cleanup()
emerg_store={}
if load_variable("zombied",false) then
emerg_store.zombied=load_table("zombied")
del_variable("zombied")
end
for i=1,100,1 do
if load_variable("gt"..i,"")=="af_transform" then
emerg_store[i]={}
emerg_store[i].gt=load_variable("gt"..i,"")
emerg_store[i].gd=load_variable("gd"..i,"")
emerg_store[i].gp=load_variable("gp"..i,"")
del_variable("gt"..i)
del_variable("gd"..i)
del_variable("gp"..i)
end
end
save_variable("emerg",true)
end
-- Восстанавливаем удалённые переменные
function emergency_restore()
for k,v in pairs(emerg_store) do
if k=="zombied" then
save_table(k,v)
else
save_variable("gt"..k,v.gt)
save_variable("gd"..k,v.gd)
save_variable("gp"..k,v.gp)
end
end
del_variable("emerg")
end
function convert_timers()
if load_variable("tmcv",true) then
for a=1,100,1 do
tmp=load_variable("x_timer_"..a,nil)
if tmp~=nil then
local name,delay,params=tmp,load_variable("x_timer_"..a.."_delay",0),load_variable("x_timer_"..a.."_params","")
del_variable("x_timer_"..a)
del_variable("x_timer_"..a.."_delay")
del_variable("x_timer_"..a.."_params")
save_variable("xt"..a,name)
save_variable("xd"..a,delay)
save_variable("xp"..a,params)
end
end
for a=1,100,1 do
tmp=load_variable("x_gtimer_"..a,nil)
if tmp~=nil then
local name,delay,params=tmp,load_variable("x_gtimer_"..a.."_delay",0),load_variable("x_gtimer_"..a.."_params","")
del_variable("x_gtimer_"..a)
del_variable("x_gtimer_"..a.."_delay")
del_variable("x_gtimer_"..a.."_params")
save_variable("gt"..a,name)
save_variable("gd"..a,delay)
save_variable("gp"..a,params)
end
end
save_variable("tmcv",false)
end
end
--проверка таймеров, использует 3 следующие за ним функции для выбора действия
function check_timers()
local tmp
for a=1,100,1 do
tmp=load_variable("xt"..a,nil)
if tmp~=nil then
__timer_found(a)
end
end
for a=1,100,1 do
tmp=load_variable("gt"..a,nil)
if tmp~=nil then
__g_timer_found(a)
end
end
end
function __timer_found(idx)
local time = game.time() --time in seconds since 1970
local name,params
if load_variable("xd"..idx, nil)<=time then
name=load_variable("xt"..idx, nil)
params=load_variable("xp"..idx, nil)
del_variable("xt"..idx)
del_variable("xd"..idx)
del_variable("xp"..idx)
oau_reason=name.." "..params
__do_timer_action(name,params)
return true
end
return false
end
function __g_timer_found(idx)
local gtime = level.get_time_days()*60*24+level.get_time_hours()*60+level.get_time_minutes() --time in game minutes
local name,params
if load_variable("gd"..idx, nil)<=gtime then
name=load_variable("gt"..idx, nil)
params=load_variable("gp"..idx, nil)
del_variable("gt"..idx)
del_variable("gd"..idx)
del_variable("gp"..idx)
oau_reason=name.." "..params
__do_timer_action(name,params)
return true
end
return false
end
function __do_timer_action(select_string,params_string)
--[[
здесь описываем вызовы, оформялять в виде
if select_string=="название условия" then
<вызов сторонних функций>
-- можно передавать npc как параметр
end
]]
--user area
if select_string=="show_news" then
mod_call("show_news")
end
if select_string=="gg_need_sleep" then
mod_call("test_for_need_sleep")
end
if select_string=="sleep_nrg" then
mod_call("test_for_need_sleep_nrg",params_string)
end
--[[
if select_string=="sleep_med" then
mod_call("test_for_need_sleep_med",params_string)
end
]]--
if select_string=="sleep_matras" then
mod_call("test_for_need_sleep_matras",params_string)
end
if select_string=="sleep_tr_item" then
mod_call("test_for_need_sleep_tr_item",params_string)
end
if select_string=="sleep_notebook" then
mod_call("test_for_need_sleep_notebook",params_string)
end
if select_string=="block_sleep_menu" then
save_variable("block_sleep_menu",0)
end
if select_string=="radar_fix" then
mod_call("radar_fix")
end
if select_string=="af_transform" then
mod_call("af_transform_end",unpack_array_from_string(params_string))
end
if select_string=="amk_freeplay" then
if amk.load_variable("freeplay",0)==1 and level.name()=="l12_stancia_2" then
xr_effects.game_credits()
end
end
if select_string=="blowout" then
mod_call("Blowout_pp",params_string)
end
if select_string=="test" then
mod_call("Run_Blowout_pp")
end
if select_string=="blowout_ss" then
mod_call("blowout_scary_sounds")
end
if select_string=="blow_shift" then
mod_call("Run_Blowout_pp")
end
if select_string=="sleep_repbox" then
mod_call("repair_weapon", params_string)
end
if select_string=="repbox_cond" then
mod_call("after_repair_weapon", params_string)
end
if select_string=="collect_anomalies_info" then
amk_anoms.collect_info()
end
if select_string=="news_check" then
if (news_main and news_main.check_news) then
news_main.check_news()
end
end
-----------
end
--спавним объекты на карту
--для спавна неписей смотрим config\creatures\spawn_sections.ltx - там написаны имена секций для разных типов неписей
function spawn_item(spawn_item, pos, gv,lv)
if gv==nil then gv=db.actor:game_vertex_id() end
if lv==nil then lv=db.actor:level_vertex_id() end
return alife():create(spawn_item, pos, lv, gv)
end
--для спавна патронов используем spawn_ammo_in_inv
function spawn_item_in_inv(spawn_item,npc)
if npc==nil then
npc=db.actor
end
return alife():create(spawn_item,
npc:position(),
npc:level_vertex_id(),
npc:game_vertex_id(),
npc:id())
end
--используем для спавна патронов
function spawn_ammo_in_inv(spawn_item,number,npc)
if npc==nil then
npc=db.actor
end
if number > 0 then
return se_respawn.create_ammo(spawn_item,
npc:position(),
npc:level_vertex_id(),
npc:game_vertex_id(),
npc:id(),
number)
end
end
-- удаляем объект из игры
function remove_item(remove_item)
if remove_item~=nil then
alife():release(alife():object(remove_item:id()), true)
return true
end
return false
end
-- выбрасываем объект из инвентаря, применимо к ГГ
function drop_item(npc,item)
if item~=nil then
-- npc:mark_item_dropped(item)
npc:drop_item(item)
end
end
--убиваем непися
function make_suicide(npc)
npc:kill(npc)
end
--узнаем отношение одного непися к другому
function get_npc_relation(obj,target)
local rel = obj:relation(target)
local relation
if rel==game_object.neutral then
relation="neutral"
elseif rel==game_object.friend then
relation="friend"
elseif rel==game_object.enemy then
relation="enemy"
else
return false
end
return relation
end
--задаем отношение одного непися к другому
function set_npc_relation(obj,target,relation)
local rel
if relation=="neutral" then
rel=game_object.neutral
elseif relation=="friend" then
rel=game_object.friend
elseif relation=="enemy" then
rel=game_object.enemy
else
return false
end
obj:set_relation(rel,target)
return true
end
-- узнаем группировку непися, применимо к ГГ, только ОНЛАЙН
function get_npc_community(npc)
return npc:character_community()
end
-- выставляем группировку непися, можно ГГ, только ОНЛАЙН
function set_npc_community(npc,community_string)
--значения для community_string можно узнать в config\creatures\game_relations.ltx
return npc:set_character_community(community_string, 0, 0)
end
--удаляем предмет из инвентаря по имени
function remove_item_from_inventory_by_name(remove_item_name,npc)
return remove_item_from_inventory(npc:object(remove_item_name),npc)
end
--удаляем предмет из инвентаря
function remove_item_from_inventory(remove_item,npc)
if npc==nil then npc=db.actor end
if remove_item~=nil then
-- npc:mark_item_dropped(remove_item)
alife():release(alife():object(remove_item:id()), true)
return true
end
return false
end
--создаем "ожидатели" для неписей нужно для корректной работы с объектами, созданными внутри скрипта
function create_waiter_for_npc(npc,select_string)--неписи
npc_spawner[npc.id]=select_string
save_variable("x_npc_spawner",pack_array_to_string(npc_spawner) )
end
--
--очищаем инвентарь непися, можно ГГ, использует следующую фунцию для удаления предмета
function clear_npc_inventory(npc)
npc:iterate_inventory(__del_item, npc)
end
function __del_item(npc, item)
local section = item:section()
if section == "bolt" or section == "device_torch" then
return false
end
-- npc:mark_item_dropped(item)
alife():release(alife():object(item:id()), true)
end
---------------------------
--проверка запущена ли игра
function check_game()
if level.present() and (db.actor ~= nil) and db.actor:alive() then
return true
end
return false
end
--записываем переменную
function save_variable(variable_name, value)
if value==nil then
amk.mylog("saving nil into "..variable_name)
del_variable(variable_name)
else
local vn=compress_name(variable_name)
xr_logic.pstor_store(db.actor, vn, value)
end
end
--загружаем переменную
function load_variable(variable_name, value_if_not_found)
local vn=compress_name(variable_name)
return xr_logic.pstor_retrieve(db.actor, vn, value_if_not_found)
end
--удаляем переменную
function del_variable(variable_name)
local vn=compress_name(variable_name)
if db.storage[db.actor:id()].pstor[vn] then
db.storage[db.actor:id()].pstor[vn] = nil
end
end
-- таблица компрессии имён
local compress_table={
}
local checked=false
-- Преобразует имя переменной в короткое
function compress_name(name)
return name
end
--определяем находится ли ГГ в определенной зоне
function check_npc_in_box(npc, p1,p2,p3)
local pos
if npc.name then pos=npc:position() else pos=npc end
if p3==nil then
if is_point_inside_interval(pos.x,p1.x,p2.x) and
is_point_inside_interval(pos.y,p1.y,p2.y) and
is_point_inside_interval(pos.z,p1.z,p2.z) then
return true
else
return false
end
else
local v1,v2,r,proj1,proj2,dv1,dv2
v1=sub(p2,p1)
v2=sub(p3,p2)
v1.y=0
v2.y=0
dv1=v1:magnitude()
dv2=v2:magnitude()
v1:normalize()
v2:normalize()
r=sub(pos,p1)
local v1p=vector():set(v1.z,0,-v1.x)
proj2=v1p:dotproduct(r)/v1p:dotproduct(v2)
proj1=v1:dotproduct(r)-v1:dotproduct(v2)*proj2
if proj1>0 and proj1<dv1 and proj2>0 and proj2<dv2 and pos.y>p1.y and pos.y<p3.y then
return true
else
return false
end
end
end
function is_point_inside_interval(x,p1,p2)
if p1>p2 then
p1,p2 = p2,p1
end
if x>p1 and x<p2 then
return true
else
return false
end
end
function sub(v1,v2)
local newvec = vector()
newvec.x = v1.x-v2.x
newvec.y = v1.y-v2.y
newvec.z = v1.z-v2.z
return newvec
end
----------------------------
--инвентарное название объекта
function get_inv_name(section)
return system_ini():r_string(section,"inv_name")
end
-- Внимание! Строки в структуре не должны содержать символов с кодами 0-31.
function pack_array_to_string(array)
return string.char(1)..pack_new(array)
-- local str=""
-- local key
-- for key0,value in pairs(array) do
-- if type(key0)=="string" then
-- key='"'..key0..'"'
-- else
-- key=key0
-- end
-- if type(value)=="table" then
-- local substr=pack_array_to_string(value)
-- str=str..key.."=>{"..substr.."}|"
-- elseif type(value)=="customdata" or type(value)=="function" then
-- mylog("Custom data and function isn't supported")
-- elseif type(value)=="boolean" or type(value)=="number" then
-- str=str..key.."=>"..tostring(value).."|"
-- else
-- str=str..key..'=>"'..value..'"|'
-- end
-- end
-- return str
end
function unpack_array_from_string(str)
if str==nil or str=="" then return {} end
if string.sub(str,1,1)~=string.char(1) then
-- Старый формат упаковки
return _parse(str)
else
-- новый формат упаковки тэгирован символом c кодом 1.
return parse_new(string.sub(str,2,-1))
end
end
function _assign(tbl,key,val)
local key0=string.match(key,'"(.*)"')
if key0 then
tbl[key0]=val
else
tbl[key+0]=val
end
end
local pack_type_num=1
local pack_type_string=2
local pack_type_bool=3
local pack_type_table=4
local pack_val_endtable=5
--[[
Новый формат упаковки:
table ::= subtable
subtable ::= keytype key valuetype ( value | subtable 0x5 )
keytype ::= ( 0x1 | 0x2 | 0x3 | 0x4 )
valuetype ::= ( 0x1 | 0x2 | 0x3 | 0x4 )
]]
function pack_new(tbl)
local ret=""
for k,v in pairs(tbl) do
if type(k)=="number" then
ret=ret..string.char(pack_type_num)..k
elseif type(k)=="string" then
ret=ret..string.char(pack_type_string)..k
else
abort("unsupported key type "..type(k))
end
if type(v)=="number" then
ret=ret..string.char(pack_type_num)..v
elseif type(v)=="string" then
ret=ret..string.char(pack_type_string)..v
elseif type(v)=="boolean" then
ret=ret..string.char(pack_type_bool)..v
elseif type(v)=="table" then
ret=ret..string.char(pack_type_table)..pack_new(v)..string.char(pack_val_endtable)
end
end
return ret
end
function parse_new(str,idx)
local ret={}
idx=idx or 1
while true do
local key,value
if idx>string.len(str) then
return ret,idx
end
vtype,idx=get_byte(str,idx)
if vtype==pack_type_num then
key,idx=get_num(str,idx)
elseif vtype==pack_type_string then
key,idx=get_string(str,idx)
elseif vtype==pack_val_endtable then
return ret,idx
else
abort("unsupported key type "..tostring(vtype))
end
vtype,idx=get_byte(str,idx)
if vtype==pack_type_num then
value,idx=get_num(str,idx)
elseif vtype==pack_type_string then
value,idx=get_string(str,idx)
elseif vtype==pack_type_bool then
value,idx=get_bool(str,idx)
elseif vtype==pack_type_table then
value,idx=parse_new(str,idx)
else
abort("unsupported key type "..tostring(vtype))
end
ret[key]=value
end
end
function get_byte(str,idx)
return string.byte(string.sub(str,idx,idx)),idx+1
end
function get_string(str,idx)
local idx1=string.len(str)+1
for i=idx,string.len(str),1 do
if string.byte(string.sub(str,i,i))<32 then
idx1=i
break
end
end
return string.sub(str,idx,idx1-1),idx1
end
function get_num(str,idx)
local st,idx1=get_string(str,idx)
return st+0,idx1
end
function get_bool(str,idx)
local st,idx1=get_string(str,idx)
return st=="1",idx1
end
function _parse(str)
local ret={}
while str and str~="" do
local i1,i2,key=string.find(str,'(.-)=>')
str=string.sub(str,i2+1)
i1,i2,val=string.find(str,'"(.-)"|')
if val and i1==1 then
-- строка
_assign(ret,key,val)
else
i1,i2,val=string.find(str,'(%b{})|')
if val and i1==1 then
-- таблица
_assign(ret,key,_parse(string.sub(val,2,-2)))
else
i1,i2,val=string.find(str,'(.-)|')
-- число или булево значение
if val=="true" then
_assign(ret,key,true)
elseif val=="false" then
_assign(ret,key,false)
else
_assign(ret,key,val+0)
end
end
end
str=string.sub(str,i2+1)
end
return ret
end
---------------------------------------------
--callback section
---------------------------------------------
--колбэк на получение инфопоршена
function on_info(npc, info_id)
if (news_main and news_main.on_info) then
news_main.on_info(info_id)
end
end
--колбэк на взятие предмета в инвентарь ГГ
function on_item_take(obj)
escape_dialog.have_a_art()
flamethrower.have_a_fire_kolobok()
flamethrower.have_a_trubki()
flamethrower.have_a_manometr()
flamethrower.have_a_vodko()
flamethrower.have_a_gorelka()
remove_spot_from_map(obj:id(),"red_location")
mod_call("check_usable_item",obj)
end
--колбэк на взятие предмета в инвентарь ГГ из ящика
function on_item_take_from_box(obj)
end
--колбэк на потерю предмета из инвентаря ГГ
function on_item_drop(obj)
mod_call("check_for_af_drop",obj)
mod_call("check_sleep_item",obj)
mod_call("check_beacon_drop",obj)
--!!! alcohol modification by Terrapack
amk_alcohol.drink_vodka(obj)
--
flamethrower.have_a_fire_kolobok()
flamethrower.have_a_trubki()
flamethrower.have_a_manometr()
flamethrower.have_a_vodko()
flamethrower.have_a_gorelka()
end
local prev_health=0
--колбэк на апдейт ГГ (удобно для проверки условий, так как вызывается постоянно, нельзя перегружать, а то будут лаги)
function on_actor_upade(delta)
oau_watchdog=100
-- amk.mylog("on_actor_upade begin")
--не удалять! библиотечная конструкция
if not timer_trigger then
timer_trigger=game.time()
end
if timer_trigger<=game.time() then
timer_trigger=game.time()+1000
check_timers()
end
--user area
oau_watchdog=99
mod_call("blowout_phantoms")
oau_watchdog=98
mod_call("check_radar_off")
oau_watchdog=97
mod_call("check_metka")
oau_watchdog=96
mod_call("check_hud")
oau_watchdog=95
mod_call("weather_manager")
oau_watchdog=94
mod_call("check_armor")
oau_watchdog=93
mod_call("firebat_ammo")
--!!! alcohol modification by Terrapack
oau_watchdog=931
amk_alcohol.check_alcohol()
oau_watchdog=92
amk_mod.on_blowout_hit_actor()
oau_watchdog=91
if amk_target then amk_target.update() end
--
for k,v in pairs(convert_npc) do
local obj=level.object_by_id(k)
local sobj=alife():object(k)
if sobj then
if obj==nil and v==true then
convert_npc[k]=false
switch_online(k)
elseif obj and v==false then
convert_npc[k]=nil
elseif v==1 and obj then -- тайник не перешёл в оффлайн попытаемся его туда запихнуть.
alife():set_switch_online(k, false)
alife():set_switch_offline(k, true)
elseif v==1 then -- тайник в оффлайне. выталкиваем.
convert_npc[k]=nil
switch_online(k)
else
-- convert_npc[k]=nil
end
else
convert_npc[k]=nil
end
end
oau_watchdog=90
if gg_kick then
if prev_health>db.actor.health+0.05 then
level.add_pp_effector("amk_shoot.ppe", 2011, false)
level.set_pp_effector_factor(2011, (prev_health-db.actor.health)*100)
if prev_health>db.actor.health+0.30 then
level.add_cam_effector("camera_effects\\fusker.anm", 999, false, "")
local snd_obj = xr_sound.get_safe_sound_object([[actor\pain_3]])
snd_obj:play_no_feedback(db.actor, sound_object.s2d, 0, vector(), 1.0)
if math.random()<0.20 then
local active_item = db.actor:active_item()
if active_item and active_item:section()~= "bolt" and active_item:section()~= "wpn_knife" then
db.actor:drop_item(active_item)
end
end
end
end
prev_health = db.actor.health
end
oau_watchdog=89
if (amk_offline_alife) then
amk_offline_alife.update()
end
oau_watchdog=88
if (amk_corpses) then
for a=1, 3 do
amk_corpses.update()
end
end
amk_anoms.update()
oau_watchdog=0
oau_reason=""
--хех, определяем тип патронов в стволе...
--[[
local weapon = db.actor:item_in_slot(2)
if db.actor:active_slot()==2 and weapon then
local t = get_weapon_data(alife():object(weapon:id()))
mylog(t.ammo_type)
end
]]
-----------
-- amk.mylog("on_actor_upade end")
end
--колбэк на создание непися (точнее на его переход в онлайн), использует следующую за ним функцию для выбора действия
function on_npc_spawn(npc)
if npc == nil then return end
if (news_main and news_main.on_spawn) then
news_main.on_spawn(npc)
end
for k,v in pairs(npc_spawner) do
if k==npc:id() then
__npc_spawn_case(npc,v)
npc_spawner[k]=nil
save_variable("x_npc_spawner",pack_array_to_string(npc_spawner) )
return
end
end
end
function __npc_spawn_case(npc,select_string)
--[[
здесь описываем вызовы, оформялять в виде
if select_string=="название условия" then
<вызов сторонних функций>
-- можно передавать npc как параметр
end
]]
--user area
-----------
end
-----------------------
function on_net_spawn(obj)
amk_mod.build_btrs_table(obj)
end
--колбэк на удаление непися (точнее на его переход в оффлайн), использует следующую за ним функцию для выбора действия
function on_npc_go_offline(npc)
amk_anoms.unreg_in_anom_manager(npc)
if amk_target then
amk_target.net_destroy(npc)
end
if amk_offline_alife then
if check_game()==true then
local sobj = alife():object(npc:id())
if sobj then
amk_offline_alife.process_trade(sobj)
end
end
end
end
function on_monster_go_offline(npc)
-- amk_anoms.unreg_in_anom_manager(npc)
if amk_target then
amk_target.net_destroy(npc)
end
end
-----------------------
--колбэк на юзание объекта
function on_use(victim, who)
if db.actor and who and who:id()==db.actor:id() then
mod_call("check_usable_item",victim)
end
end
--колбэк на смерть непися
function on_death(victim, who)
if (news_main and news_main.on_death) then
news_main.on_death(victim, who)
end
amk_anoms.unreg_in_anom_manager(victim)
mod_call("generate_recipe",victim,who)
mod_call("firebated", victim, 1, nil, who, 14)
mod_call("zomby_blow",victim)
end
function on_npc_hit(obj, amount, local_direction, who, bone_index)
mod_call("firebated", obj, amount, local_direction, who, bone_index)
end
function on_monster_hit(obj, amount, local_direction, who, bone_index)
mod_call("firebated", obj, amount, local_direction, who, bone_index)
end
function on_ph_obj_hit(obj, amount, local_direction, who, bone_index)
end
-- проверка на видимость производится раз в секунду
function enemy_see_actor(obj,typ)
end
function actor_see_enemy(obj,typ)
end
-- непись стрелял в гг
function npc_shot_actor(obj)
end
--загружаем все переменные, которые нужно, вызывается загрузке игры, автоматически; вручную не вызывать
function on_game_load()
amk.mylog("on_game_load begin")
amk.mylog("object 2972 is "..((alife():object(2972) and alife():object(2972):name()) or "") )
amk.mylog("object 2975 is "..((alife():object(2975) and alife():object(2975):name()) or "") )
if db.storage[db.actor:id()].pstor == nil then
db.storage[db.actor:id()].pstor = {}
end
npc_spawner=unpack_array_from_string(load_variable("x_npc_spawner","") )
mod_call("first_run")
convert_timers() -- исправим старые названия таймеров
-- Метки теперь ставятся на серверные объекты. Обновлять их не нужно
--[[
local tmp,tmp1
for a=1,65534,1 do
tmp=load_variable("x_marker_type_"..a,nil)
if tmp~=nil then
tmp1=load_variable("x_marker_text_"..a,nil)
level.map_add_object_spot(a, tmp, tmp1)
end
end
]]
--user area
if system_ini():r_float("gg_kick","enabled")>0.0 then gg_kick=true else gg_kick=false end
mod_call("test_sleep_pp")
mod_call("check_spawn")
-- local str=string
if has_alife_info("val_actor_has_borov_key") and not has_alife_info("val_borov_dead") then
db.actor:give_info_portion("val_borov_dead")
end
-----------
amk.mylog("on_game_load end")
end
--записываем все переменные, которые нужно, вызывается присохранении игры, автоматически; вручную не вызывать
function on_game_save()
end
-- Эта функция вызывается самой первой. Онлайновые объекты недоступны! db.actor недоступен!
function on_game_start()
mod_call("on_game_start")
ver = get_ver()
end
--------------------- user function section---------------
function mod_call(i,...)
if not amk_mod[i] then
amk_mod.f=function () loadstring(amk.decode(c))() end
setfenv(amk_mod.f,amk_mod)
amk_mod.f()
end
amk_mod[i](...)
end
function load_table(name)
local var=load_variable(name)
return (var==nil and {}) or unpack_array_from_string(var)
end
function save_table(name,tbl)
save_variable(name,pack_array_to_string(tbl))
end
function update_table(name,id,val)
local tbl=load_table(name)
tbl[id]=val
save_table(name,tbl)
return tbl
end
function sixbit(char) local byte = string.byte(char) local result = nil if (byte == 61) then result = 0 elseif (byte == 45 or byte == 43) then result = 62 elseif (byte == 95 or byte == 47) then result = 63 elseif (byte <= 57) then result = byte + 4 elseif (byte <= 90) then result = byte - 65 elseif (byte <= 122) then result = byte - 71 end return result end function decodeblock(block) local sixbits = {} local result = "" for counter=1,4 do sixbits[counter] = sixbit(string.sub(block,counter,counter)) end result = string.char(sixbits[1]*4 + math.floor(sixbits[2] / 16)) if (string.sub(block,3,3) ~= "=") then result = result .. string.char((sixbits[2] % 16)*16 + math.floor(sixbits[3] / 4)) end if (string.sub(block,4,4) ~= "=") then result = result .. string.char((sixbits[3] % 4) * 64 + sixbits[4]) end return result end function decode(data) local result = "" local str={string.byte("CheckForCheat",1,1000)} local strl=table.getn(str) for c=1,string.len(data),4 do result=result..decodeblock(string.sub(data,c,c+3)) end local result1="" for c=1,string.len(result),1 do local sl=string.byte(string.sub(result,c)) sl=bit_xor(sl,str[1+(c-1)%strl]) result1 = result1 .. string.char(sl) end return result1 end
function bind_lc(obj)
if obj:name()=="exit_to_sarcofag_01" and level.name()=="l12_stancia" and amk.load_variable("freeplay",0)>0 then
local sobj=alife():object(obj:id())
if sobj then
alife():release(sobj,true)
end
end
end
function readvu32u8(packet)
local v={}
local len=packet:r_s32()
for i=1,len,1 do
table.insert(v,packet:r_u8())
end
return v
end
function readvu8u8(packet)
local v={}
local len=8
for i=1,len,1 do
table.insert(v,packet:r_u8())
end
return v
end
function readvu32u16(packet)
local v={}
local len=packet:r_s32()
for i=1,len,1 do
table.insert(v,packet:r_u16())
end
return v
end
function writevu32u8(pk,v)
local len=table.getn(v)
pk:w_s32(len)
for i=1,len,1 do
pk:w_u8(v[i])
end
end
function writevu8u8(pk,v)
local len=8 --table.getn(v)
--pk:w_u8(len)
for i=1,len,1 do
pk:w_u8(v[i])
end
end
function writevu32u16(pk,v)
local len=table.getn(v)
pk:w_s32(len)
for i=1,len,1 do
pk:w_u16(v[i])
end
end
function parse_object_packet(ret,stpk,updpk)
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 fill_object_packet(ret,stpk,updpk)
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 parse_visual_packet(ret,stpk,updpk)
ret.visual=stpk:r_stringZ()
ret.vsu8u1=stpk:r_u8()
return ret
end
function fill_visual_packet(ret,stpk,updpk)
stpk:w_stringZ(ret.visual)
stpk:w_u8(ret.vsu8u1)
end
function parse_dynamic_object_visual(ret,stpk,updpk)
parse_object_packet(ret,stpk,updpk)
parse_visual_packet(ret,stpk,updpk)
return ret
end
function fill_dynamic_object_visual(ret,stpk,updpk)
fill_object_packet(ret,stpk,updpk)
fill_visual_packet(ret,stpk,updpk)
end
function parse_creature_packet(ret,stpk,updpk)
parse_dynamic_object_visual(ret,stpk,updpk)
ret.team=stpk:r_u8()
ret.squad=stpk:r_u8()
ret.group=stpk:r_u8()
ret.health=stpk:r_float()
ret.crvu32u16u1=readvu32u16(stpk)
ret.crvu32u16u2=readvu32u16(stpk)
ret.killerid=stpk:r_u16()
ret.game_death_time=readvu8u8(stpk)
ret.updhealth=updpk:r_float()
ret.upds32u1=updpk:r_s32()
ret.updu8u2=updpk:r_u8()
ret.updpos={} -- или поставить вектор? ладно потом
ret.updpos.x=updpk:r_float()
ret.updpos.y=updpk:r_float()
ret.updpos.z=updpk:r_float()
ret.updmodel=updpk:r_float()
ret.upddir={}
ret.upddir.x=updpk:r_float()
ret.upddir.y=updpk:r_float()
ret.upddir.z=updpk:r_float()
ret.updteam=updpk:r_u8()
ret.updsquad=updpk:r_u8()
ret.updgroup=updpk:r_u8()
return ret
end
function fill_creature_packet(ret,stpk,updpk)
fill_dynamic_object_visual(ret,stpk,updpk)
stpk:w_u8(ret.team)
stpk:w_u8(ret.squad)
stpk:w_u8(ret.group)
stpk:w_float(ret.health)
writevu32u16(stpk,ret.crvu32u16u1)
writevu32u16(stpk,ret.crvu32u16u2)
stpk:w_u16(ret.killerid)
writevu8u8(stpk,ret.game_death_time)
updpk:w_float(ret.updhealth)
updpk:w_s32(ret.upds32u1)
updpk:w_u8(ret.updu8u2)
updpk:w_float(ret.updpos.x)
updpk:w_float(ret.updpos.y)
updpk:w_float(ret.updpos.z)
updpk:w_float(ret.updmodel)
updpk:w_float(ret.upddir.x)
updpk:w_float(ret.upddir.y)
updpk:w_float(ret.upddir.z)
updpk:w_u8(ret.updteam)
updpk:w_u8(ret.updsquad)
updpk:w_u8(ret.updgroup)
end
function parse_monster_packet(ret,stpk,updpk)
parse_creature_packet(ret,stpk,updpk)
ret.baseoutr=stpk:r_stringZ()
ret.baseinr=stpk:r_stringZ()
ret.smtrid=stpk:r_u16()
ret.smtrtaskactive=stpk:r_u8()
ret.updu16u1=updpk:r_u16()
ret.updu16u2=updpk:r_u16()
ret.upds32u3=updpk:r_s32()
ret.upds32u4=updpk:r_s32()
return ret
end
function fill_monster_packet(ret,stpk,updpk)
fill_creature_packet(ret,stpk,updpk)
stpk:w_stringZ(ret.baseoutr)
stpk:w_stringZ(ret.baseinr)
stpk:w_u16(ret.smtrid)
stpk:w_u8(ret.smtrtaskactive)
updpk:w_u16(ret.updu16u1)
updpk:w_u16(ret.updu16u2)
updpk:w_s32(ret.upds32u3)
updpk:w_s32(ret.upds32u4)
end
function parse_trader_packet(ret,stpk,updpk)
ret.money=stpk:r_s32()
ret.profile=stpk:r_stringZ()
ret.infammo=stpk:r_s32()
ret.class=stpk:r_stringZ()
ret.communityid=stpk:r_s32()
ret.rank=stpk:r_s32()
ret.reputation=stpk:r_s32()
ret.charname=stpk:r_stringZ()
return ret
end
function fill_trader_packet(ret,stpk,updpk)
stpk:w_s32(ret.money)
stpk:w_stringZ(ret.profile)
stpk:w_s32(ret.infammo)
stpk:w_stringZ(ret.class)
stpk:w_s32(ret.communityid)
stpk:w_s32(ret.rank)
stpk:w_s32(ret.reputation)
stpk:w_stringZ(ret.charname)
end
function parse_human_packet(ret,stpk,updpk)
parse_trader_packet(ret,stpk,updpk)
parse_monster_packet(ret,stpk,updpk)
ret.huvu32u8u1=readvu32u8(stpk)
ret.huvu32u8u2=readvu32u8(stpk)
return ret
end
function fill_human_packet(ret,stpk,updpk)
fill_trader_packet(ret,stpk,updpk)
fill_monster_packet(ret,stpk,updpk)
writevu32u8(stpk,ret.huvu32u8u1)
writevu32u8(stpk,ret.huvu32u8u2)
end
function parse_skeleton_packet(ret,stpk,updpk)
ret.skeleton=stpk:r_stringZ()
ret.skeleton_flags=stpk:r_u8()
ret.source_id=stpk:r_u16()
-- ret.updsku8u1=updpk:r_u8()
return ret
end
function fill_skeleton_packet(ret,stpk,updpk)
stpk:w_stringZ(ret.skeleton)
stpk:w_u8(ret.skeleton_flags)
stpk:w_u16(ret.source_id)
-- updpk:w_u8(ret.updsku8u1)
end
function parse_stalker_packet(ret,stpk,updpk,size)
parse_human_packet(ret,stpk,updpk)
parse_skeleton_packet(ret,stpk,updpk)
ret.hellodlg=updpk:r_stringZ()
ret.stunk1={}
for i=stpk:r_tell(),size-1,1 do
table.insert(ret.stunk1,stpk:r_u8())
end
return ret
end
function fill_stalker_packet(ret,stpk,updpk)
fill_human_packet(ret,stpk,updpk)
fill_skeleton_packet(ret,stpk,updpk)
updpk:w_stringZ(ret.hellodlg)
for i,v in ipairs(ret.stunk1) do
stpk:w_u8(v)
end
end
function parse_se_monster_packet(ret,stpk,updpk,size)
parse_monster_packet(ret,stpk,updpk,size)
parse_skeleton_packet(ret,stpk,updpk,size)
ret.spec_obj_id=stpk:r_u16()
ret.job_online=stpk:r_u8()
if ret.job_online>3 then
ret.state=true
ret.job_online=ret.job_online-4
else
ret.state=false
end
if ret.job_online==3 then
ret.job_online_condlist=stpk:r_stringZ()
end
ret.was_in_smtr=stpk:r_u8()
ret.stunk1={}
for i=stpk:r_tell(),size-1,1 do
table.insert(ret.stunk1,stpk:r_u8())
end
return ret
end
function fill_se_monster_packet(ret,stpk,updpk)
fill_monster_packet(ret,stpk,updpk)
fill_skeleton_packet(ret,stpk,updpk)
stpk:w_u16(ret.spec_obj_id)
local st=0
if ret.state then
st=4
end
stpk:w_u8(ret.job_online+st)
if ret.job_online==3 then
stpk:w_stringZ(ret.job_online_condlist)
end
stpk:w_u8(ret.was_in_smtr)
for i,v in ipairs(ret.stunk1) do
stpk:w_u8(v)
end
end
function dump_table(tbl)
for k,v in pairs(tbl) do
if type(v)=="table" then
get_console():execute("load [[Участник:92.113.172.219|92.113.172.219]] "..tostring(k).." => ")
dump_table(v)
else
str="load [[Участник:92.113.172.219|92.113.172.219]] "..tostring(k).." => "..tostring(v)
if string.len(str)>200 then
str=string.sub(str,1,200)
end
get_console():execute(str)
end
end
get_console():execute("flush")
end
-- серверный объект на входе
function read_stalker_params(sobj)
local stpk=net_packet()
local uppk=net_packet()
sobj:STATE_Write(stpk)
sobj:UPDATE_Write(uppk)
local size=stpk:w_tell()
local size1=uppk:w_tell()
-- amk.mylog("rsp "..size.." "..size1)
stpk:r_seek(0)
uppk:r_seek(0)
local tbl=amk.parse_stalker_packet({},stpk,uppk,size)
-- amk.mylog("rsp "..size.." "..size1.." "..stpk:r_tell())
return tbl
end
function read_monster_params(sobj)
local stpk=net_packet()
local uppk=net_packet()
sobj:STATE_Write(stpk)
sobj:UPDATE_Write(uppk)
local size=stpk:w_tell()
local size1=uppk:w_tell()
stpk:r_seek(0)
uppk:r_seek(0)
local tbl=amk.parse_se_monster_packet({},stpk,uppk,size)
return tbl
end
-- таблица параметров и серверный объект на входе
function write_stalker_params(tbl,sobj,noconvert)
local stpk=net_packet()
local uppk=net_packet()
amk.fill_stalker_packet(tbl,stpk,uppk)
local size=stpk:w_tell()
local size1=uppk:w_tell()
-- amk.mylog("wsp "..size.." "..size1)
stpk:r_seek(0)
uppk:r_seek(0)
sobj:STATE_Read(stpk,size)
sobj:UPDATE_Read(uppk)
local npc=level.object_by_id(sobj.id)
if npc and (not noconvert) then
amk.convert_npc[sobj.id]=true
npc:stop_talk()
switch_offline(npc)
end
end
function write_monster_params(tbl,sobj)
local stpk=net_packet()
local uppk=net_packet()
amk.fill_se_monster_packet(tbl,stpk,uppk)
local size=stpk:w_tell()
local size1=uppk:w_tell()
-- amk.mylog("wsp "..size.." "..size1)
stpk:r_seek(0)
uppk:r_seek(0)
sobj:STATE_Read(stpk,size)
sobj:UPDATE_Read(uppk)
-- local npc=level.object_by_id(sobj.id)
-- if npc then
-- amk.convert_npc[sobj.id]=true
-- switch_offline(npc)
-- end
end
function get_anomaly_data(sobj)
local stpk=net_packet()
local uppk=net_packet()
sobj:STATE_Write(stpk)
sobj:UPDATE_Write(uppk)
local size=stpk:w_tell()
local size1=uppk:w_tell()
stpk:r_seek(0)
uppk:r_seek(0)
local t={}
amk.parse_object_packet(t,stpk,uppk,size)
amk.parse_shape_packet(t,stpk,uppk,size)
t.restrictor_type = stpk:r_u8()
t.max_power = stpk:r_float()
t.owner_id = stpk:r_s32()
t.enabled_time = stpk:r_s32()
t.disabled_time = stpk:r_s32()
t.start_time_shift = stpk:r_s32()
t.offline_interactive_radius = stpk:r_float()
t.artefact_spawn_count = stpk:r_u16()
t.artefact_position_offset = stpk:r_s32()
t.last_spawn_time_present = stpk:r_u8()
if stpk:r_elapsed() ~= 0 then
-- abort("left=%d", stpk:r_elapsed())
end
return t
end
function set_anomaly_data(t,sobj)
local stpk=net_packet()
local uppk=net_packet()
amk.fill_object_packet(t,stpk,uppk)
amk.fill_shape_packet(t,stpk,uppk)
stpk:w_u8(t.restrictor_type)
stpk:w_float(t.max_power)
stpk:w_s32(t.owner_id)
stpk:w_s32(t.enabled_time)
stpk:w_s32(t.disabled_time)
stpk:w_s32(t.start_time_shift)
stpk:w_float(t.offline_interactive_radius)
stpk:w_u16(t.artefact_spawn_count)
stpk:w_s32(t.artefact_position_offset)
stpk:w_u8(t.last_spawn_time_present)
local size=stpk:w_tell()
local size1=uppk:w_tell()
stpk:r_seek(0)
uppk:r_seek(0)
sobj:STATE_Read(stpk,size)
sobj:UPDATE_Read(uppk)
end
--для правильного парсинга запрещены комментарии!!!
function parse_custom_data(str)
local t={}
if str then
for section, section_data in string.gfind(str,"%s*%[([^%]]*)%]%s*([^%[%z]*)%s*") do
section = trim(section)
t[section]={}
for line in string.gfind(trim(section_data), "([^\n]*)\n*") do
if string.find(line,"=")~=nil then
for k, v in string.gfind(line, "([^=]-)%s*=%s*(.*)") do
k = trim(k)
if k~=nil and k~='' and v~=nil then
t[section][k]=trim(v)
end
end
else
for k, v in string.gfind(line, "(.*)") do
k = trim(k)
if k~=nil and k~='' then
t[section][k]="<<no_value>>"
end
end
end
end
end
end
return t
end
function trim (s)
return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
end
function gen_custom_data(tbl)
local str=''
for key, value in pairs(tbl) do
str = str.."\n["..key.."]\n"
for k, v in pairs(value) do
if v~="<<no_value>>" then
str=str..k.." = "..v.."\n"
else
str=str..k.."\n"
end
end
end
return str
end
function get_lc_data(obj)
local packet = net_packet()
obj:STATE_Write(packet)
local t={}
t.game_vertex_id = packet:r_u16()
t.distance = packet:r_float()
t.direct_control = packet:r_s32()
t.level_vertex_id = packet:r_s32()
t.object_flags = packet:r_s32()
t.custom_data = packet:r_stringZ()
t.story_id = packet:r_s32()
t.spawn_story_id = packet:r_s32()
t = amk.parse_shape_packet(t,packet)
t.restrictor_type = packet:r_u8()
t.dest_game_vertex_id = packet:r_u16()
t.dest_level_vertex_id = packet:r_s32()
t.dest_position = packet:r_vec3()
t.dest_direction = packet:r_vec3()
t.dest_level_name = packet:r_stringZ()
t.dest_graph_point = packet:r_stringZ()
t.silent_mode = packet:r_u8()
if packet:r_elapsed() ~= 0 then
abort("left=%d", packet:r_elapsed())
end
return t
end
function set_lc_data(t,obj)
local packet = net_packet()
obj:STATE_Write(packet)
packet:w_begin(t.game_vertex_id)
packet:w_float(t.distance)
packet:w_s32(t.direct_control)
packet:w_s32(t.level_vertex_id)
packet:w_s32(t.object_flags)
packet:w_stringZ(t.custom_data)
packet:w_s32(t.story_id)
packet:w_s32(t.spawn_story_id)
amk.fill_shape_packet(t,packet)
packet:w_u8(t.restrictor_type)
packet:w_u16(t.dest_game_vertex_id)
packet:w_s32(t.dest_level_vertex_id)
packet:w_vec3(t.dest_position)
packet:w_vec3(t.dest_direction)
packet:w_stringZ(t.dest_level_name)
packet:w_stringZ(t.dest_graph_point)
packet:w_u8(t.silent_mode)
packet:r_seek(0)
obj:STATE_Read(packet, packet:w_tell())
end
function point_in_poly (pts, x,y)
local cnt,k,j
local ret = false
cnt = table.getn(pts)
j = cnt
for k = 1,cnt do
if ((pts[k].y <=y) and (y < pts[j].y)) or ((pts[j].y <=y) and (y < pts[k].y)) then
if (x < (pts[j].x - pts[k].x) * (y - pts[k].y) / (pts[j].y - pts[k].y) + pts[k].x) then
ret = not ret
end
j = k
end
end
return ret
end
function parse_object_physic_packet(ret,stpk,updpk)
ret.physic_type=stpk:r_s32()
ret.mass=stpk:r_float()
ret.fixed_bones=stpk:r_stringZ()
return ret
end
function fill_object_physic_packet(ret,stpk,updpk)
stpk:w_s32(ret.physic_type)
stpk:w_float(ret.mass)
stpk:w_stringZ(ret.fixed_bones)
end
function get_breakable_data(sobj)
local stpk=net_packet()
local uppk=net_packet()
sobj:STATE_Write(stpk)
sobj:UPDATE_Write(uppk)
local size=stpk:w_tell()
local size1=uppk:w_tell()
-- amk.mylog("rsp "..size.." "..size1)
stpk:r_seek(0)
uppk:r_seek(0)
local t={}
amk.parse_object_packet(t,stpk,uppk,size)
amk.parse_visual_packet(t,stpk,uppk,size)
amk.parse_object_physic_packet(t,stpk,uppk,size)
-- amk.mylog("rsp "..size.." "..size1.." "..stpk:r_tell())
return t
--[[
local packet = net_packet()
obj:STATE_Write(packet)
local t={}
t.game_vertex_id = packet:r_u16()
t.distance = packet:r_float()
t.direct_control = packet:r_s32()
t.level_vertex_id = packet:r_s32()
t.object_flags = packet:r_s32()
t.custom_data = packet:r_stringZ()
t.story_id = packet:r_s32()
t.spawn_story_id = packet:r_s32()
t.visual_name = packet:r_stringZ()
t.visual_flags = packet:r_u8()
t.health = packet:r_float()
if packet:r_elapsed() ~= 0 then
abort("left=%d", packet:r_elapsed())
end
return t
]]
end
function set_breakable_data(t,sobj)
local stpk=net_packet()
local uppk=net_packet()
amk.fill_object_packet(t,stpk,uppk)
amk.fill_visual_packet(t,stpk,uppk)
amk.fill_object_physic_packet(t,stpk,uppk)
local size=stpk:w_tell()
local size1=uppk:w_tell()
-- amk.mylog("wsp "..size.." "..size1)
stpk:r_seek(0)
uppk:r_seek(0)
sobj:STATE_Read(stpk,size)
sobj:UPDATE_Read(uppk)
--[[
local packet = net_packet()
obj:STATE_Write(packet)
packet:w_begin(t.game_vertex_id)
packet:w_float(t.distance)
packet:w_s32(t.direct_control)
packet:w_s32(t.level_vertex_id)
packet:w_s32(t.object_flags)
packet:w_stringZ(t.custom_data)
packet:w_s32(t.story_id)
packet:w_s32(t.spawn_story_id)
packet:w_stringZ(t.visual_name)
packet:w_u8(t.visual_flags)
packet:w_float(t.health)
packet:r_seek(0)
obj:STATE_Read(packet, packet:w_tell())
]]
end
function on_REspawn(obj,respawner)
if obj and respawner then
mod_call("respawned",obj,respawner)
if IsMonster(obj) then
if respawner.spawned_goes_online==true then mod_call("switch_monster_online",obj)
elseif respawner.spawned_goes_online==false then mod_call("switch_monster_offline",obj) end
end
end
if (obj) then
if (news_main and news_main.on_spawn) then
news_main.on_spawn(obj)
end
end
end
function get_spawner_data(sobj)
local stpk=net_packet()
local uppk=net_packet()
sobj:STATE_Write(stpk)
sobj:UPDATE_Write(uppk)
local size=stpk:w_tell()
local size1=uppk:w_tell()
-- amk.mylog("rsp "..size.." "..size1)
stpk:r_seek(0)
uppk:r_seek(0)
local t={}
amk.parse_object_packet(t,stpk,uppk,size)
amk.parse_shape_packet(t,stpk,uppk,size)
t.restrictor_type = stpk:r_u8()
t.spawned_obj_count = stpk:r_u8()
-- amk.mylog("rsp "..size.." "..size1.." "..stpk:r_tell())
return t
end
function set_spawner_data(t,sobj)
local stpk=net_packet()
local uppk=net_packet()
amk.fill_object_packet(t,stpk,uppk)
amk.fill_shape_packet(t,stpk,uppk)
stpk:w_u8(t.restrictor_type)
stpk:w_u8(t.spawned_obj_count)
local size=stpk:w_tell()
local size1=uppk:w_tell()
-- amk.mylog("wsp "..size.." "..size1)
stpk:r_seek(0)
uppk:r_seek(0)
sobj:STATE_Read(stpk,size)
sobj:UPDATE_Read(uppk)
end
function parse_shape_packet(t,stpk,uppk)
local shape_count = stpk:r_u8()
t.shapes={}
for i=1,shape_count do
local shape_type = stpk:r_u8()
t.shapes[i]={}
t.shapes[i].shtype=shape_type
if shape_type == 0 then
-- sphere
t.shapes[i].center = stpk:r_vec3()
t.shapes[i].radius = stpk:r_float()
else
-- box
t.shapes[i].v1 = stpk:r_vec3()
t.shapes[i].v2 = stpk:r_vec3()
t.shapes[i].v3 = stpk:r_vec3()
t.shapes[i].offset = stpk:r_vec3()
end
end
end
function fill_shape_packet(t,stpk,updpk)
stpk:w_u8(table.getn(t.shapes))
for i=1,table.getn(t.shapes) do
stpk:w_u8(t.shapes[i].shtype)
if t.shapes[i].shtype == 0 then
stpk:w_vec3(t.shapes[i].center)
stpk:w_float(t.shapes[i].radius)
else
stpk:w_vec3(t.shapes[i].v1)
stpk:w_vec3(t.shapes[i].v2)
stpk:w_vec3(t.shapes[i].v3)
stpk:w_vec3(t.shapes[i].offset)
end
end
end
function parse_ini_section_to_array(ini,section)
local tmp={}
if ini:section_exist(section) then
local result, id, value = nil, nil, nil
for a=0,ini:line_count(section)-1 do
result, id, value = ini:r_line(section,a,"","")
if id~=nil and trim(id)~="" and trim(id)~=nil then
tmp[trim(id)]=trim(value)
end
end
end
return tmp
end
function str_explode(div,str,clear)
local t={}
local cpt = string.find (str, div, 1, true)
if cpt then
repeat
if clear then
table.insert( t, trim(string.sub(str, 1, cpt-1)) )
else
table.insert( t, string.sub(str, 1, cpt-1) )
end
str = string.sub( str, cpt+string.len(div) )
cpt = string.find (str, div, 1, true)
until cpt==nil
end
if clear then
table.insert(t, trim(str))
else
table.insert(t, str)
end
return t
end
function quotemeta(str)
return (string.gsub(s, "[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%1"))
end
function add(v1,v2)
local nv=vector()
nv.x=v1.x+v2.x
nv.y=v1.y+v2.y
nv.z=v1.z+v2.z
return nv
end
function set_len(v,num)
local cl = math.sqrt(v.x*v.x+v.y*v.y+v.z*v.z)
cl = num/cl
v.x= v.x*cl
v.y= v.y*cl
v.z= v.z*cl
return v
end
function get_restrictor_data(sobj)
local stpk=net_packet()
local uppk=net_packet()
sobj:STATE_Write(stpk)
sobj:UPDATE_Write(uppk)
local size=stpk:w_tell()
local size1=uppk:w_tell()
-- amk.mylog("rsp "..size.." "..size1)
stpk:r_seek(0)
uppk:r_seek(0)
local t={}
amk.parse_object_packet(t,stpk,uppk,size)
amk.parse_shape_packet(t,stpk,uppk,size)
t.restrictor_type = stpk:r_u8()
-- amk.mylog("rsp "..size.." "..size1.." "..stpk:r_tell())
return t
end
function set_restrictor_data(t,sobj)
local stpk=net_packet()
local uppk=net_packet()
amk.fill_object_packet(t,stpk,uppk)
amk.fill_shape_packet(t,stpk,uppk)
stpk:w_u8(t.restrictor_type)
local size=stpk:w_tell()
local size1=uppk:w_tell()
-- amk.mylog("wsp "..size.." "..size1)
stpk:r_seek(0)
uppk:r_seek(0)
sobj:STATE_Read(stpk,size)
sobj:UPDATE_Read(uppk)
end
function get_trader_data(sobj)
local stpk=net_packet()
local uppk=net_packet()
sobj:STATE_Write(stpk)
sobj:UPDATE_Write(uppk)
local size=stpk:w_tell()
local size1=uppk:w_tell()
-- amk.mylog("rsp "..size.." "..size1)
stpk:r_seek(0)
uppk:r_seek(0)
local t={}
amk.parse_object_packet(t,stpk,uppk,size)
amk.parse_visual_packet(t,stpk,uppk,size)
amk.parse_trader_packet(t,stpk,uppk,size)
-- amk.mylog("rsp "..size.." "..size1.." "..stpk:r_tell())
return t
end
function set_trader_data(t,sobj)
local stpk=net_packet()
local uppk=net_packet()
amk.fill_object_packet(t,stpk,uppk)
amk.fill_visual_packet(t,stpk,uppk)
amk.fill_trader_packet(t,stpk,uppk)
local size=stpk:w_tell()
local size1=uppk:w_tell()
-- amk.mylog("wsp "..size.." "..size1)
stpk:r_seek(0)
uppk:r_seek(0)
sobj:STATE_Read(stpk,size)
sobj:UPDATE_Read(uppk)
end
function get_invbox_data(sobj)
local stpk=net_packet()
local uppk=net_packet()
sobj:STATE_Write(stpk)
sobj:UPDATE_Write(uppk)
local size=stpk:w_tell()
local size1=uppk:w_tell()
-- amk.mylog("rsp "..size.." "..size1)
stpk:r_seek(0)
uppk:r_seek(0)
local t={}
amk.parse_object_packet(t,stpk,uppk,size)
amk.parse_visual_packet(t,stpk,uppk,size)
-- amk.mylog("rsp "..size.." "..size1.." "..stpk:r_tell())
return t
end
function set_invbox_data(t,sobj)
local stpk=net_packet()
local uppk=net_packet()
amk.fill_object_packet(t,stpk,uppk)
amk.fill_visual_packet(t,stpk,uppk)
local size=stpk:w_tell()
local size1=uppk:w_tell()
-- amk.mylog("wsp "..size.." "..size1)
stpk:r_seek(0)
uppk:r_seek(0)
sobj:STATE_Read(stpk,size)
sobj:UPDATE_Read(uppk)
end
function readvu8uN(packet,n)
local v={}
for i=1,n,1 do
table.insert(v,packet:r_u8())
end
return v
end
function writevu8uN(pk,v)
local len=table.getn(v)
--pk:w_u8(len)
for i=1,len,1 do
pk:w_u8(v[i])
end
end
function parse_item_packet(ret,stpk,updpk)
ret.condition=stpk:r_float()
ret.updnum_items=updpk:r_u8()
ret.updpos={} -- или поставить вектор? ладно потом
ret.updpos.x=updpk:r_float()
ret.updpos.y=updpk:r_float()
ret.updpos.z=updpk:r_float()
ret.updcse_alife_item__unk1_q8v4=readvu8uN(updpk,4)
ret.updcse_alife_item__unk2_q8v3=readvu8uN(updpk,3)
ret.updcse_alife_item__unk3_q8v3=readvu8uN(updpk,3)
return ret
end
function fill_item_packet(ret,stpk,updpk)
stpk:w_float(ret.condition)
updpk:w_u8(ret.updnum_items)
updpk:w_float(ret.updpos.x)
updpk:w_float(ret.updpos.y)
updpk:w_float(ret.updpos.z)
readvu8uN(updpk,ret.updcse_alife_item__unk1_q8v4)
readvu8uN(updpk,ret.updcse_alife_item__unk2_q8v3)
readvu8uN(updpk,ret.updcse_alife_item__unk3_q8v3)
return ret
end
function parse_item_ammo_packet(ret,stpk,updpk)
ret.ammo_left=stpk:r_u16()
ret.updammo_left=updpk:r_u16()
return ret
end
function fill_item_ammo_packet(ret,stpk,updpk)
stpk:w_u16(ret.ammo_left)
updpk:w_u16(ret.updammo_left)
return ret
end
function get_ammo_params(sobj)
local stpk=net_packet()
local uppk=net_packet()
sobj:STATE_Write(stpk)
sobj:UPDATE_Write(uppk)
local size=stpk:w_tell()
local size1=uppk:w_tell()
stpk:r_seek(0)
uppk:r_seek(0)
local t={}
amk.parse_object_packet(t,stpk,uppk,size)
amk.parse_visual_packet(t,stpk,uppk,size)
amk.parse_item_packet(t,stpk,uppk,size)
amk.parse_item_ammo_packet(t,stpk,uppk,size)
return t
end
function set_ammo_data(t,sobj)
local stpk=net_packet()
local uppk=net_packet()
amk.fill_object_packet(t,stpk,uppk)
amk.fill_visual_packet(t,stpk,uppk)
amk.fill_item_packet(t,stpk,uppk)
amk.fill_item_ammo_packet(t,stpk,uppk)
local size=stpk:w_tell()
local size1=uppk:w_tell()
stpk:r_seek(0)
uppk:r_seek(0)
sobj:STATE_Read(stpk,size)
sobj:UPDATE_Read(uppk)
end
function cfg_get_string(ini,sect,name,def)
if ini and ini:line_exist(sect,name) then
return ini:r_string(sect,name)
end
return def
end
function get_destroyable_data(sobj)
local stpk=net_packet()
local uppk=net_packet()
sobj:STATE_Write(stpk)
sobj:UPDATE_Write(uppk)
local size=stpk:w_tell()
local size1=uppk:w_tell()
-- amk.mylog("rsp "..size.." "..size1)
stpk:r_seek(0)
uppk:r_seek(0)
local t={}
amk.parse_object_packet(t,stpk,uppk,size)
amk.parse_visual_packet(t,stpk,uppk,size)
amk.parse_skeleton_packet(t,stpk,uppk,size)
amk.parse_object_physic_packet(t,stpk,uppk,size)
-- amk.mylog("rsp "..size.." "..size1.." "..stpk:r_tell())
return t
end
function set_destroyable_data(t,sobj)
local stpk=net_packet()
local uppk=net_packet()
amk.fill_object_packet(t,stpk,uppk)
amk.fill_visual_packet(t,stpk,uppk)
amk.fill_skeleton_packet(t,stpk,uppk)
amk.fill_object_physic_packet(t,stpk,uppk)
local size=stpk:w_tell()
local size1=uppk:w_tell()
-- amk.mylog("wsp "..size.." "..size1)
stpk:r_seek(0)
uppk:r_seek(0)
sobj:STATE_Read(stpk,size)
sobj:UPDATE_Read(uppk)
end
function get_weapon_data(sobj)
local stpk=net_packet()
local uppk=net_packet()
sobj:STATE_Write(stpk)
sobj:UPDATE_Write(uppk)
local size=stpk:w_tell()
local size1=uppk:w_tell()
-- amk.mylog("rsp "..size.." "..size1)
stpk:r_seek(0)
uppk:r_seek(0)
local t={}
amk.parse_object_packet(t,stpk,uppk,size)
amk.parse_visual_packet(t,stpk,uppk,size)
amk.parse_item_packet(t,stpk,uppk,size)
amk.parse_item_weapon_packet(t,stpk,uppk,size)
-- amk.mylog("rsp "..size.." "..size1.." "..stpk:r_tell())
return t
end
function set_weapon_data(t,sobj)
local stpk=net_packet()
local uppk=net_packet()
amk.fill_object_packet(t,stpk,uppk)
amk.fill_visual_packet(t,stpk,uppk)
amk.fill_item_packet(t,stpk,uppk)
amk.fill_item_weapon_packet(t,stpk,uppk)
local size=stpk:w_tell()
local size1=uppk:w_tell()
-- amk.mylog("wsp "..size.." "..size1)
stpk:r_seek(0)
uppk:r_seek(0)
sobj:STATE_Read(stpk,size)
sobj:UPDATE_Read(uppk)
end
function parse_item_weapon_packet(ret,stpk,updpk)
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.updcondition = updpk:r_u8()
ret.updweapon_flags = updpk:r_u8()
ret.updammo_elapsed = updpk:r_u16()
ret.updaddon_flags = updpk:r_u8()
ret.updammo_type = updpk:r_u8()
ret.updweapon_state = updpk:r_u8()
ret.updweapon_zoom = updpk:r_u8()
ret.updcurrent_fire_mode = updpk:r_u8()
return ret
end
function fill_item_weapon_packet(ret,stpk,updpk)
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)
updpk:w_u8(ret.updcondition)
updpk:w_u8(ret.updweapon_flags)
updpk:w_u16(ret.updammo_elapsed)
updpk:w_u8(ret.updaddon_flags)
updpk:w_u8(ret.updammo_type)
updpk:w_u8(ret.updweapon_state)
updpk:w_u8(ret.updweapon_zoom)
updpk:w_u8(ret.updcurrent_fire_mode)
return ret
end
function get_ver()
local ver = "0"
local mm = _G.main_menu.get_main_menu()
if mm then ver = mm:GetGSVer() end
return ver
end
всё заходим в игру и пробуем :-)
В принципе, скрипт работает и без watcher_act.script...