From b0231f8183e65be6e88d1e914b9184c23bf6b4df Mon Sep 17 00:00:00 2001 From: Kaan Soral Date: Tue, 10 Sep 2019 20:27:46 +0300 Subject: [PATCH] Update runner_functions.js --- runner_functions.js | 251 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 202 insertions(+), 49 deletions(-) diff --git a/runner_functions.js b/runner_functions.js index 9fb0775..3fafc0c 100644 --- a/runner_functions.js +++ b/runner_functions.js @@ -8,10 +8,12 @@ var character={ // Added this wrapper so instead of using .real_x and .real_y on all entities, .x and .y's can be used uniformly "note":"This is a proxy object, the real character is in parent.character", "properties":["x","y"], + "read_only":["x","y","real_x","real_y","from_x","from_y","going_x","going_y","moving","target","vx","vy","move_num","attack","speed","hp","mp","xp","max_hp","max_mp","range","level","rip","s","c","in","map","stand","items","slots"], + "proxy_character":true, } -Object.defineProperty(character,'x',{get:function(){return parent.character.real_x;},set:function(){game_log("You can't set coordinates manually, use the move(x,y) function!");}}); -Object.defineProperty(character,'y',{get:function(){return parent.character.real_y;},set:function(){game_log("You can't set coordinates manually, use the move(x,y) function!");}}); +Object.defineProperty(character,'x',{get:function(){return parent.character.real_x;},set:function(){game_log("You can't set coordinates manually, use the move(x,y) function!");},enumerable:true}); +Object.defineProperty(character,'y',{get:function(){return parent.character.real_y;},set:function(){game_log("You can't set coordinates manually, use the move(x,y) function!");},enumerable:true}); for(var p in parent.character) proxy(p); // Not all properties are sadly available right away, new properties are captured imperfectly // var character=parent.character; // Old [25/06/2018] @@ -124,6 +126,18 @@ function use_skill(name,target) parent.use_skill(name,target); } +function reduce_cooldown(name,ms) +{ + // parent.next_skill contains Date objects of when the skills will be available next + // show_json(parent.next_skill) to get a better idea + // reduce_cooldown("attack",100) would cause the attack cooldown to reduce by 100 ms + // If your ping is 100+ms - this would ~correct/improve/adjust the cooldown + // attack(target).then(function(data){ reduce_cooldown("attack",character.ping*0.95); }); + // Above call is likely the ideal usage + if(parent.next_skill[name]) + parent.skill_timeout(name,-mssince(parent.next_skill[name])-ms); +} + function bank_deposit(gold) { if(!character.bank) return game_log("Not inside the bank"); @@ -260,7 +274,14 @@ function set_message(text,color) function game_log(message,color) { if(!color) color="#51D2E1"; - parent.add_log(message,color); + if(character.bot) parent.parent.add_log(character.name+": "+message,color); + else parent.add_log(message,color); +} + +function log(message,color) +{ + if(is_object(message)) message=JSON.stringify(message); + game_log(message,color); } function get_target_of(entity) // .target is a Name for Monsters and `id` for Players - this function return whatever the entity in question is targeting @@ -322,7 +343,7 @@ function can_attack(target) // also works for priests/heal { // is_disabled function checks .rip and .stunned if(!target) return false; - if(!parent.is_disabled(character) && in_attack_range(target) && new Date()>=parent.next_attack) return true; + if(!parent.is_disabled(character) && in_attack_range(target) && new Date()>=parent.next_skill.attack) return true; return false; } @@ -348,19 +369,27 @@ function is_transporting(entity) function attack(target) { - if(safeties && mssince(last_attack)<400) return; - if(!target) { game_log("Nothing to attack()","gray"); return; } - if(target.type=="character") parent.player_attack.call(target); - else parent.monster_attack.call(target); - last_attack=new Date(); + if(target==character) target=parent.character; + if(!target) + { + game_log("Nothing to attack()","gray"); + return rejecting_promise({reason:"not_found"}); + } + if(target.type=="character") + return parent.player_attack.call(target,null,true); + else + return parent.monster_attack.call(target,null,true); } function heal(target) { - if(safeties && mssince(last_attack)<400) return; - if(!target) { game_log("No one to heal()","gray"); return; } - parent.player_heal.call(target); - last_attack=new Date(); + if(target==character) target=parent.character; // Don't send the proxy object to parent [10/06/19] + if(!target) + { + game_log("No one to heal()","gray"); + return rejecting_promise({reason:"not_found"}); + } + return parent.player_heal.call(target,null,true); } function buy(name,quantity) //item names can be spotted from show_json(character.items) - they can be bought only if an NPC sells them @@ -406,19 +435,12 @@ function trade_buy(target,trade_slot) // target needs to be an actual player function upgrade(item_num,scroll_num,offering_num) // number of the item and scroll on the show_json(character.items) array - 0 to N-1 { - parent.u_item=item_num; - parent.u_scroll=scroll_num; - parent.u_offering=offering_num; - return parent.upgrade("code"); // returns a Promise + return parent.upgrade(item_num,scroll_num,offering_num,"code"); // returns a Promise } function compound(item0,item1,item2,scroll_num,offering_num) // for example -> compound(0,1,2,6) -> 3 items in the first 3 slots, scroll at the 6th spot { - parent.c_items=[item0,item1,item2]; - parent.c_last=3; - parent.c_scroll=scroll_num; - parent.c_offering=offering_num; - parent.compound(); + parent.compound(item0,item1,item2,scroll_num,offering_num,"code"); } function craft(i0,i1,i2,i3,i4,i5,i6,i7,i8) @@ -429,6 +451,12 @@ function craft(i0,i1,i2,i3,i4,i5,i6,i7,i8) parent.craft(); } +function auto_craft(name) +{ + // Picks the inventory positions automatically. Example: auto_craft("computer") + return parent.auto_craft(name,true); +} + function dismantle(item_num) { parent.ds_item=item_num; @@ -468,14 +496,48 @@ function show_json(e) // renders the object as json inside the game else parent.show_json(parent.game_stringify(e,'\t')); } -function get_player(name) // returns the player by name, if the player is within the vision area +function get_monster(id) { + // returns the monster by id, an integer, if the monster is within the vision area + var target=parent.entities[id]; + if(target && target.type!="monster") target=null; + return target; +} + +function get_player(name) +{ + // returns the player by name, if the player is within the vision area var target=null,entities=parent.entities; if(name==character.name) target=character; for(i in entities) if(entities[i].type=="character" && entities[i].name==name) target=entities[i]; return target; } +function get_entity(id) +{ + // entities are currently players, monsters and citizen npcs, this function returns players and monsters + var target=parent.entities[id]; + if(id==character.name) target=character; + return target; +} + +function find_npc(npc_id) +{ + // returns smart_move'able coordinates for an NPC key from G.npcs + for(var name in parent.G.maps) + { + var map=parent.G.maps[name]; + if(map.ignore || !map.npcs) continue; + for(var i=0;icharacter.esize || chest.last_loot && mssince(chest.last_loot)<1600)) continue; @@ -635,7 +698,13 @@ function send_cm(to,data) { // to: Name or Array of Name's // data: JSON object - parent.send_code_message(to,data); + var to_server=[]; + if(!is_array(to)) to=[to]; + to.forEach(function(name){ + if(is_character_local(name)) send_local_cm(name,data); + else to_server.push(name); + }) + if(to_server.length) parent.send_code_message(to_server,data); // message over the server - has a high call cost / character.cc } function on_disappear(entity,data) @@ -643,11 +712,6 @@ function on_disappear(entity,data) // game_log("disappear: "+entity.id+" "+JSON.stringify(data)); } -function on_combined_damage() // When multiple characters stay in the same spot, they receive combined damage, this function gets called whenever a monster deals combined damage -{ - // move(character.real_x+5,character.real_y); -} - function on_party_invite(name) // called by the inviter's name { // accept_party_invite(name) @@ -786,11 +850,19 @@ character.all=function(f){ character.listeners.push(def); return def.id; }; -character.on=function(event,f){ - var def={f:f,id:randomStr(30),event:event}; +character.one=function(event,f){ // gets overwritten if another handler comes along + var def={f:f,id:randomStr(30),event:event,one:true}; character.listeners.push(def); return def.id; }; +character.on=function(event,f){ + var def={f:f,id:randomStr(30),event:event},handled=false; + for(var i=0;i200) + activity.heartbeat[character.name]=(new Date()).toString(),processed_activity_change=true; + if(!activity.cm) activity.cm={}; + if(activity.cm[character.name] && activity.cm[character.name].length) + { + activity.cm[character.name].forEach(function(cm){ + character.trigger("cm",{name:cm[0],message:cm[1],local:true}); + }); + delete activity.cm[character.name]; + processed_activity_change=true; + } + if(processed_activity_change) + localStorage.setItem("activity",JSON.stringify(activity)); + processed_activity=false; +},10); + +function send_local_cm(name,data) +{ + var activity=processed_activity; + if(!processed_activity) + { + activity=localStorage.getItem("activity"); + activity=activity&&JSON.parse(activity)||{}; + } + if(!activity.heartbeat) activity.heartbeat={}; + if(!activity.cm) activity.cm={}; + if(!activity.cm[name]) activity.cm[name]=[]; + activity.cm[name].push([character.name,data]); + if(!processed_activity) + localStorage.setItem("activity",JSON.stringify(activity)); + else + processed_activity_change=true; +} + +function is_character_local(name) +{ + var activity=localStorage.getItem("activity"); + activity=activity&&JSON.parse(activity)||{}; + if(activity.heartbeat && activity.heartbeat[name] && mssince(new Date(activity.heartbeat[name]))<2400) + return true; + return false; +} + function pset(name,value) { // on Web, window.localStorage is used, on Steam/Mac, the electron-store package is used for persistent storage @@ -1000,6 +1130,7 @@ function smart_move(destination,on_done) // despite the name, smart_move isn't v if(destination.to=="town") destination.to="main"; if(G.monsters[destination.to]) { + var locations=[],theone; for(var name in G.maps) (G.maps[name].monsters||[]).forEach(function(pack){ if(pack.type!=destination.to || G.maps[name].ignore || G.maps[name].instance) return; @@ -1008,18 +1139,19 @@ function smart_move(destination,on_done) // despite the name, smart_move isn't v pack.last=pack.last||0; var boundary=pack.boundaries[pack.last%pack.boundaries.length]; pack.last++; - smart.map=boundary[0]; - smart.x=(boundary[1]+boundary[3])/2; - smart.y=(boundary[2]+boundary[4])/2; + locations.push([boundary[0],(boundary[1]+boundary[3])/2,(boundary[2]+boundary[4])/2]); } else if(pack.boundary) { var boundary=pack.boundary; - smart.map=name; - smart.x=(boundary[0]+boundary[2])/2; - smart.y=(boundary[1]+boundary[3])/2; + locations.push([name,(boundary[0]+boundary[2])/2,(boundary[1]+boundary[3])/2]); } }); + if(locations.length) // This way, when you smart_move("snake") repeatedly - you can keep visiting different maps with snakes + { + theone=random_one(locations); + smart.map=theone[0]; smart.x=theone[1]; smart.y=theone[2]; + } } else if(G.maps[destination.to||destination.map]) { @@ -1033,6 +1165,11 @@ function smart_move(destination,on_done) // despite the name, smart_move isn't v else if(destination.to=="potions" && in_arr(character.map,["winterland","winter_inn","winter_cave"])) smart.map="winter_inn",smart.x=-84,smart.y=-173; else if(destination.to=="potions") smart.map="main",smart.x=56,smart.y=-122; else if(destination.to=="scrolls") smart.map="main",smart.x=-465,smart.y=-71; + else if(find_npc(destination.to)) + { + var l=find_npc(destination.to); + smart.map=l.map,smart.x=l.x,smart.y=l.y+15; + } } if(!smart.map) { @@ -1122,7 +1259,7 @@ function bfs() var current=queue[start]; // game_log(current.x+" "+current.y); var map=G.maps[current.map]; - var c_moves=moves; + var c_moves=moves,qlist=[]; if(current.map==smart.map) { var c_dist=abs(current.x-smart.x)+abs(current.y-smart.y); @@ -1144,15 +1281,16 @@ function bfs() if(smart.prune.map && smart.flags.map) {start++; continue;} map.doors.forEach(function(door){ // if(simple_distance({x:map.spawns[door[6]][0],y:map.spawns[door[6]][1]},{x:current.x,y:current.y})<30) + if(smart.map!="bank" && door[4]=="bank") return; // manually patch the bank shortcut if(is_door_close(current.map,door,current.x,current.y) && can_use_door(current.map,door,current.x,current.y)) - qpush({map:door[4],x:G.maps[door[4]].spawns[door[5]||0][0],y:G.maps[door[4]].spawns[door[5]||0][1],transport:true,s:door[5]||0}); + qlist.push({map:door[4],x:G.maps[door[4]].spawns[door[5]||0][0],y:G.maps[door[4]].spawns[door[5]||0][1],transport:true,s:door[5]||0}); }); map.npcs.forEach(function(npc){ if(npc.id=="transporter" && simple_distance({x:npc.position[0],y:npc.position[1]},{x:current.x,y:current.y})<75) { for(var place in G.npcs.transporter.places) { - qpush({map:place,x:G.maps[place].spawns[G.npcs.transporter.places[place]][0],y:G.maps[place].spawns[G.npcs.transporter.places[place]][1],transport:true,s:G.npcs.transporter.places[place]}); + qlist.push({map:place,x:G.maps[place].spawns[G.npcs.transporter.places[place]][0],y:G.maps[place].spawns[G.npcs.transporter.places[place]][1],transport:true,s:G.npcs.transporter.places[place]}); } } }); @@ -1168,6 +1306,7 @@ function bfs() if(can_move({map:current.map,x:current.x,y:current.y,going_x:new_x,going_y:new_y,base:character.base})) qpush({map:current.map,x:new_x,y:new_y}); }); + qlist.forEach(function(q){qpush(q);}); // So regular move's are priotised start++; if(mssince(timer)>(!parent.is_hidden()&&40||500)) return; @@ -1273,9 +1412,24 @@ function proxy(name) { if(in_arr(name,character.properties)) return; character.properties.push(name); - Object.defineProperty(character,name,{get:function(){return parent.character[name];},set:function(value){delete this[name]; parent.character[name]=value;}}); + Object.defineProperty(character,name,{ + get:function(){return parent.character[name];}, + set:function(value){ + delete this[name]; + if(character.read_only.includes(name)) + { + game_log("You attempted to change the character."+name+" value manually. You have to use the provided functions to control your character!",colors.code_error); + } + else + { + parent.character[name]=value; + } + }, + enumerable:true, + }); } +character.read_only.push(...["on","once"]); ["bank","user","code","angle","direction","target","from_x","from_y","going_x","going_y","moving","vx","vy","move_num"].forEach(function(p){proxy(p)}); setInterval(function(){ for(var p in parent.character) proxy(p); },50); // bottom of the barrel @@ -1296,11 +1450,10 @@ function performance_trick() //safety flags var last_loot=new Date(0); -var last_attack=new Date(0); var last_potion=new Date(0); -var last_transport=new Date(0); var last_message="",current_message=""; +if(!window.requestAnimationFrame) window.requestAnimationFrame=function(a){ setTimeout(a,16); }; // jsdom patch [18/04/19] function code_draw() { if(last_message!=current_message) $("#gg").html(current_message),last_message=current_message;