diff --git a/runner_functions.js b/runner_functions.js index 3fafc0c..9000027 100644 --- a/runner_functions.js +++ b/runner_functions.js @@ -119,11 +119,17 @@ function use(name,target) // a multi-purpose use function, works for skills too } } -function use_skill(name,target) +function use_skill(name,target,extra_arg) { - // for blink: use_skill("blink",[x,y]) + // target: object or string (character name or monster ID) + // for "blink": use_skill("blink",[x,y]) + // for "3shot", "5shot" target can be an array of objects or strings (name or ID) + // example: use_skill("3shot",[target1,target2,target3]) + // extra_arg is currently for use_skill("throw",target,inventory_num) and use_skill("energize",target,optional_mp) if(!target) target=get_target(); - parent.use_skill(name,target); + parent.use_skill(name,target,extra_arg); + // Returns a Promise + // For "3shot", "5shot", "cburst" returns an array of Promise's - one for each target } function reduce_cooldown(name,ms) @@ -271,8 +277,9 @@ function set_message(text,color) } } -function game_log(message,color) +function game_log(message,color,x) { + if(game.platform=="electron" && !x) return safe_log(message,color); if(!color) color="#51D2E1"; if(character.bot) parent.parent.add_log(character.name+": "+message,color); else parent.add_log(message,color); @@ -284,6 +291,23 @@ function log(message,color) game_log(message,color); } +function safe_log(message,color) +{ + // If the logged message/object is from an untrusted source, this function must be used + // For example if you: character.on("cm",function(data){log(data)}); + // Someone can: send_cm("You",""); + if(is_object(message)) message=JSON.stringify(message); + game_log(html_escape(message),color,true); +} + +function get_focus() +{ + // focus is a secondary target that appears on top of the actual target + // it was added to let you view other characters around and still target separately + if(parent.xtarget && parent.xtarget.visible) return parent.xtarget; + return null; +} + 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 { if(!entity || !entity.target) return null; @@ -298,7 +322,7 @@ function get_target_of(entity) // .target is a Name for Monsters and `id` for Pl function get_target() { - if(parent.ctarget && !parent.ctarget.dead) return parent.ctarget; + if(parent.ctarget && parent.ctarget.visible) return parent.ctarget; return null; } @@ -332,18 +356,31 @@ function xmove(x,y) else smart_move({x:x,y:y}); } -function in_attack_range(target) // also works for priests/heal +function is_in_range(target,skill) { - if(!target) return false; - if(parent.distance(character,target)<=character.range) return true; + // Valid usages: is_in_range(target), is_in_range(target,"attack"), is_in_range(target,"heal"), is_in_range(target,"mentalburst") + if(!target || !target.visible) return false; + // When a target leaves your viewpoint, .visible becomes false and the object reference is never updated again + var range_multiplier=1,range_bonus=0; + if(G.skills[skill] && G.skills[skill].range_multiplier) range_multiplier=G.skills[skill].range_multiplier; + if(G.skills[skill] && G.skills[skill].range_bonus) range_bonus=G.skills[skill].range_bonus; + if(distance(character,target)<=character.range*range_multiplier+range_bonus) return true; return false; } -function can_attack(target) // also works for priests/heal +function is_on_cooldown(skill) { + if(parent.next_skill[skill] && new Date()=parent.next_skill.attack) return true; + if(!parent.is_disabled(character) && is_in_range(target) && new Date()>=parent.next_skill.attack) return true; return false; } @@ -440,7 +477,7 @@ function upgrade(item_num,scroll_num,offering_num) // number of the item and scr 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.compound(item0,item1,item2,scroll_num,offering_num,"code"); + return parent.compound(item0,item1,item2,scroll_num,offering_num,"code"); // returns a Promise } function craft(i0,i1,i2,i3,i4,i5,i6,i7,i8) @@ -605,9 +642,12 @@ function use_hp_or_mp() if(used) last_potion=new Date(); } -function loot(commander) +function loot(id_or_arg) { + // loot(id) loots a specific chest // loot(true) allows code characters to make their commanders' loot instead, extremely useful [14/01/18] + // after recent looting changes, loot(true) isn't too useful any more [08/12/19] + if(id_or_arg && id_or_arg!==true) return parent.parent.open_chest(id_or_arg); var looted=0; if(safeties && mssince(last_loot)character.esize || chest.last_loot && mssince(chest.last_loot)<1600)) continue; chest.last_loot=last_loot; - if(commander) parent.parent.open_chest(id); + if(id_or_arg==true) parent.parent.open_chest(id); else parent.open_chest(id); // parent.socket.emit("open_chest",{id:id}); old version [02/07/18] looted++; @@ -624,6 +664,13 @@ function loot(commander) } } +function get_chests() +{ + // parent.chests is an object, each key is a chest ID + // you can: for(var id in get_chests()) loot(id); + return parent.chests; +} + function send_gold(receiver,gold) { if(!receiver) return game_log("No receiver sent to send_gold"); @@ -638,7 +685,7 @@ function send_item(receiver,num,quantity) parent.socket.emit("send",{name:receiver,num:num,q:quantity||1}); } -function destroy_item(num) // num: 0 to 41 +function destroy(num) // num: 0 to 41 { parent.socket.emit("destroy",{num:num}); } @@ -656,13 +703,13 @@ function send_party_request(name) function accept_party_invite(name) { - parent.$(".pin"+name).remove(); + parent.remove_chat("pin"+name); parent.socket.emit('party',{event:'accept',name:name}); } function accept_party_request(name) { - parent.$(".pin"+name).remove(); + parent.remove_chat("rq"+name); parent.socket.emit('party',{event:'raccept',name:name}); } @@ -673,7 +720,7 @@ function leave_party() function accept_magiport(name) { - parent.$(".mpin"+name).remove(); + parent.remove_chat("mp"+name); parent.socket.emit('magiport',{name:name}); } @@ -745,18 +792,6 @@ function on_draw() // the game calls this function at the best place in each gam } -function on_game_event(event) -{ - if(event.name=="pinkgoo") - { - // start searching for the "Love Goo" of the Valentine's Day event - } - if(event.name=="goblin") - { - // start searching for the "Sneaky Goblin" - } -} - var PIXI=parent.PIXI; // for drawing stuff into the game var drawings=parent.drawings; var buttons=parent.code_buttons; @@ -1023,45 +1058,35 @@ function reset_mappings() 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={}; + var activity=localStorage.getItem("activity"),activities=[],beat={},change=false; + activity=activity&&JSON.parse(activity)||{}; 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; + activity.heartbeat[character.name]=(new Date()).toString(),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}); - }); + activities=activity.cm[character.name]; delete activity.cm[character.name]; - processed_activity_change=true; + change=true; } - if(processed_activity_change) + if(change) localStorage.setItem("activity",JSON.stringify(activity)); - processed_activity=false; + activities.forEach(function(cm){ + character.trigger("cm",{name:cm[0],message:cm[1],local:true}); + }); },10); function send_local_cm(name,data) { - var activity=processed_activity; - if(!processed_activity) - { - activity=localStorage.getItem("activity"); - activity=activity&&JSON.parse(activity)||{}; - } + var 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; + localStorage.setItem("activity",JSON.stringify(activity)); } function is_character_local(name) @@ -1075,16 +1100,40 @@ function is_character_local(name) function pset(name,value) { + // persistent set function for string values // on Web, window.localStorage is used, on Steam/Mac, the electron-store package is used for persistent storage return parent.storage_set(name,value); } function pget(name) { + // persistent get function for string values // on Web, window.localStorage is used, on Steam/Mac, the electron-store package is used for persistent storage return parent.storage_get(name); } +function set(name,value) +{ + // persistent set function that works for serializable objects + try{ + window.localStorage.setItem("cstore_"+name,JSON.stringify(value)); + return true; + }catch(e){ + game_log("set() call failed for: "+name+" reason: "+e,colors.code_error); + return false; + } +} + +function get(name) +{ + // persistent get function that works for serializable objects + try{ + return JSON.parse(window.localStorage.getItem("cstore_"+name)); + }catch(e){ + return null; + } +} + function load_code(name,onerror) // onerror can be a function that will be executed if load_code fails { if(!onerror) onerror=function(){ game_log("load_code: Failed to load",colors.code_error); } @@ -1173,7 +1222,7 @@ function smart_move(destination,on_done) // despite the name, smart_move isn't v } if(!smart.map) { - game_log("Unrecognized","#CF5B5B"); + game_log("Unrecognized location","#CF5B5B"); return; } smart.moving=true; @@ -1453,11 +1502,12 @@ var last_loot=new Date(0); var last_potion=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() { + var t; if(last_message!=current_message) $("#gg").html(current_message),last_message=current_message; - requestAnimationFrame(code_draw); + if(!game.graphics) t=setTimeout(code_draw,16); // jsdom patch [18/04/19] + else requestAnimationFrame(code_draw); } code_draw();