character.esize || chest.last_loot && mssince(chest.last_loot)<1600)) continue;
chest.last_loot=last_loot;
parent.socket.emit("open_chest",{id:id});
looted++;
if(looted==2) break;
}
}
function send_gold(receiver,gold)
{
if(!receiver) return game_log("No receiver sent to send_gold");
if(receiver.name) receiver=receiver.name;
parent.socket.emit("send",{name:receiver,gold:gold});
}
function send_item(receiver,num,quantity)
{
if(!receiver) return game_log("No receiver sent to send_item");
if(receiver.name) receiver=receiver.name;
parent.socket.emit("send",{name:receiver,num:num,q:quantity||1});
}
function destroy_item(num) // num: 0 to 41
{
parent.socket.emit("destroy",{num:num});
}
function send_party_invite(name,is_request) // name could be a player object, name, or id
{
if(is_object(name)) name=name.name;
parent.socket.emit('party',{event:is_request&&'request'||'invite',name:name});
}
function send_party_request(name)
{
send_party_invite(name,1);
}
function accept_party_invite(name)
{
parent.socket.emit('party',{event:'accept',name:name});
}
function accept_party_request(name)
{
parent.socket.emit('party',{event:'raccept',name:name});
}
function respawn()
{
parent.socket.emit('respawn');
}
function handle_death()
{
// When a character dies, character.rip is true, you can override handle_death and manually respawn
// IDEA: A Resident PVP-Dweller, with an evasive Code + irregular respawning
// respawn current has a 12 second cooldown, best wait 15 seconds before respawning [24/11/16]
// setTimeout(respawn,15000);
// return true;
// NOTE: Add `if(character.rip) {respawn(); return;}` to your main loop/interval too, just in case
return -1;
}
function handle_command(command,args) // command's are things like "/party" that are entered through Chat - args is a string
{
// game_log("Command: /"+command+" Args: "+args);
// return true;
return -1;
}
function send_cm(to,data)
{
// to: Name or Array of Name's
// data: JSON object
parent.send_code_message(to,data);
}
function on_cm(name,data)
{
game_log("Received a code message from: "+name);
}
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)
}
function on_party_request(name) // called by the inviter's name - request = someone requesting to join your existing party
{
// accept_party_request(name)
}
function on_destroy() // called just before the CODE is destroyed
{
clear_drawings();
}
function on_draw() // the game calls this function at the best place in each game draw frame, so if you are playing the game at 60fps, this function gets called 60 times per second
{
}
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;
//Documentation: https://pixijs.github.io/docs/PIXI.Graphics.html
function draw_line(x,y,x2,y2,size,color)
{
// keep in mind that drawings could significantly slow redraws, especially if you don't .destroy() them
if(!color) color=0xF38D00;
if(!size) size=1;
e=new PIXI.Graphics();
e.lineStyle(size, color);
e.moveTo(x,y);
e.lineTo(x2,y2);
e.endFill();
parent.drawings.push(e); //for the game to keep track of your drawings
parent.map.addChild(e); //e.destroy() would remove it, if you draw too many things and leave them there, it will likely bring the game to a halt
return e;
}
// Example: draw_circle(character.real_x,character.real_y,character.range) :) [22/10/16]
function draw_circle(x,y,radius,size,color)
{
if(!color) color=0x00F33E;
if(!size) size=1;
e=new PIXI.Graphics();
e.lineStyle(size, color);
e.drawCircle(x,y,radius);
parent.drawings.push(e);
parent.map.addChild(e);
return e;
}
function clear_drawings()
{
drawings.forEach(function(e){
try{e.destroy({children:true})}catch(ex){}
});
drawings=parent.drawings=[];
}
var game={
last:0,
callbacks:[],
on:function(event,f){
},
once:function(event,f){
},
remove:function(num){
},
trigger:function(event,args){
},
};
function preview_item(def,args)
{
//PLANNED Improvements:
//- Importing a custom thumbnail
//- Drafting custom item abilities
// Email me or create an issue if you need these features (if you want to suggest new items) [20/03/17]
if(!args) args={};
var html="";
var styles="vertical-align: top; margin: 10px";
var name=def.id||args.id||"staff";
parent.prop_cache={}; // bust the item cache
if(def.compound || def.upgrade)
{
for(var level=0;level<=10;level++)
html+=parent.render_item("html",{item:def,name:name,styles:styles,actual:{name:name,level:level},sell:true,thumbnail:args.thumbnail});
}
else
{
html+=parent.render_item("html",{item:def,name:name,thumbnail:args.thumbnail});
}
html+=""+parent.json_to_html(def)+"
";
parent.show_modal(html);
parent.prop_cache={};
}
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","#E13758"); }
var xhrObj = new XMLHttpRequest();
xhrObj.open('GET',"/code.js?name="+encodeURIComponent(name)+"×tamp="+(new Date().getTime()), false);
xhrObj.send('');
var library=document.createElement("script");
library.type="text/javascript";
library.text=xhrObj.responseText;
library.onerror=onerror;
document.getElementsByTagName("head")[0].appendChild(library);
}
var smart={
moving:false,
map:"main",x:0,y:0,
on_done:function(){},
plot:null,
edge:20,
use_town:false,
prune:{
smooth:true,
map:true,
},
flags:{}
};
function smart_move(destination,on_done) // despite the name, smart_move isn't very smart or efficient, it's up to the players to implement a better movement method [05/02/17]
{
smart.map="";
if(is_string(destination)) destination={to:destination};
if("x" in destination)
{
smart.map=destination.map||character.map;
smart.x=destination.x;
smart.y=destination.y;
}
else if("to" in destination || "map" in destination)
{
if(destination.to=="town") destination.to="main";
if(G.monsters[destination.to])
{
for(var name in G.maps)
(G.maps[name].monsters||[]).forEach(function(pack){
if(pack.type!=destination.to || G.maps[name].ignore) return;
if(pack.boundaries) // boundaries: for phoenix, mvampire
{
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;
}
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;
}
});
}
else if(G.maps[destination.to||destination.map])
{
smart.map=destination.to||destination.map;
smart.x=G.maps[smart.map].spawns[0][0];
smart.y=G.maps[smart.map].spawns[0][1];
}
else if(destination.to=="upgrade" || destination.to=="compound") smart.map="main",smart.x=-204,smart.y=-129;
else if(destination.to=="exchange") smart.map="main",smart.x=-26,smart.y=-432;
else if(destination.to=="potions" && character.map=="halloween") smart.map="halloween",smart.x=149,smart.y=-182;
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;
}
if(!smart.map)
{
game_log("Unrecognized","#CF5B5B");
return;
}
smart.moving=true;
smart.plot=[]; smart.flags={}; smart.searching=smart.found=false;
if(destination.return)
{
var cx=character.real_x,cy=character.real_y,cmap=character.map;
smart.on_done=function(){
if(on_done) on_done();
smart_move({map:cmap,x:cx,y:cy});
}
}
else smart.on_done=on_done||function(){};
console.log(smart.map+" "+smart.x+" "+smart.y);
}
function stop()
{
if(smart.moving) smart.on_done(false);
smart.moving=false;
move(character.real_x,character.real_y);
}
var queue=[],visited={},start=0,best=null;
var moves=[[0,15],[0,-15],[15,0],[-15,0]];
function plot(index)
{
if(index==-1) return;
plot(queue[index].i); // Recursively back-tracks the path we came from
smart.plot.push(queue[index]);
}
function qpush(node)
{
// If we haven't visited this location, adds the location to the queue
if(smart.prune.map && smart.flags.map && node.map!=smart.map) return;
if(visited[node.map+"-"+node.x+"-"+node.y]) return;
if(!node.i) node.i=start; // set the index, to aid the plot function
queue.push(node);
visited[node.map+"-"+node.x+"-"+node.y]=true;
}
function smooth_path()
{
var i=0,j;
while(i(!parent.is_hidden()&&40||500)) return;
}
if(result===null) result=best,optimal=false;
if(result===null)
{
game_log("Path not found!","#CF575F");
smart.moving=false;
smart.on_done(false);
}
else
{
plot(result);
smart.found=true;
if(smart.prune.smooth) smooth_path();
if(optimal) game_log("Path found!","#C882D1");
else game_log("Path found~","#C882D1");
// game_log(queue.length);
parent.d_text("Yes!",character,{color:"#58D685"});
}
}
function start_pathfinding()
{
smart.searching=true;
queue=[],visited={},start=0,best=null;
qpush({x:character.real_x,y:character.real_y,map:character.map,i:-1});
game_log("Searching for a path...","#89D4A2");
bfs();
}
function continue_pathfinding()
{
bfs();
}
function smart_move_logic()
{
if(!smart.moving) return;
if(!smart.searching && !smart.found)
{
start_pathfinding();
}
else if(!smart.found)
{
if(Math.random()<0.1)
{
move(character.real_x+Math.random()*0.0002-0.0001,character.real_y+Math.random()*0.0002-0.0001);
parent.d_text(shuffle(["Hmm","...","???","Definitely left","No right!","Is it?","I can do this!","I think ...","What If","Should be","I'm Sure","Nope","Wait a min!","Oh my"])[0],character,{color:shuffle(["#68B3D1","#D06F99","#6ED5A3","#D2CF5A"])[0]});
}
continue_pathfinding();
}
else if(!character.moving && can_walk(character) && !is_transporting(character))
{
if(!smart.plot.length)
{
smart.moving=false;
smart.on_done(true);
return;
}
var current=smart.plot[0];
smart.plot.splice(0,1);
// game_log(JSON.stringify(current));
if(current.town)
{
use("town");
}
else if(current.transport)
{
parent.socket.emit("transport",{to:current.map,s:current.s});
// use("transporter",current.map);
}
else if(character.map==current.map && can_move_to(current.x,current.y))
{
move(current.x,current.y);
}
else
{
game_log("Lost the path...","#CF5B5B");
smart_move({map:smart.map,x:smart.x,y:smart.y},smart.on_done);
}
}
}
setInterval(function(){smart_move_logic();},80);
//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);