Update runner_functions.js

This commit is contained in:
Kaan Soral
2019-09-10 20:27:46 +03:00
committed by GitHub
parent 5db0ee50e7
commit b0231f8183
+202 -49
View File
@@ -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;i<map.npcs.length;i++)
{
var npc=map.npcs[i];
if(npc.id==npc_id)
return {map:name,"in":name,x:npc.position[0],y:npc.position[1]};
}
}
return null;
}
function get_nearest_monster(args)
{
//args:
@@ -519,8 +581,9 @@ function get_nearest_hostile(args) // mainly as an example [08/02/17]
{
var current=parent.entities[id];
if(current.type!="character" || !current.visible || current.rip || current.invincible || current.npc) continue;
if(current.party && character.party==current.party) continue;
if(current.guild && character.guild==current.guild) continue;
if(character.team && current.team==character.team) continue;
if(!character.team && current.party && character.party==current.party) continue;
if(!character.team && current.guild && character.guild==current.guild) continue;
if(args.friendship && in_arr(current.owner,parent.friends)) continue;
if(args.exclude && in_arr(current.name,args.exclude)) continue; // get_nearest_hostile({exclude:["Wizard"]}); Thanks
var c_dist=parent.distance(character,current);
@@ -531,9 +594,9 @@ function get_nearest_hostile(args) // mainly as an example [08/02/17]
function use_hp_or_mp()
{
if(safeties && mssince(last_potion)<600) return;
if(safeties && mssince(last_potion)<min(200,character.ping*3)) return;
var used=false;
if(new Date()<parent.next_potion) return;
if(new Date()<parent.next_skill.use_hp) return;
if(character.mp/character.max_mp<0.2) use('use_mp'),used=true;
else if(character.hp/character.max_hp<0.7) use('use_hp'),used=true;
else if(character.mp/character.max_mp<0.8) use('use_mp'),used=true;
@@ -546,9 +609,9 @@ function loot(commander)
{
// loot(true) allows code characters to make their commanders' loot instead, extremely useful [14/01/18]
var looted=0;
if(safeties && mssince(last_loot)<200) return;
if(safeties && mssince(last_loot)<min(300,character.ping*3)) return;
last_loot=new Date();
for(id in parent.chests)
for(var id in parent.chests)
{
var chest=parent.chests[id];
if(safeties && (chest.items>character.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;i<character.listeners.length;i++)
if(character.listeners[i].one && character.listeners[i].event==event)
character.listeners[i]=def,handled=true;
if(!handled) character.listeners.push(def);
return def.id;
};
character.trigger=function(event,args){
var to_delete=[];
for(var i=0;i<character.listeners.length;i++)
@@ -943,6 +1015,64 @@ function reset_mappings()
set_skillbar(parent.skillbar);
}
// delete previous/stale messages
var activity=localStorage.getItem("activity");
activity=activity&&JSON.parse(activity)||{};
if(!activity.cm) activity.cm={};
delete activity.cm[character.name];
localStorage.setItem("activity",JSON.stringify(activity));
var processed_activity=false,processed_activity_change=false;
setInterval(function(){
var activity=localStorage.getItem("activity");
processed_activity_change=false;
processed_activity=activity=activity&&JSON.parse(activity)||{};beat={};
if(!activity.heartbeat) activity.heartbeat={};
if(!activity.heartbeat[character.name] || mssince(new Date(activity.heartbeat[character.name]))>200)
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;