Asuramaru UserScript for Moomoo.io
Asuramaru UserScript for Moomoo.io
// @name Asuramaru
// @version 1.1
// @author kusoi
// @contributors Walmart and rim
// @grant none
// @description Walmart likes feet
// @match *://*.moomoo.io/*
// @noframes true
// @unwrap true
// @license MIT
// @copyright 2024 Kusoi. All Rights Reserved.
// ==/UserScript==
let asura;
let getEl = id => document.getElementById(id);
class Configurations {
constructor() {
//Screen
this.maxScreenWidth = 1920;
this.maxScreenHeight = 1080
//Server
this.isSandbox = window.location.hostname == "sandbox.moomoo.io" ? true :
false;
this.serverUpdateRate = 9;
this.clientSendRate = 5;
this.maxPlayers = 40;
this.maxPlayersHard = 50;
//Game UI
this.minimapRate = 3000;
this.deathFadeout = 3000;
this.colGrid = 10;
this.collisionDepth = 6;
this.healthBarWidth = 50;
this.healthBarPad = 4;
this.iconPadding = 15;
this.iconPad = 0.9;
this.crownIconScale = 60;
this.cownPad = 35;
this.chatCountdown = 3000;
this.chatCooldown = 500;
this.nameY = 34;
//Players
this.maxAge = 100;
this.gatherAngle = Math.PI / 2.6;
this.gatherWiggle = 10;
this.hitReturnRatio = 0.25;
this.hitAngle = Math.PI / 2;
this.playerScale = 35;
this.playerSpeed = 0.0016;
this.playerDecel = 0.993;
this.nameY = 34;
this.skinColors = ["#bf8f54", "#cbb091", "#896c4b", "#fadadc", "#ececec",
"#c37373", "#4c4c4c", "#ecaff7", "#738cc3", "#8bc373"];
this.animalCount = 7;
this.aiTurnRandom = 0.06;
this.cowNames = ["Sid", "Steph", "Bmoe", "Romn", "Jononthecool", "Fiona",
"Vince", "Nathan", "Nick", "Flappy", "Ronald", "Otis", "Pepe", "Mc Donald", "Theo",
"Fabz", "Oliver", "Jeff", "Jimmy", "Helena", "Reaper", "Ben", "Alan", "Naomi",
"XYZ", "Clever", "Jeremy", "Mike", "Destined", "Stallion", "Allison", "Meaty",
"Sophia", "Vaja", "Joey", "Pendy", "Murdoch", "Theo", "Jared", "July", "Sonia",
"Mel", "Dexter", "Quinn", "Milky"];
this.shieldAngle = Math.PI / 3;
this.weaponVariants = [
{ id: 0, src: "", xp: 0, val: 1 },
{ id: 1, src: "_g", xp: 3000, val: 1.1 },
{ id: 2, src: "_d", xp: 7000, val: 1.18 },
{ id: 3, src: "_r", poison: true, xp: 12000, val: 1.18 }
];
this.resourceTypes = ["wood", "food", "stone", "points"];
this.areaCount = 7;
this.treesPerArea = 9;
this.bushesPerArea = 3;
this.totalRocks = 32;
this.goldOres = 7;
this.riverWidth = 724;
this.riverPadding = 114;
this.waterCurrent = 0.0011;
this.waveSpeed = 0.0001;
this.waveMax = 1.3;
this.treeScales = [150, 160, 165, 175];
this.bushScales = [80, 85, 95];
this.rockScales = [80, 85, 90];
this.snowBiomeTop = 2400;
this.snowSpeed = 0.75;
this.maxNameLength = 15;
this.mapScale = 14400;
this.mapPingScale = 40;
this.mapPingTime = 2200;
// volcano
this.volcano = {
outerScale: 340,
innerScale: 115,
AnimDuration: 3200,
animationSpeed: 16,
radius: 1440,
percentage: 0.2,
x: 14400 - 440,
y: 14400 - 440,
animationTime: 0
};
// script shit
this.timeBetweenTick = 1000 / 9;
}
}
let styleItem = document.createElement("style");
styleItem.type = "text/css";
styleItem.appendChild(document.createTextNode(`
#chatcommand {
width: 230px;
border-radius: 3px;
background-color: rgba(0,0,0,0.5);
margin: auto;
text-align: left;
z-index: 49;
pointer-events: auto;
position: relative;
bottom: 3.5px;
overflow-y: auto;
}
#chatcommand div {
background-color: rgba(255,255,255,0);
color: rgba(255,255,255,1);
transition: background-color 0.3s, color 0.3s;
}
#chatcommand div:hover {
background-color: rgba(255,255,255,0.2);
color: rgba(0,0,0,1);
}
.chatcommandHard {
color: rgba(255,255,255,1);
font-size: 18px;
}
.chatcommandLight {
color: rgba(255,255,255,0.7);
font-size: 18px;
}
`));
document.head.appendChild(styleItem);
// my menu
let fontAwesomeStylesheet =
'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css';
let link = document.createElement('link');
link.rel = 'stylesheet';
link.href = fontAwesomeStylesheet;
document.head.appendChild(link);
let menuHtml = `
<div id="customMenu" style="
position:fixed;top:50%;left:50%;width:480px;height:320px;background:#2b2b2b;color:#
fff;border-radius:8px;box-shadow:0 0 10px rgba(0,0,0,0.5);font-family:sans-
serif;transform:translate(-50%, -50%);transition:opacity 0.3s, transform
0.3s;opacity:0;visibility:hidden;">
<div style="padding:10px;background:#333;">
<input type="text" id="search" placeholder="Search..."
style="width:calc(100% - 20px);padding:5px;border:none;border-
radius:4px;background:#444;color:#fff;">
</div>
<div style="display:flex;height:calc(100% - 50px);">
<div id="menuItems" style="width:120px;background:#333;">
<div class="menu-item active" data-tab="offensive">
<i class="fas fa-crosshairs" style="padding-right:10px;"></i>
Offensive
</div>
<div class="menu-item" data-tab="defensive">
<i class="fas fa-shield-alt" style="padding-right:10px;"></i>
Defensive
</div>
<div class="menu-item" data-tab="visuals">
<i class="fas fa-eye" style="padding-right:10px;"></i> Visuals
</div>
<div class="menu-item" data-tab="configs">
<i class="fas fa-cogs" style="padding-right:10px;"></i>
Settings
</div>
<div class="menu-item" data-tab="music">
<i class="fas fa-music" style="padding-right:10px;"></i> Music
</div>
</div>
<div id="tabContent" style="flex-
grow:1;padding:10px;background:#2b2b2b;overflow-y:auto;">
<div class="tab" id="offensive" style="display:block;">
<div class="toggle-group">
<div class="toggle" data-toggle="autoplace">
<label style="display:block;margin-bottom:15px;">
Autoplace
<label class="switch" style="float:right;">
<input type="checkbox" checked id="autoplace">
<span class="slider"></span>
</label>
</label>
</div>
<div class="toggle" data-toggle="preplace">
<label style="display:block;margin-bottom:15px;">
Preplace
<label class="switch" style="float:right;">
<input type="checkbox" checked id="preplace">
<span class="slider"></span>
</label>
</label>
</div>
<div class="toggle" data-toggle="autobullspam">
<label style="display:block;margin-bottom:15px;">
AutoBullSpam
<label class="switch" style="float:right;">
<input type="checkbox" id="autobullspam">
<span class="slider"></span>
</label>
</label>
</div>
<div class="toggle" data-toggle="autoreplace">
<label style="display:block;margin-bottom:15px;">
AutoReplace
<label class="switch" style="float:right;">
<input type="checkbox" checked
id="autoreplace">
<span class="slider"></span>
</label>
</label>
</div>
</div>
</div>
<div class="tab" id="defensive" style="display:none;">
<div class="toggle-group">
<div class="toggle" data-toggle="safewalk">
<label style="display:block;margin-bottom:15px;">
SafeWalk
<label class="switch" style="float:right;">
<input type="checkbox" checked id="safewalk">
<span class="slider"></span>
</label>
</label>
</div>
</div>
</div>
<div class="tab" id="visuals" style="display:none;">
<div class="toggle-group">
<div class="toggle" data-toggle="placeindi">
<label style="display:block;margin-bottom:15px;">
Place-Indicator
<label class="switch" style="float:right;">
<input type="checkbox" checked id="placeindi">
<span class="slider"></span>
</label>
</label>
</div>
<div class="toggle" data-toggle="ae86dir">
<label style="display:block;margin-bottom:15px;">
No-Dir/Aim
<label class="switch" style="float:right;">
<input type="checkbox" checked id="ae86dir">
<span class="slider"></span>
</label>
</label>
</div>
<div class="toggle" data-toggle="stack">
<label style="display:block;margin-bottom:15px;">
Stack-Dmg
<label class="switch" style="float:right;">
<input type="checkbox" checked id="stack">
<span class="slider"></span>
</label>
</label>
</div>
<div class="toggle" data-toggle="rendertxt">
<label style="display:block;margin-bottom:15px;">
Render-Dmg
<label class="switch" style="float:right;">
<input type="checkbox" checked id="rendertxt">
<span class="slider"></span>
</label>
</label>
</div>
<div class="toggle" data-toggle="buildhp">
<label style="display:block;margin-bottom:15px;">
Object-Health
<label class="switch" style="float:right;">
<input type="checkbox" checked id="buildhp">
<span class="slider"></span>
</label>
</label>
</div>
</div>
</div>
<div class="tab" id="configs" style="display:none;">
<div class="toggle-group">
<div class="toggle" data-toggle="autoupg">
<label style="display:block;margin-bottom:15px;">
Smart Auto-Upg
<label class="switch" style="float:right;">
<input type="checkbox" checked id="autoupg">
<span class="slider"></span>
</label>
</label>
</div>
<div class="toggle" data-toggle="autoGrind">
<label style="display:block;margin-bottom:15px;">
AutoGrind
<label class="switch" style="float:right;">
<input type="checkbox" id="autoGrind">
<span class="slider"></span>
</label>
</label>
</div>
</div>
</div>
<div class="tab" id="music" style="display:none;">
<div class="toggle-group">
<div style="background-color: #f0f0f0; padding: 2px; border:
1px solid #ccc; border-radius: 5px;">
<audio id="audioPlayer" controls style="width: 100%;
margin-top: 0;">
<source id="audioSource" src="" type="audio/mp3">
failed to play audio.
</audio>
</div>
</br>
<div class="music-item"
data-song="https://cdn.discordapp.com/attachments/1253797905123377243/1266474532781
424650/Tommy_Richman_-_MILLION_DOLLAR_BABY_Official_Visualizer.mp3?
ex=66a547d2&is=66a3f652&hm=92847a1239177f87f65160204148b53fadbd223fc5087dbfc2ec2d66
f8d58b40&">
<label style="display:block;margin-bottom:15px;">
MILLION DOLLAR BABY - Tommy Richman
</label>
</div>
</div>
</div>
</div>
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', menuHtml);
document.querySelectorAll('#menuItems .menu-item').forEach(item => {
item.addEventListener('click', () => {
document.querySelectorAll('#menuItems .menu-item').forEach(i =>
i.classList.remove('active'));
document.querySelectorAll('#tabContent .tab').forEach(tab =>
tab.style.display = 'none');
item.classList.add('active');
getEl(item.dataset.tab).style.display = 'block';
});
});
document.querySelector('#menuItems .menu-item[data-tab="offensive"]').click();
getEl('search').addEventListener('input', function() {
let query = this.value.toLowerCase();
document.querySelectorAll('#tabContent .tab').forEach(tab => {
let toggleGroups = tab.querySelectorAll('.toggle-group');
toggleGroups.forEach(group => {
group.querySelectorAll('.toggle').forEach(toggle => {
let text = toggle.textContent.toLowerCase();
toggle.style.display = text.includes(query) ? '' : 'none';
});
tab.style.display =
Array.from(group.querySelectorAll('.toggle')).some(toggle => toggle.style.display
=== '') ? 'block' : 'none';
});
});
});
document.querySelectorAll('.music-item').forEach(item => {
item.addEventListener('click', () => {
let song = item.dataset.song;
let audioPlayer = getEl('audioPlayer');
let audioSource = getEl('audioSource');
if (audioSource.src.includes(song)) {
if (audioPlayer.paused) {
audioPlayer.play();
} else {
audioPlayer.pause();
}
} else {
audioSource.src = song;
audioPlayer.load();
audioPlayer.play();
}
});
});
document.addEventListener('keydown', function(event) {
if (event.key === 'Escape') {
let menu = getEl('customMenu');
if (menu.style.visibility === 'visible') {
menu.style.opacity = '0';
menu.style.transform = 'translate(-50%, -50%) scale(0.8)';
menu.style.visibility = 'hidden';
} else {
menu.style.visibility = 'visible';
menu.style.opacity = '1';
menu.style.transform = 'translate(-50%, -50%) scale(1)';
}
}
});
let styles = `
#customMenu {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0.8);
visibility: hidden;
opacity: 0;
transition: opacity 1s ease-in-out, transform 1s ease-in-out, visibility 1s
ease-in-out;
background: #222;
border: 1px solid #444;
border-radius: 8px;
width: 300px;
z-index: 1000;
}
#customMenu.visible {
visibility: visible;
opacity: 1;
transform: translate(-50%, -50%) scale(1);
}
#customMenu .menu-item {
padding: 10px;
cursor: pointer;
transition: background 0.3s;
display: flex;
align-items: center;
color: #ccc;
}
#customMenu .menu-item:hover {
background: #444;
}
#customMenu .menu-item.active {
background: #555;
color: #fff;
}
#customMenu .tab {
display: none;
}
#customMenu .tab.active {
display: block;
}
.toggle-group {
background: #333;
padding: 10px;
border-radius: 4px;
}
.toggle {
background: #444;
padding: 10px;
border-radius: 4px;
margin-bottom: 10px;
}
.switch {
position: relative;
display: inline-block;
width: 34px;
height: 20px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: .4s;
border-radius: 34px;
}
.slider:before {
position: absolute;
content: "";
height: 14px;
width: 14px;
left: 3px;
bottom: 3px;
background-color: white;
transition: .4s;
border-radius: 50%;
}
input:checked + .slider {
background-color: #2196F3;
}
input:checked + .slider:before {
transform: translateX(14px);
}
#tabContent {
scrollbar-width: thin;
scrollbar-color: #555 #333;
}
#tabContent::-webkit-scrollbar {
width: 8px;
}
#tabContent::-webkit-scrollbar-thumb {
background: #555;
border-radius: 4px;
}
#tabContent::-webkit-scrollbar-track {
background: #333;
border-radius: 4px;
}
.music-item {
background: #444;
padding: 10px;
border-radius: 4px;
margin-bottom: 10px;
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
}
.music-item:hover {
background: #555;
}
`;
let styleSheet = document.createElement("style");
styleSheet.type = "text/css";
styleSheet.innerText = styles;
document.head.appendChild(styleSheet);
let config = new Configurations();
class HtmlAction {
constructor(element) {
this.element = element;
};
add(code) {
if (!this.element) return undefined;
this.element.innerHTML += code;
};
newLine(amount) {
let result = `<br>`;
if (amount > 0) {
result = ``;
for (let i = 0; i < amount; i++) {
result += `<br>`;
}
}
this.add(result);
};
checkBox(setting) {
let newCheck = `<input type = "checkbox"`;
setting.id && (newCheck += ` id = ${setting.id}`);
setting.style && (newCheck += ` style = ${setting.style.replaceAll(" ",
"")}`);
setting.class && (newCheck += ` class = ${setting.class}`);
setting.checked && (newCheck += ` checked`);
setting.onclick && (newCheck += ` onclick = ${setting.onclick}`);
newCheck += `>`;
this.add(newCheck);
};
text(setting) {
let newText = `<input type = "text"`;
setting.id && (newText += ` id = ${setting.id}`);
setting.style && (newText += ` style = ${setting.style.replaceAll(" ",
"")}`);
setting.class && (newText += ` class = ${setting.class}`);
setting.size && (newText += ` size = ${setting.size}`);
setting.maxLength && (newText += ` maxLength = ${setting.maxLength}`);
setting.value && (newText += ` value = ${setting.value}`);
setting.placeHolder && (newText += ` placeHolder = $
{setting.placeHolder.replaceAll(" ", " ")}`);
newText += `>`;
this.add(newText);
};
select(setting) {
let newSelect = `<select`;
setting.id && (newSelect += ` id = ${setting.id}`);
setting.style && (newSelect += ` style = ${setting.style.replaceAll(" ",
"")}`);
setting.class && (newSelect += ` class = ${setting.class}`);
newSelect += `>`;
for (let options in setting.option) {
newSelect += `<option value = ${setting.option[options].id}`
setting.option[options].selected && (newSelect += ` selected`);
newSelect += `>${options}</option>`;
}
newSelect += `</select>`;
this.add(newSelect);
};
button(setting) {
let newButton = `<button`;
setting.id && (newButton += ` id = ${setting.id}`);
setting.style && (newButton += ` style = ${setting.style.replaceAll(" ",
"")}`);
setting.class && (newButton += ` class = ${setting.class}`);
setting.onclick && (newButton += ` onclick = ${setting.onclick}`);
newButton += `>`;
setting.innerHTML && (newButton += setting.innerHTML);
newButton += `</button>`;
this.add(newButton);
};
selectMenu(setting) {
let newSelect = `<select`;
if (!setting.id) {
alert("please put id skid");
return;
}
window[setting.id + "Func"] = function() {};
setting.id && (newSelect += ` id = ${setting.id}`);
setting.style && (newSelect += ` style = ${setting.style.replaceAll(" ",
"")}`);
setting.class && (newSelect += ` class = ${setting.class}`);
newSelect += ` onchange = window.${setting.id + "Func"}()`;
newSelect += `>`;
let last;
let i = 0;
for (let options in setting.menu) {
newSelect += `<option value = ${"option_" + options} id = ${"O_" +
options}`;
setting.menu[options] && (newSelect += ` checked`);
newSelect += ` style = "color: ${setting.menu[options] ? "#000" :
"#fff"}; background: ${setting.menu[options] ? "#8ecc51" : "#cc5151"};">$
{options}</option>`;
i++;
}
newSelect += `</select>`;
this.add(newSelect);
i = 0;
for (let options in setting.menu) {
window[options + "Func"] = function() {
setting.menu[options] = getEl("check_" + options).checked ? true :
false;
getEl("O_" + options).style.color = setting.menu[options] ?
"#000" : "#fff";
getEl("O_" + options).style.background = setting.menu[options] ?
"#8ecc51" : "#cc5151";
};
this.checkBox({
id: "check_" + options,
style: `display: ${i == 0 ? "inline-block" : "none"};`,
class: "checkB",
onclick: `window.${options + "Func"}()`,
checked: setting.menu[options]
});
i++;
}
//getEl(setting.id).style.color = setting.menu[last.split("_")[1]] ?
"#8ecc51" : "#fff";
};
};
};
class Html {
constructor() {
this.element = null;
this.action = null;
this.divElement = null;
this.startDiv = function(setting, func) {
};
this.addDiv = function(setting, func) {
};
};
set(id) {
this.element = getEl(id);
this.action = new HtmlAction(this.element);
};
resetHTML(text) {
if (text) {
this.element.innerHTML = ``;
} else {
this.element.innerHTML = ``;
}
};
setStyle(style) {
this.element.style = style;
};
setCSS(style) {
this.action.add(`<style>` + style + `</style>`);
};
};
// chatlog
let HTML = new Html
let menuChatDiv = document.createElement("div");
menuChatDiv.id = "menuChatDiv";
document.body.appendChild(menuChatDiv);
HTML.set("menuChatDiv");
HTML.setStyle(`position: absolute;
left: 0px;
top: 0px;
`);
HTML.resetHTML();
HTML.setCSS(`
.chDiv{
color: #fff;
padding: 10px;
width: 450px;
height: 250px;
background-color: rgba(0, 0, 0, 0.05);
border-radius: 10px;
}
.chMainDiv{
font-family: "Hammersmith One";
font-size: 12px;
max-height: 180px;
overflow-y: scroll;
padding: 10px;
scrollbar-width: none;
}
.chMainDiv::-webkit-scrollbar {
display: none;
}
.menuChDisp {
margin-bottom: 10px;
padding: 5px;
border-radius: 5px;
background-color: rgba(0, 0, 0, 0.05);
}
.chMainBox{
position: absolute;
left: 10px;
bottom: 10px;
width: 420px;
height: 30px;
background-color: rgba(128, 128, 128, 0.05);
border-radius: 4px;
color: #fff;
font-family: "Hammersmith One";
font-size: 16px;
border: none;
outline: none;
padding: 5px;
}
`);
HTML.startDiv({
id: "mChDiv",
class: "chDiv"
}, (html) => {
HTML.addDiv({
id: "mChMain",
class: "chMainDiv",
appendID: "mChDiv"
}, (html) => {});
html.text({
id: "mChBox",
class: "chMainBox",
placeHolder: `To chat click here or press "Enter" key`,
});
});
let menuChats = getEl("mChMain");
let menuChatBox = getEl("mChBox");
let menuCBFocus = false;
let menuChCounts = 0;
menuChatBox.value = "";
menuChatBox.addEventListener("focus", () => {
menuCBFocus = true;
});
menuChatBox.addEventListener("blur", () => {
menuCBFocus = false;
});
function replaceHTML(string) {
return string.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>',
'>')
}
let lastMsg = null;
let lastMsgCount = 0;
function addMenuChText(name, message, color, noTimer) {
HTML.set("menuChatDiv");
message = replaceHTML(message);
color = color || "white";
let time = new Date();
let min = time.getMinutes();
let hour = time.getHours();
let getAMPM = hour >= 12 ? "PM" : "AM";
let text = ``;
if (!noTimer) text += `[${(hour % 12) + ":" + min + " " + getAMPM}]`;
if (name) text += `${(!noTimer ? " - " : "") + name}`;
if (lastMsg !== null && lastMsg !== undefined) {
let lastMessageDiv = document.getElementById(lastMsg);
if (lastMessageDiv && lastMessageDiv.innerText.includes(message)) {
lastMsgCount++;
lastMessageDiv.innerText = lastMessageDiv.innerText.replace(/\s*\(\
d+x\)$/, '');
lastMessageDiv.innerText += ` (${lastMsgCount}x)`;
return;
}
}
lastMsgCount = 1;
lastMsg = "menuChDisp" + (menuChCounts + 1);
text += `${(name ? ": " : !noTimer ? " - " : "") + message}\n`;
menuChCounts++;
if (menuChCounts > 250) { //holy shit we need a limit dawg, just to keep the
FPS safe
resetMenuChText();
addMenuChText(null, "Successfully Auto-Cleared Chat", "lime", 1);
}
HTML.addDiv({id: lastMsg, style: `color: ${color}`, appendID: "mChMain"},
(html) => {
html.add(text);
});
menuChats.scrollTop = menuChats.scrollHeight;
}
function resetMenuChText() {
menuChats.innerHTML = ``;
menuChCounts = 0;
addMenuChText(null, "Current Commands:", "white", 1)
addMenuChText(null, ".block {enemy sid}", "white", 1)
addMenuChText(null, ".unblock {enemy sid}", "white", 1)
}
resetMenuChText();
let game = {
tick: 0,
tickQueue: [],
tickBase: function(set, tick) {
if (this.tickQueue[this.tick + tick]) {
this.tickQueue[this.tick + tick].push(set);
} else {
this.tickQueue[this.tick + tick] = [set];
}
},
tickRate: (1000 / config.serverUpdateRate),
tickSpeed: 0,
lastTick: performance.now()
};
// packet handling shit
let lastMoveDir = undefined;
let lastsp = ["cc", 1, "__proto__"];
let io = {
socket: null,
connected: false,
socketId: -1,
secPacket: 0,
secTime: 1000,
timerRunning: false,
connect: function(callback, events) {
if (this.socket) return;
let _this = this;
try {
let socketError = false;
WebSocket.prototype.sends = WebSocket.prototype.send;
WebSocket.prototype.send = function(message) {
if (!_this.socket) {
_this.socket = this;
_this.socket.addEventListener("message", (event) => {
let data = new Uint8Array(event.data);
let parsed = msgpack.decode(data);
let type = parsed[0];
data = parsed[1];
if (type == "M") { // name and skin color
data[0].name = data[0].name === "" ? "Fran" :
data[0].name;
data[0].moofoll = true;
data[0].skin = data[0].skin === 10 ? "__proto__" :
data[0].skin;
lastsp = [data[0].name, data[0].moofoll, data[0].skin];
}
if (type === "io-init") {
_this.socketId = data[0];
} else {
if (events[type]) {
events[type].apply(undefined, data);
}
}
});
_this.connected = true;
_this.socket.addEventListener("open", () => {
_this.connected = true;
callback();
});
_this.socket.addEventListener("close", (event) => {
_this.connected = false;
if (event.code == 4001) {
callback("Invalid Connection");
} else if (!socketError) {
callback("disconnected");
}
});
_this.socket.addEventListener("error", (error) => {
if (_this.socket && _this.socket.readyState !==
WebSocket.OPEN) {
socketError = true;
callback("Socket error");
}
});
}
this.sends(message);
};
} catch (e) {
console.error("Error in connect:", e);
}
},
send: function(type) {
let data = Array.prototype.slice.call(arguments, 1);
let binary = msgpack.encode([type, data]);
this.socket.send(binary);
this.secPacket++;
if (!this.timerRunning) {
this.timerRunning = true;
setTimeout(() => {
this.secPacket = 0;
this.timerRunning = false;
}, this.secTime);
}
},
socketReady: function() {
return this.socket && this.connected;
},
close: function() {
this.socket && this.socket.close();
},
};
// just added this so i can actually prevent shit from sending useless packets
WebSocket.prototype.nsend = WebSocket.prototype.send;
WebSocket.prototype.send = function (message) {
let dontSend = false;
let WS = undefined;
if (!WS) {
WS = this;
WS.addEventListener("close", event => {
if (event.code == 4001) {
window.location.reload();
}
});
}
if (WS == this) {
dontSend = false;
let data = new Uint8Array(message);
let parsed = msgpack.decode(data);
let type = parsed[0];
data = parsed[1];
if (type == "F") {
if (!data[2]) {
dontSend = true;
} else if (![null, undefined].includes(data[1])) {
asura.lastDir = data[1];
}
} else if (type == "K") {
if (!data[1]) {
dontSend = true;
}
} else if (type == "f") {
if (data[1]) {
if (player.moveDir == data[0]) {
dontSend = true;
}
player.moveDir = data[0];
} else {
dontSend = true;
}
}
if (!dontSend) {
let binary = msgpack.encode([type, data]);
this.nsend(binary);
}
} else {
this.nsend(message);
}
};
// encoding and decoding shit
function serialize(data) {
const pow32 = 0x100000000;
let floatBuffer, floatView;
let array = new Uint8Array(128);
let length = 0;
append(data);
return array.subarray(0, length);
function append(data) {
switch (typeof data) {
case "undefined":
appendNull(data);
break;
case "boolean":
appendBoolean(data);
break;
case "number":
appendNumber(data);
break;
case "string":
appendString(data);
break;
case "object":
if (data === null) {
appendNull(data);
} else if (data instanceof Date) {
appendDate(data);
} else if (Array.isArray(data)) {
appendArray(data);
} else if (data instanceof Uint8Array || data instanceof
Uint8ClampedArray) {
appendBinArray(data);
} else if (data instanceof Int8Array || data instanceof Int16Array
|| data instanceof Uint16Array ||
data instanceof Int32Array || data instanceof
Uint32Array ||
data instanceof Float32Array || data instanceof
Float64Array) {
appendArray(data);
} else {
appendObject(data);
}
break;
}
}
function appendNull(data) {
appendByte(0xc0);
}
function appendBoolean(data) {
appendByte(data ? 0xc3 : 0xc2);
}
function appendNumber(data) {
if (isFinite(data) && Math.floor(data) === data) {
if (data >= 0 && data <= 0x7f) {
appendByte(data);
} else if (data < 0 && data >= -0x20) {
appendByte(data);
} else if (data > 0 && data <= 0xff) { // uint8
appendBytes([0xcc, data]);
} else if (data >= -0x80 && data <= 0x7f) { // int8
appendBytes([0xd0, data]);
} else if (data > 0 && data <= 0xffff) { // uint16
appendBytes([0xcd, data >>> 8, data]);
} else if (data >= -0x8000 && data <= 0x7fff) { // int16
appendBytes([0xd1, data >>> 8, data]);
} else if (data > 0 && data <= 0xffffffff) { // uint32
appendBytes([0xce, data >>> 24, data >>> 16, data >>> 8, data]);
} else if (data >= -0x80000000 && data <= 0x7fffffff) { // int32
appendBytes([0xd2, data >>> 24, data >>> 16, data >>> 8, data]);
} else if (data > 0 && data <= 0xffffffffffffffff) { // uint64
let hi = data / pow32;
let lo = data % pow32;
appendBytes([0xd3, hi >>> 24, hi >>> 16, hi >>> 8, hi, lo >>> 24,
lo >>> 16, lo >>> 8, lo]);
} else if (data >= -0x8000000000000000 && data <= 0x7fffffffffffffff) {
// int64
appendByte(0xd3);
appendInt64(data);
} else if (data < 0) { // below int64
appendBytes([0xd3, 0x80, 0, 0, 0, 0, 0, 0, 0]);
} else { // above uint64
appendBytes([0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff]);
}
} else {
if (!floatView) {
floatBuffer = new ArrayBuffer(8);
floatView = new DataView(floatBuffer);
}
floatView.setFloat64(0, data);
appendByte(0xcb);
appendBytes(new Uint8Array(floatBuffer));
}
}
function appendString(data) {
let bytes = encodeUtf8(data);
let length = bytes.length;
appendBytes(bytes);
}
function appendArray(data) {
let length = data.length;
if (length <= 0xf) {
appendByte(0x90 + length);
} else if (length <= 0xffff) {
appendBytes([0xdc, length >>> 8, length]);
} else {
appendBytes([0xdd, length >>> 24, length >>> 16, length >>> 8,
length]);
}
for (let index = 0; index < length; index++) {
append(data[index]);
}
}
function appendBinArray(data) {
let length = data.length;
if (length <= 0xf) {
appendBytes([0xc4, length]);
} else if (length <= 0xffff) {
appendBytes([0xc5, length >>> 8, length]);
} else {
appendBytes([0xc6, length >>> 24, length >>> 16, length >>> 8,
length]);
}
appendBytes(data);
}
function appendObject(data) {
let length = 0;
for (let key in data) length++;
if (length <= 0xf) {
appendByte(0x80 + length);
} else if (length <= 0xffff) {
appendBytes([0xde, length >>> 8, length]);
} else {
appendBytes([0xdf, length >>> 24, length >>> 16, length >>> 8,
length]);
}
for (let key in data) {
append(key);
append(data[key]);
}
}
function appendDate(data) {
let sec = data.getTime() / 1000;
if (data.getMilliseconds() === 0 && sec >= 0 && sec < 0x100000000) { // 32
bit seconds
appendBytes([0xd6, 0xff, sec >>> 24, sec >>> 16, sec >>> 8, sec]);
}
else if (sec >= 0 && sec < 0x400000000) { // 30 bit nanoseconds, 34 bit
seconds
let ns = data.getMilliseconds() * 1000000;
appendBytes([0xd7, 0xff, ns >>> 22, ns >>> 14, ns >>> 6, ((ns << 2) >>>
0) | (sec / pow32), sec >>> 24, sec >>> 16, sec >>> 8, sec]);
}
else { // 32 bit nanoseconds, 64 bit seconds, negative values allowed
let ns = data.getMilliseconds() * 1000000;
appendBytes([0xc7, 12, 0xff, ns >>> 24, ns >>> 16, ns >>> 8, ns]);
appendInt64(sec);
}
}
function appendByte(byte) {
if (array.length < length + 1) {
let newLength = array.length * 2;
while (newLength < length + 1) newLength *= 2;
let newArray = new Uint8Array(newLength);
newArray.set(array);
array = newArray;
}
array[length] = byte;
length++;
}
function appendBytes(bytes) {
if (array.length < length + bytes.length) {
let newLength = array.length * 2;
while (newLength < length + bytes.length) newLength *= 2;
let newArray = new Uint8Array(newLength);
newArray.set(array);
array = newArray;
}
array.set(bytes, length);
length += bytes.length;
}
function appendInt64(value) {
let hi, lo;
if (value >= 0) {
hi = value / pow32;
lo = value % pow32;
}
else {
value++;
hi = Math.abs(value) / pow32;
lo = Math.abs(value) % pow32;
hi = ~hi;
lo = ~lo;
}
appendBytes([hi >>> 24, hi >>> 16, hi >>> 8, hi, lo >>> 24, lo >>> 16, lo
>>> 8, lo]);
}
}
function deserialize(array) {
const pow32 = 0x100000000; // 2^32
let pos = 0;
if (array instanceof ArrayBuffer) {
array = new Uint8Array(array);
}
if (typeof array !== "object" || typeof array.length === "undefined") {
throw new Error("Invalid argument type: Expected a byte array (Array or
Uint8Array) to deserialize.");
}
if (!array.length) {
throw new Error("Invalid argument: The byte array to deserialize is
empty.");
}
if (!(array instanceof Uint8Array)) {
array = new Uint8Array(array);
}
let data = read();
if (pos < array.length) {
}
return data;
function read() {
const byte = array[pos++];
if (byte >= 0x00 && byte <= 0x7f) return byte; // positive fixint
if (byte >= 0x80 && byte <= 0x8f) return readMap(byte - 0x80); // fixmap
if (byte >= 0x90 && byte <= 0x9f) return readArray(byte - 0x90); //
fixarray
if (byte >= 0xa0 && byte <= 0xbf) return readStr(byte - 0xa0); // fixstr
if (byte === 0xc0) return null; // nil
if (byte === 0xc1) throw new Error("Invalid byte code 0xc1 found."); //
never used
if (byte === 0xc2) return false // false
if (byte === 0xc3) return true; // true
if (byte === 0xc4) return readBin(-1, 1); // bin 8
if (byte === 0xc5) return readBin(-1, 2); // bin 16
if (byte === 0xc6) return readBin(-1, 4); // bin 32
if (byte === 0xc7) return readExt(-1, 1); // ext 8
if (byte === 0xc8) return readExt(-1, 2); // ext 16
if (byte === 0xc9) return readExt(-1, 4) // ext 32
if (byte === 0xca) return readFloat(4); // float 32
if (byte === 0xcb) return readFloat(8); // float 64
if (byte === 0xcc) return readUInt(1); // uint 8
if (byte === 0xcd) return readUInt(2); // uint 16
if (byte === 0xce) return readUInt(4); // uint 32
if (byte === 0xcf) return readUInt(8) // uint 64
if (byte === 0xd0) return readInt(1); // int 8
if (byte === 0xd1) return readInt(2); // int 16
if (byte === 0xd2) return readInt(4); // int 32
if (byte === 0xd3) return readInt(8); // int 64
if (byte === 0xd4) return readExt(1); // fixext 1
if (byte === 0xd5) return readExt(2); // fixext 2
if (byte === 0xd6) return readExt(4); // fixext 4
if (byte === 0xd7) return readExt(8); // fixext 8
if (byte === 0xd8) return readExt(16); // fixext 16
if (byte === 0xd9) return readStr(-1, 1); // str 8
if (byte === 0xda) return readStr(-1, 2); // str 16
if (byte === 0xdb) return readStr(-1, 4); // str 32
if (byte === 0xdc) return readArray(-1, 2); // array 16
if (byte === 0xdd) return readArray(-1, 4); // array 32
if (byte === 0xde) return readMap(-1, 2); // map 16
if (byte === 0xdf) return readMap(-1, 4); // map 32
if (byte >= 0xe0 && byte <= 0xff) return byte - 256; // negative fixint
console.debug("msgpack array:", array);
throw new Error("Invalid byte value '" + byte + "' at index " + (pos - 1) +
" in the MessagePack binary data (length " + array.length + "): Expecting a range
of 0 to 255. This is not a byte array.");
}
function readInt(size) {
let value = 0;
let first = true;
while (size-- > 0) {
if (first) {
let byte = array[pos++];
value += byte & 0x7f;
if (byte & 0x80) {
value -= 0x80;
}
first = false;
}
else {
value *= 256;
value += array[pos++];
}
}
return value;
}
function readUInt(size) {
let value = 0;
while (size-- > 0) {
value *= 256;
value += array[pos++];
}
return value;
}
function readFloat(size) {
let view = new DataView(array.buffer, pos, size);
pos += size;
if (size === 4) {
return view.getFloat32(0, false);
}
if (size === 8) {
return view.getFloat64(0, false);
}
}
function readBin(size, lengthSize) {
if (size < 0) size = readUInt(lengthSize);
let data = array.subarray(pos, pos + size);
pos += size;
return data;
}
function readMap(size, lengthSize) {
if (size < 0) size = readUInt(lengthSize);
let data = {};
while (size-- > 0) {
let key = read();
data[key] = read();
}
return data;
}
function readArray(size, lengthSize) {
if (size < 0) size = readUInt(lengthSize);
let data = [];
while (size-- > 0) {
data.push(read());
}
return data;
}
function readStr(size, lengthSize) {
if (size < 0) size = readUInt(lengthSize);
let start = pos;
pos += size;
return decodeUtf8(array, start, size);
}
function readExt(size, lengthSize) {
if (size < 0) size = readUInt(lengthSize);
let type = readUInt(1);
let data = readBin(size);
switch (type) {
case 255:
return readExtDate(data);
}
return { type: type, data: data };
}
function readExtDate(data) {
if (data.length === 4) {
let sec = ((data[0] << 24) >>> 0) +
((data[1] << 16) >>> 0) +
((data[2] << 8) >>> 0) +
data[3];
return new Date(sec * 1000);
}
if (data.length === 8) {
let ns = ((data[0] << 22) >>> 0) +
((data[1] << 14) >>> 0) +
((data[2] << 6) >>> 0) +
(data[3] >>> 2);
let sec = ((data[3] & 0x3) * pow32) +
((data[4] << 24) >>> 0) +
((data[5] << 16) >>> 0) +
((data[6] << 8) >>> 0) +
data[7];
return new Date(sec * 1000 + ns / 1000000);
}
if (data.length === 12) {
let ns = ((data[0] << 24) >>> 0) +
((data[1] << 16) >>> 0) +
((data[2] << 8) >>> 0) +
data[3];
pos -= 8;
let sec = readInt(8);
return new Date(sec * 1000 + ns / 1000000);
}
throw new Error("Invalid data length for a date value.");
}
}
function encodeUtf8(str) {
let ascii = true, length = str.length;
for (let x = 0; x < length; x++) {
if (str.charCodeAt(x) > 127) {
ascii = false;
break;
}
}
let i = 0, bytes = new Uint8Array(str.length * (ascii ? 1 : 4));
for (let ci = 0; ci !== length; ci++) {
let c = str.charCodeAt(ci);
if (c < 128) {
bytes[i++] = c;
continue;
}
if (c < 2048) {
bytes[i++] = c >> 6 | 192;
}
else {
if (c > 0xd7ff && c < 0xdc00) {
if (++ci >= length) throw new Error("UTF-8 encode: incomplete
surrogate pair");
let c2 = str.charCodeAt(ci);
if (c2 < 0xdc00 || c2 > 0xdfff) throw new Error("UTF-8 encode:
second surrogate character 0x" + c2.toString(16) + " at index " + ci + " out of
range");
c = 0x10000 + ((c & 0x03ff) << 10) + (c2 & 0x03ff);
bytes[i++] = c >> 18 | 240;
bytes[i++] = c >> 12 & 63 | 128;
}
else bytes[i++] = c >> 12 | 224;
bytes[i++] = c >> 6 & 63 | 128;
}
bytes[i++] = c & 63 | 128;
}
return ascii ? bytes : bytes.subarray(0, i);
}
function decodeUtf8(bytes, start, length) {
let i = start, str = "";
length += start;
while (i < length) {
let c = bytes[i++];
if (c > 127) {
if (c > 191 && c < 224) {
if (i >= length) throw new Error("UTF-8 decode: incomplete 2-byte
sequence");
c = (c & 31) << 6 | bytes[i++] & 63;
}
else if (c > 223 && c < 240) {
if (i + 1 >= length) throw new Error("UTF-8 decode: incomplete 3-
byte sequence");
c = (c & 15) << 12 | (bytes[i++] & 63) << 6 | bytes[i++] & 63;
}
else if (c > 239 && c < 248) {
if (i + 2 >= length) throw new Error("UTF-8 decode: incomplete 4-
byte sequence");
c = (c & 7) << 18 | (bytes[i++] & 63) << 12 | (bytes[i++] & 63) <<
6 | bytes[i++] & 63;
}
else throw new Error("UTF-8 decode: unknown multibyte start 0x" +
c.toString(16) + " at index " + (i - 1));
}
if (c <= 0xffff) str += String.fromCharCode(c);
else if (c <= 0x10ffff) {
c -= 0x10000;
str += String.fromCharCode(c >> 10 | 0xd800)
str += String.fromCharCode(c & 0x3FF | 0xdc00)
}
else throw new Error("UTF-8 decode: code point 0x" + c.toString(16) + "
exceeds UTF-16 reach");
}
return str;
}
let msgpack = {
serialize: serialize,
deserialize: deserialize,
encode: serialize,
decode: deserialize
};
var module = { // kys asshole
exports: {}
};
if (typeof module === "object" && module && typeof module.exports === "object") {
module.exports = msgpack;
}
else {
window[window.msgpackJsName || "msgpack"] = msgpack;
}
// user client to server shit
function disconnect(reason) {
io.close();
console.log(reason);
}
io.connect(function(error) {
if (error) disconnect(error);
}, {
A: setInitData,
B: disconnect,
C: setupGame,
D: addPlayer,
E: removePlayer,
a: updatePlayers,
G: updateLeaderboard,
H: loadGameObject,
I: loadAI,
J: animateAI,
K: gatherAnimation,
L: wiggleGameObject,
M: shootTurret,
N: updatePlayerValue,
O: updateHealth,
P: killPlayer,
Q: killObject,
R: killObjects,
S: updateItemCounts,
T: updateAge,
U: updateUpgrades,
V: updateItems,
X: addProjectile,
Y: remProjectile,
3: setPlayerTeam,
4: setAlliancePlayers,
5: updateStoreItems,
6: receiveChat,
7: updateMinimap,
8: showText,
9: pingMap,
0: pingSocketResponse
});
function resetMoveDir() {
keys = {};
io.send("e");
}
let ticks = {
tick: 0,
delay: 0,
time: [],
manage: [],
};
// variables
let screenWidth, screenHeight, enterGameButton = getEl("enterGame"), gameUI =
getEl("gameUI"), settingsButton = getEl("settingsButton"), settingsButtonTitle =
settingsButton.getElementsByTagName("span")[0], guideCard = getEl("guideCard"),
maxScreenWidth = config.maxScreenWidth, maxScreenHeight = config.maxScreenHeight,
pixelDensity = 1, ais = [], players = [], alliances = [], alliancePlayers = [],
gameObjects = [], objects = [], projectiles = [], breakObjects = [], enemies = [],
niggers = [], nears = [], near = [], lastLeaderboardData = [], player, playerSID,
tmpObj, tmpDir, lastDir, camX, camY, mouseX = 0, mouseY = 0, waterMult = 1,
waterPlus = 0, outlineColor = "#525252", darkOutlineColor = "#3d3f42", outlineWidth
= 6.5, firstSetup = true, keys = {}, moveKeys = {87:[0,-1],38:[0,-1],83:[0,1],40:
[0,1],65:[-1,0],37:[-1,0],68:[1,0],39:[1,0]}, attackState = 0, inGame = false,
macro = {}, mills = {place: 0}, inWindow = true, delta, now, lastUpdate =
performance.now(), mapDisplay = getEl("mapDisplay"), mapContext =
mapDisplay.getContext("2d"), gameCanvas = getEl("gameCanvas"), mainContext =
gameCanvas.getContext("2d"), storeMenu = getEl("storeMenu"), storeHolder =
getEl("storeHolder"), upgradeHolder = getEl("upgradeHolder"), upgradeCounter =
getEl("upgradeCounter"), chatBox = getEl("chatBox"), chatHolder =
getEl("chatHolder"), actionBar = getEl("actionBar"), leaderboardData =
getEl("leaderboardData"), itemInfoHolder = getEl("itemInfoHolder"), menuCardHolder
= getEl("menuCardHolder"), mainMenu = getEl("mainMenu"), diedText =
getEl("diedText"), allianceMenu = getEl("allianceMenu");
mapDisplay.width = 300;
mapDisplay.height = 300;
let ms = {
avg: 0,
max: 0,
min: 0,
suddenSpikeThreshold: 3,
spikeCount: 0,
stdDev: 0,
pingHistory: [], // store ping times for calculating stdDev
mahiru: 0,
EWMStdDev: 0,
alpha: 0.1,
beta: 0.1
}
getEl("promoImg").remove();
document.getElementById('loadingText').innerHTML = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
.progress-container {
top: 80%;
left: 50%;
transform: translate(-50%, -50%) scale(0.5);
width: 75%;
background-color: gray;
border-radius: 25px;
overflow: hidden;
height: 90px;
position: relative;
}
.progress-bar {
width: 0%;
margin-top: 5px;
margin-left: 5px;
height: 80%;
background-color: #fff;
border-radius: 25px;
animation: loading 1.1s linear forwards;
position: relative;
}
@keyframes loading {
from { width: 0%; }
to { width: 98%; }
}
.progress-text {
position: absolute;
top: 50%;
font-size: 50px;
left: 50%;
transform: translate(-50%, -50%);
color: black;
font-weight: bold;
}
</style>
</head>
<body>
<div class="progress-container">
<div class="progress-bar">
<div class="progress-text" id="progressText">Loading...</div>
</div>
</div>
</body>
</html>
`;
let lagspike = false;
// sid shit
function findID(tmpObj, tmp) {
return tmpObj.find((THIS) => THIS.id == tmp);
}
function findSID(tmpObj, tmp) {
return tmpObj.find((THIS) => THIS.sid == tmp);
}
function findPlayerByID(id) {
return findID(players, id);
}
function findPlayerBySID(sid) {
return findSID(players, sid);
}
function findAIBySID(sid) {
return findSID(ais, sid);
}
function findObjectBySid(sid) {
return findSID(gameObjects, sid);
}
function findAllianceBySid(sid) {
return player.team ? alliancePlayers.find((THIS) => THIS === sid) : null;
}
// ping socket stuff
let lastResetTime = Date.now()
function pingSocketResponse() {
let pingTime = window.pingTime;
let currentTime = Date.now();
const pingDisplay = document.getElementById("pingDisplay")
pingDisplay.innerText = "Ping: " + pingTime + " || FPS " + asura.FPS;
ms.pingHistory.push(pingTime);
if (ms.pingHistory.length > 10) {
ms.pingHistory.shift();
}
if (ms.mahiru === 0) {
ms.mahiru = pingTime;
} else {
ms.mahiru = (1 - ms.alpha) * ms.mahiru + ms.alpha * pingTime;
}
if (currentTime - lastResetTime >= 300000) {
ms.spikeCount = 0;
lastResetTime = currentTime;
}
if (ms.EWMStdDev === 0) {
ms.EWMStdDev = Math.abs(pingTime - ms.mahiru);
} else {
ms.EWMStdDev = (1 - ms.beta) * ms.EWMStdDev + ms.beta * Math.abs(pingTime -
ms.mahiru);
}
// detect lag spikes (should be fixed)
if (Math.abs(pingTime - ms.mahiru) > ms.suddenSpikeThreshold * ms.EWMStdDev) {
lagspike = true;
ms.spikeCount++;
textManager.showText(player.x, player.y, 30, 0.15, 1850, 'LagSpike
Detected', 'red', 2);
console.log(`lagspike detected ` + pingTime);
} else {
lagspike = false;
console.log(ms.spikeCount)
}
// detect unstable ping
if (ms.EWMStdDev > 20 && !lagspike) {
textManager.showText(player.x, player.y, 30, 0.15, 1850, 'Unstable Ping
Detected', 'orange', 2);
console.log(`unstable ping detected ` + ms.EWMStdDev);
}
}
// Utils
function UTILZ() {
const mathABS = Math.abs,
mathCOS = Math.cos,
mathSIN = Math.sin,
mathPOW = Math.pow,
mathSQRT = Math.sqrt,
mathATAN2 = Math.atan2,
mathPI = Math.PI;
this.round = function(n, v) {
return Math.round(n * v) / v;
};
this.toRad = function(angle) {
return angle * (mathPI / 180);
};
this.toAng = function(radian) {
return radian / (mathPI / 180);
};
this.randInt = function(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
this.randFloat = function(min, max) {
return Math.random() * (max - min + 1) + min;
};
this.lerp = function(value1, value2, amount) {
return value1 + (value2 - value1) * amount;
};
this.decel = function(val, cel) {
if (val > 0) val = Math.max(0, val - cel);
else if (val < 0) val = Math.min(0, val + cel);
return val;
};
this.getPosFromAngle = function (referencePoint, angle, distance) {
return {
x: referencePoint.x + Math.cos(angle) * distance,
y: referencePoint.y + Math.sin(angle) * distance
};
};
this.createTempObject = function() {
return { x: 0, y: 0, scale: 0 }
};
this.getDistance = function(x1, y1, x2, y2) {
return mathSQRT((x2 -= x1) * x2 + (y2 -= y1) * y2);
};
this.getDist2 = function(a, b, v1 = '', v2 = '') {
if (v1 === 0) v1 = '';
if (v2 === 0) v2 = '';
return Math.hypot(a[`x${v1}`] - b[`x${v2}`], a[`y${v1}`] - b[`y${v2}`]);
};
this.getDist = function (tmp1, tmp2, type1, type2) {
let tmpXY1 = {
x: type1 == 0 ? tmp1.x : type1 == 1 ? tmp1.x1 : type1 == 2 ? tmp1.x2 :
type1 == 3 && tmp1.x3,
y: type1 == 0 ? tmp1.y : type1 == 1 ? tmp1.y1 : type1 == 2 ? tmp1.y2 :
type1 == 3 && tmp1.y3,
};
let tmpXY2 = {
x: type2 == 0 ? tmp2.x : type2 == 1 ? tmp2.x1 : type2 == 2 ? tmp2.x2 :
type2 == 3 && tmp2.x3,
y: type2 == 0 ? tmp2.y : type2 == 1 ? tmp2.y1 : type2 == 2 ? tmp2.y2 :
type2 == 3 && tmp2.y3,
};
return mathSQRT((tmpXY2.x -= tmpXY1.x) * tmpXY2.x + (tmpXY2.y -= tmpXY1.y)
* tmpXY2.y);
};
this.dist = function(t, n, i = "", o = "") {
return Math.hypot(
t[`x${i || ""}`] - n[`x${o || ""}`],
t[`y${i || ""}`] - n[`y${o || ""}`]
);
}
this.getDirection = function(x1, y1, x2, y2) {
return mathATAN2(y1 - y2, x1 - x2);
};
this.lerpAngle = function(value1, value2, amount) {
let difference = Math.abs(value2 - value1);
if (difference > Math.PI) {
if (value1 > value2) {
value2 += Math.PI * 2;
} else {
value1 += Math.PI * 2;
}
}
let value = value2 + ((value1 - value2) * amount);
if (value >= 0 && value <= Math.PI * 2) return value;
return value % (Math.PI * 2);
};
this.getDirect = function(tmp1, tmp2, type1, type2) {
const tmpXY1 = {
x: type1 === 0 ? tmp1.x : type1 === 1 ? tmp1.x1 : type1 === 2 ? tmp1.x2
: type1 === 3 && tmp1.x3,
y: type1 === 0 ? tmp1.y : type1 === 1 ? tmp1.y1 : type1 === 2 ? tmp1.y2
: type1 === 3 && tmp1.y3,
};
const tmpXY2 = {
x: type2 === 0 ? tmp2.x : type2 === 1 ? tmp2.x1 : type2 === 2 ? tmp2.x2
: type2 === 3 && tmp2.x3,
y: type2 === 0 ? tmp2.y : type2 === 1 ? tmp2.y1 : type2 === 2 ? tmp2.y2
: type2 === 3 && tmp2.y3,
};
return mathATAN2(tmpXY1.y - tmpXY2.y, tmpXY1.x - tmpXY2.x);
};
this.getAngle = function (pointA, pointB) {
return Math.atan2(pointB.y - pointA.y, pointB.x - pointA.x);
};
this.getAngleDist = function(a, b) {
const p = mathABS(b - a) % (mathPI * 2);
return (p > mathPI ? (mathPI * 2) - p : p);
};
this.isNumber = function(n) {
return (typeof n === "number" && !isNaN(n) && isFinite(n));
};
this.isString = function(s) {
return (s && typeof s === "string");
};
this.kFormat = function(num) {
return num > 999 ? (num / 1000).toFixed(1) + "k" : num;
};
this.sFormat = function(num) {
const fixs = [
{ num: 1e3, string: "k" },
{ num: 1e6, string: "m" },
{ num: 1e9, string: "b" },
{ num: 1e12, string: "q" }
].reverse();
const sp = fixs.find(v => num >= v.num);
if (!sp) return num;
return (num / sp.num).toFixed(1) + sp.string;
};
this.capitalizeFirst = function(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
};
this.fixTo = function(n, v) {
return parseFloat(n.toFixed(v));
};
this.sortByPoints = function(a, b) {
return parseFloat(b.points) - parseFloat(a.points);
};
this.lineInRect = function(recX, recY, recX2, recY2, x1, y1, x2, y2) {
let minX = x1;
let maxX = x2;
if (x1 > x2) {
minX = x2;
maxX = x1;
}
if (maxX > recX2) maxX = recX2;
if (minX < recX) minX = recX;
if (minX > maxX) return false;
let minY = y1;
let maxY = y2;
const dx = x2 - x1;
if (Math.abs(dx) > 0.0000001) {
const a = (y2 - y1) / dx;
const b = y1 - a * x1;
minY = a * minX + b;
maxY = a * maxX + b;
}
if (minY > maxY) {
const tmp = maxY;
maxY = minY;
minY = tmp;
}
if (maxY > recY2) maxY = recY2;
if (minY < recY) minY = recY;
if (minY > maxY) return false;
return true;
};
this.containsPoint = function(element, x, y) {
const bounds = element.getBoundingClientRect();
const left = bounds.left + window.scrollX;
const top = bounds.top + window.scrollY;
const width = bounds.width;
const height = bounds.height;
};
this.removeAllChildren = function(element) {
while (element.hasChildNodes()) {
element.removeChild(element.lastChild);
}
};
this.generateElement = function(config) {
const element = document.createElement(config.tag || "div");
this.checkTrusted = function(callback) {
return function(ev) {
if (ev && ev instanceof Event && (ev && typeof ev.isTrusted ===
"boolean" ? ev.isTrusted : true)) {
callback(ev);
} else {
//console.error("Event is not trusted.", ev);
}
};
};
this.randomString = function(length) {
let text = "";
const possible =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (let i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
};
this.hexToRgb = function(hex) {
return hex.slice(1).match(/.{1,2}/g).map(g => parseInt(g, 16));
};
this.getRgb = function(r, g, b) {
return [r / 255, g / 255, b / 255].join(", ");
};
}
// text rendering
function Animtext() {
this.init = function (posX, posY, scale, speed, life, text, color, type,
playerData) {
this.x = posX;
this.y = posY;
this.color = color;
this.scale = scale;
this.weight = 50;
this.startScale = this.scale * 0.8;
this.maxScale = 1.5 * scale;
this.scaleSpeed = 0.7;
this.speed = speed;
this.speedMax = speed;
this.life = life;
this.maxLife = life;
this.text = text;
this.movSpeed = Math.random() * 1 + 1;
this.movAngle = Math.random() < 0.5;
this.type = type; // type 1 = dmg, type 2 = heal, type 3 = custom
this.playerData = playerData;
};
// UPDATE:
this.update = function (e) {
if (this.life > 0) {
this.life -= e;
if (this.scaleSpeed !== -0.35) {
this.x += this.movAngle ? -this.speed * e * this.movSpeed :
this.speed * e * this.movSpeed;
this.y -= this.speed * e;
}
this.scale += this.scaleSpeed * (e / 4.5);
this.scale = Math.max(this.scale, this.startScale);
if (this.speed < this.speedMax) {
this.speed += this.speedMax * 0.01;
}
if (this.scale >= this.maxScale) {
this.scale = this.maxScale;
this.scaleSpeed *= -0.5;
this.speed *= 0.5;
}
if (this.life <= 0) {
this.life = 0;
}
}
};
// RENDER:
this.render = function (ctxt, xOff, yOff) {
ctxt.strokeStyle = "#000";
ctxt.fillStyle = this.color;
ctxt.globalAlpha = (this.life / this.maxLife) * 2;
ctxt.font = this.scale + "px Hammersmith One";
ctxt.fillText(this.text, this.x - xOff, this.y - yOff);
ctxt.globalAlpha = 1;
};
}
function Textmanager() {
this.texts = [];
this.stack = [];
this.update = function(delta, ctxt, xOff, yOff) {
ctxt.textBaseline = "middle";
ctxt.textAlign = "center";
for (let i = 0; i < this.texts.length; ++i) {
if (this.texts[i].life) {
this.texts[i].update(delta);
this.texts[i].render(ctxt, xOff, yOff);
}
}
};
this.showText = function(x, y, scale, speed, life, text, color) {
let tmpText;
for (let i = 0; i < this.texts.length; ++i) {
if (!this.texts[i].life) {
tmpText = this.texts[i];
break;
}
}
if (!tmpText) {
tmpText = new Animtext();
this.texts.push(tmpText);
}
tmpText.init(x, y, scale, speed, life, text, color);
};
}
// game object stuff
function GameObject(sid) {
this.sid = sid;
this.init = function (x, y, dir, scale, type, data, owner) {
data = data || {};
this.sentTo = {};
this.gridLocations = [];
this.active = true;
this.alive = true;
this.doUpdate = data.doUpdate;
this.x = x;
this.y = y;
this.dir = dir;
this.lastDir = dir;
this.xWiggle = 0;
this.yWiggle = 0;
this.visScale = scale;
this.scale = scale;
this.type = type;
this.id = data.id;
this.owner = owner;
this.name = data.name;
this.isItem = (this.id != undefined);
this.group = data.group;
this.maxHealth = data.health;
this.health = this.maxHealth;
this.layer = 2;
if (this.group != undefined) {
this.layer = this.group.layer;
} else if (this.type == 0) {
this.layer = 3;
} else if (this.type == 2) {
this.layer = 0;
} else if (this.type == 4) {
this.layer = -1;
}
this.colDiv = data.colDiv || 1;
this.blocker = data.blocker;
this.ignoreCollision = data.ignoreCollision;
this.dontGather = data.dontGather;
this.hideFromenemies = data.hideFromenemies;
this.friction = data.friction;
this.projDmg = data.projDmg;
this.dmg = data.dmg;
this.pDmg = data.pDmg;
this.pps = data.pps;
this.zIndex = data.zIndex || 0;
this.turnSpeed = data.turnSpeed;
this.req = data.req;
this.trap = data.trap;
this.healCol = data.healCol;
this.teleport = data.teleport;
this.boostSpeed = data.boostSpeed;
this.projectile = data.projectile;
this.shootRange = data.shootRange;
this.shootRate = data.shootRate;
this.shootCount = this.shootRate;
this.spawnPoint = data.spawnPoint;
this.onNear = 0;
this.breakObj = false;
this.alpha = data.alpha || 1;
this.maxAlpha = data.alpha || 1;
this.damaged = 0;
this.breakTimestamp = 0
};
this.changeHealth = function (amount, doer) {
this.health += amount;
return (this.health <= 0);
};
this.getScale = function (sM, ig) {
sM = sM || 1;
return this.scale * ((this.isItem || this.type == 2 || this.type == 3 ||
this.type == 4) ?
1 : (0.6 * sM)) * (ig ? 1 : this.colDiv);
};
this.visibleToPlayer = function (player) {
return !(this.hideFromenemies) || (this.owner && (this.owner == player ||
(this.owner.team && player.team == this.owner.team)));
};
this.update = function (delta) {
if (this.active) {
if (this.xWiggle) {
this.xWiggle *= Math.pow(0.99, delta);
}
if (this.yWiggle) {
this.yWiggle *= Math.pow(0.99, delta);
}
let d2 = Utils.getAngleDist(this.lastDir, this.dir);
if (d2 > 0.01) {
this.dir += d2 / 5;
} else if (this.turnSpeed && this.dmg) {
this.dir += this.turnSpeed * delta;
} else {
this.dir = this.lastDir;
}
} else {
if (this.alive) {
this.alpha -= delta / (200 / this.maxAlpha);
this.visScale += delta / (this.scale / 2.5);
if (this.alpha <= 0) {
this.alpha = 0;
this.alive = false;
}
}
}
};
this.isTeamObject = function (tmpObj) {
return this.owner == null ? true : (this.owner && tmpObj.sid ==
this.owner.sid || tmpObj.findAllianceBySid(this.owner.sid));
};
}
function Objectmanager(GameObject, gameObjects, Utils, config, players, server) {
let mathFloor = Math.floor,
mathABS = Math.abs,
mathCOS = Math.cos,
mathSIN = Math.sin,
mathPOW = Math.pow,
mathSQRT = Math.sqrt;
this.ignoreAdd = false;
this.hitObj = [];
this.disableObj = function (obj) {
obj.active = false;
};
let tmpObj;
this.add = function (sid, x, y, dir, s, type, data, setSID, owner) {
tmpObj = findObjectBySid(sid);
if (!tmpObj) {
tmpObj = gameObjects.find((tmp) => !tmp.active);
if (!tmpObj) {
tmpObj = new GameObject(sid);
gameObjects.push(tmpObj);
}
}
if (setSID) {
tmpObj.sid = sid;
}
tmpObj.init(x, y, dir, s, type, data, owner);
};
this.disableBySid = function (sid) {
let find = findObjectBySid(sid);
if (find) {
this.disableObj(find);
}
};
this.removeAllItems = function (sid, server) {
gameObjects.filter((tmp) => tmp.active && tmp.owner && tmp.owner.sid ==
sid).forEach((tmp) => this.disableObj(tmp));
};
this.checkItemLocation = function (x, y, s, sM, indx, ignoreWater, placer) {
let cantPlace = gameObjects.find((tmp) => tmp.active &&
Utils.getDistance(x, y, tmp.x, tmp.y) < s + (tmp.blocker ? tmp.blocker :
tmp.getScale(sM, tmp.isItem)));
if (cantPlace) return false;
if (!ignoreWater && indx != 18 && y >= config.mapScale / 2 -
config.riverWidth / 2 && y <= config.mapScale / 2 + config.riverWidth / 2) return
false;
return true;
};
}
// items
function Items() {
this.groups = [{
id: 0,
name: "food",
layer: 0
}, {
id: 1,
name: "walls",
place: true,
limit: 30,
layer: 0
}, {
id: 2,
name: "spikes",
place: true,
limit: 15,
layer: 0
}, {
id: 3,
name: "mill",
place: true,
limit: 7,
layer: 1
}, {
id: 4,
name: "mine",
place: true,
limit: 1,
layer: 0
}, {
id: 5,
name: "trap",
place: true,
limit: 6,
layer: -1
}, {
id: 6,
name: "booster",
place: true,
limit: 12,
layer: -1
}, {
id: 7,
name: "turret",
place: true,
limit: 2,
layer: 1
}, {
id: 8,
name: "watchtower",
place: true,
limit: 12,
layer: 1
}, {
id: 9,
name: "buff",
place: true,
limit: 4,
layer: -1
}, {
id: 10,
name: "spawn",
place: true,
limit: 1,
layer: -1
}, {
id: 11,
name: "sapling",
place: true,
limit: 2,
layer: 0
}, {
id: 12,
name: "blocker",
place: true,
limit: 3,
layer: -1
}, {
id: 13,
name: "teleporter",
place: true,
limit: 2,
layer: -1
}];
this.projectiles = [{
indx: 0,
layer: 0,
src: "arrow_1",
dmg: 25,
speed: 1.6,
scale: 103,
range: 1000
}, {
indx: 1,
layer: 1,
dmg: 25,
scale: 20
}, {
indx: 0,
layer: 0,
src: "arrow_1",
dmg: 35,
speed: 2.5,
scale: 103,
range: 1200
}, {
indx: 0,
layer: 0,
src: "arrow_1",
dmg: 30,
speed: 2,
scale: 103,
range: 1200
}, {
indx: 1,
layer: 1,
dmg: 16,
scale: 20
}, {
indx: 0,
layer: 0,
src: "bullet_1",
dmg: 50,
speed: 3.6,
scale: 160,
range: 1400
}];
this.weapons = [{
id: 0,
type: 0,
name: "tool hammer",
desc: "tool for gathering all resources",
src: "hammer_1",
length: 140,
width: 140,
xOff: -3,
yOff: 18,
dmg: 25,
range: 65,
gather: 1,
speed: 300
}, {
id: 1,
type: 0,
age: 2,
name: "hand axe",
desc: "gathers resources at a higher rate",
src: "axe_1",
length: 140,
width: 140,
xOff: 3,
yOff: 24,
dmg: 30,
spdMult: 1,
range: 70,
gather: 2,
speed: 400
}, {
id: 2,
type: 0,
age: 8,
pre: 1,
name: "great axe",
desc: "deal more damage and gather more resources",
src: "great_axe_1",
length: 140,
width: 140,
xOff: -8,
yOff: 25,
dmg: 35,
spdMult: 1,
range: 75,
gather: 4,
speed: 400
}, {
id: 3,
type: 0,
age: 2,
name: "short sword",
desc: "increased attack power but slower move speed",
src: "samurai_1",
iPad: 1.3,
length: 130,
width: 210,
xOff: -8,
yOff: 59,
dmg: 35,
spdMult: 0.85,
range: 110,
gather: 1,
speed: 300
}, {
id: 4,
type: 0,
age: 8,
pre: 3,
name: "katana",
desc: "greater range and damage",
src: "samurai_1",
iPad: 1.3,
length: 130,
width: 210,
xOff: -8,
yOff: 59,
dmg: 40,
spdMult: 0.8,
range: 118,
gather: 1,
speed: 300
}, {
id: 5,
type: 0,
age: 2,
name: "polearm",
desc: "long range melee weapon",
src: "spear_1",
iPad: 1.3,
length: 130,
width: 210,
xOff: -8,
yOff: 53,
dmg: 45,
knock: 0.2,
spdMult: 0.82,
range: 142,
gather: 1,
speed: 700
}, {
id: 6,
type: 0,
age: 2,
name: "bat",
desc: "fast long range melee weapon",
src: "bat_1",
iPad: 1.3,
length: 110,
width: 180,
xOff: -8,
yOff: 53,
dmg: 20,
knock: 0.7,
range: 110,
gather: 1,
speed: 300
}, {
id: 7,
type: 0,
age: 2,
name: "daggers",
desc: "really fast short range weapon",
src: "dagger_1",
iPad: 0.8,
length: 110,
width: 110,
xOff: 18,
yOff: 0,
dmg: 20,
knock: 0.1,
range: 65,
gather: 1,
hitSlow: 0.1,
spdMult: 1.13,
speed: 100
}, {
id: 8,
type: 0,
age: 2,
name: "stick",
desc: "great for gathering but very weak",
src: "stick_1",
length: 140,
width: 140,
xOff: 3,
yOff: 24,
dmg: 1,
spdMult: 1,
range: 70,
gather: 7,
speed: 400
}, {
id: 9,
type: 1,
age: 6,
name: "hunting bow",
desc: "bow used for ranged combat and hunting",
src: "bow_1",
req: ["wood", 4],
length: 120,
width: 120,
xOff: -6,
yOff: 0,
Pdmg: 25,
projectile: 0,
spdMult: 0.75,
speed: 600
}, {
id: 10,
type: 1,
age: 6,
name: "great hammer",
desc: "hammer used for destroying structures",
src: "great_hammer_1",
length: 140,
width: 140,
xOff: -9,
yOff: 25,
dmg: 10,
Pdmg: 10,
spdMult: 0.88,
range: 75,
sDmg: 7.5,
gather: 1,
speed: 400
}, {
id: 11,
type: 1,
age: 6,
name: "wooden shield",
desc: "blocks projectiles and reduces melee damage",
src: "shield_1",
length: 120,
width: 120,
shield: 0.2,
xOff: 6,
yOff: 0,
Pdmg: 0,
spdMult: 0.7
}, {
id: 12,
type: 1,
age: 8,
pre: 9,
name: "crossbow",
desc: "deals more damage and has greater range",
src: "crossbow_1",
req: ["wood", 5],
aboveHand: true,
armS: 0.75,
length: 120,
width: 120,
xOff: -4,
yOff: 0,
Pdmg: 35,
projectile: 2,
spdMult: 0.7,
speed: 700
}, {
id: 13,
type: 1,
age: 9,
pre: 12,
name: "repeater crossbow",
desc: "high firerate crossbow with reduced damage",
src: "crossbow_2",
req: ["wood", 10],
aboveHand: true,
armS: 0.75,
length: 120,
width: 120,
xOff: -4,
yOff: 0,
Pdmg: 30,
projectile: 3,
spdMult: 0.7,
speed: 230
}, {
id: 14,
type: 1,
age: 6,
name: "mc grabby",
desc: "steals resources from enemies",
src: "grab_1",
length: 130,
width: 210,
xOff: -8,
yOff: 53,
dmg: 0,
Pdmg: 0,
steal: 250,
knock: 0.2,
spdMult: 1.05,
range: 125,
gather: 0,
speed: 700
}, {
id: 15,
type: 1,
age: 9,
pre: 12,
name: "musket",
desc: "slow firerate but high damage and range",
src: "musket_1",
req: ["stone", 10],
aboveHand: true,
rec: 0.35,
armS: 0.6,
hndS: 0.3,
hndD: 1.6,
length: 205,
width: 205,
xOff: 25,
yOff: 0,
Pdmg: 50,
projectile: 5,
hideProjectile: true,
spdMult: 0.6,
speed: 1500
}];
this.list = [{
group: this.groups[0],
name: "apple",
desc: "restores 20 health when consumed",
req: ["food", 10],
consume: function (doer) {
return doer.changeHealth(20, doer);
},
scale: 22,
holdOffset: 15,
healing: 20,
itemID: 0,
itemAID: 16,
}, {
age: 3,
group: this.groups[0],
name: "cookie",
desc: "restores 40 health when consumed",
req: ["food", 15],
consume: function (doer) {
return doer.changeHealth(40, doer);
},
scale: 27,
holdOffset: 15,
healing: 40,
itemID: 1,
itemAID: 17,
}, {
age: 7,
group: this.groups[0],
name: "cheese",
desc: "restores 30 health and another 50 over 5 seconds",
req: ["food", 25],
consume: function (doer) {
if (doer.changeHealth(30, doer) || doer.health < 100) {
doer.dmgOverTime.dmg = -10;
doer.dmgOverTime.doer = doer;
doer.dmgOverTime.time = 5;
return true;
}
return false;
},
scale: 27,
holdOffset: 15,
healing: 30,
itemID: 2,
itemAID: 18,
}, {
group: this.groups[1],
name: "wood wall",
desc: "provides protection for your village",
req: ["wood", 10],
projDmg: true,
health: 380,
scale: 50,
holdOffset: 20,
placeOffset: -5,
itemID: 3,
itemAID: 19,
}, {
age: 3,
group: this.groups[1],
name: "stone wall",
desc: "provides improved protection for your village",
req: ["stone", 25],
health: 900,
scale: 50,
holdOffset: 20,
placeOffset: -5,
itemID: 4,
itemAID: 20,
}, {
age: 7,
group: this.groups[1],
name: "castle wall",
desc: "provides powerful protection for your village",
req: ["stone", 35],
health: 1500,
scale: 52,
holdOffset: 20,
placeOffset: -5,
itemID: 5,
itemAID: 21,
}, {
group: this.groups[2],
name: "spikes",
desc: "damages enemies when they touch them",
req: ["wood", 20, "stone", 5],
health: 400,
dmg: 20,
scale: 49,
spritePadding: -23,
holdOffset: 8,
placeOffset: -5,
itemID: 6,
itemAID: 22,
}, {
age: 5,
group: this.groups[2],
name: "greater spikes",
desc: "damages enemies when they touch them",
req: ["wood", 30, "stone", 10],
health: 500,
dmg: 35,
scale: 52,
spritePadding: -23,
holdOffset: 8,
placeOffset: -5,
itemID: 7,
itemAID: 23,
}, {
age: 9,
group: this.groups[2],
name: "poison spikes",
desc: "poisons enemies when they touch them",
req: ["wood", 35, "stone", 15],
health: 600,
dmg: 30,
pDmg: 5,
scale: 52,
spritePadding: -23,
holdOffset: 8,
placeOffset: -5,
itemID: 8,
itemAID: 24,
}, {
age: 9,
group: this.groups[2],
name: "spinning spikes",
desc: "damages enemies when they touch them",
req: ["wood", 30, "stone", 20],
health: 500,
dmg: 45,
turnSpeed: 0.003,
scale: 52,
spritePadding: -23,
holdOffset: 8,
placeOffset: -5,
itemID: 9,
itemAID: 25,
}, {
group: this.groups[3],
name: "windmill",
desc: "generates gold over time",
req: ["wood", 50, "stone", 10],
health: 400,
pps: 1,
turnSpeed: 0.0016,
spritePadding: 25,
iconLineMult: 12,
scale: 45,
holdOffset: 20,
placeOffset: 5,
itemID: 10,
itemAID: 26,
}, {
age: 5,
group: this.groups[3],
name: "faster windmill",
desc: "generates more gold over time",
req: ["wood", 60, "stone", 20],
health: 500,
pps: 1.5,
turnSpeed: 0.0025,
spritePadding: 25,
iconLineMult: 12,
scale: 47,
holdOffset: 20,
placeOffset: 5,
itemID: 11,
itemAID: 27,
}, {
age: 8,
group: this.groups[3],
name: "power mill",
desc: "generates more gold over time",
req: ["wood", 100, "stone", 50],
health: 800,
pps: 2,
turnSpeed: 0.005,
spritePadding: 25,
iconLineMult: 12,
scale: 47,
holdOffset: 20,
placeOffset: 5,
itemID: 12,
itemAID: 28,
}, {
age: 5,
group: this.groups[4],
type: 2,
name: "mine",
desc: "allows you to mine stone",
req: ["wood", 20, "stone", 100],
iconLineMult: 12,
scale: 65,
holdOffset: 20,
placeOffset: 0,
itemID: 13,
itemAID: 29,
}, {
age: 5,
group: this.groups[11],
type: 0,
name: "sapling",
desc: "allows you to farm wood",
req: ["wood", 150],
iconLineMult: 12,
colDiv: 0.5,
scale: 110,
holdOffset: 50,
placeOffset: -15,
itemID: 14,
itemAID: 30,
}, {
age: 4,
group: this.groups[5],
name: "pit trap",
desc: "pit that traps enemies if they walk over it",
req: ["wood", 30, "stone", 30],
trap: true,
ignoreCollision: true,
hideFromenemies: true,
health: 500,
colDiv: 0.2,
scale: 50,
holdOffset: 20,
placeOffset: -5,
alpha: 0.6,
itemID: 15,
itemAID: 31,
}, {
age: 4,
group: this.groups[6],
name: "boost pad",
desc: "provides boost when stepped on",
req: ["stone", 20, "wood", 5],
ignoreCollision: true,
boostSpeed: 1.5,
health: 150,
colDiv: 0.7,
scale: 45,
holdOffset: 20,
placeOffset: -5,
itemID: 16,
itemAID: 32,
}, {
age: 7,
group: this.groups[7],
doUpdate: true,
name: "turret",
desc: "defensive structure that shoots at enemies",
req: ["wood", 200, "stone", 150],
health: 800,
projectile: 1,
shootRange: 700,
shootRate: 2200,
scale: 43,
holdOffset: 20,
placeOffset: -5,
itemID: 17,
itemAID: 33,
}, {
age: 7,
group: this.groups[8],
name: "platform",
desc: "platform to shoot over walls and cross over water",
req: ["wood", 20],
ignoreCollision: true,
zIndex: 1,
health: 300,
scale: 43,
holdOffset: 20,
placeOffset: -5,
itemID: 18,
itemAID: 34,
}, {
age: 7,
group: this.groups[9],
name: "healing pad",
desc: "standing on it will slowly heal you",
req: ["wood", 30, "food", 10],
ignoreCollision: true,
healCol: 15,
health: 400,
colDiv: 0.7,
scale: 45,
holdOffset: 20,
placeOffset: -5,
itemID: 19,
itemAID: 35,
}, {
age: 9,
group: this.groups[10],
name: "spawn pad",
desc: "you will spawn here when you die but it will dissapear",
req: ["wood", 100, "stone", 100],
health: 400,
ignoreCollision: true,
spawnPoint: true,
scale: 45,
holdOffset: 20,
placeOffset: -5,
itemID: 20,
itemAID: 36,
}, {
age: 7,
group: this.groups[12],
name: "blocker",
desc: "blocks building in radius",
req: ["wood", 30, "stone", 25],
ignoreCollision: true,
blocker: 300,
health: 400,
colDiv: 0.7,
scale: 45,
holdOffset: 20,
placeOffset: -5,
itemID: 21,
itemAID: 37,
}, {
age: 7,
group: this.groups[13],
name: "teleporter",
desc: "teleports you to a random point on the map",
req: ["wood", 60, "stone", 60],
ignoreCollision: true,
teleport: true,
health: 200,
colDiv: 0.7,
scale: 45,
holdOffset: 20,
placeOffset: -5,
itemID: 22,
itemAID: 38
}];
this.checkItem = {
index: function(id, myItems) {
return [0, 1, 2].includes(id) ? 0 :
[3, 4, 5].includes(id) ? 1 :
[6, 7, 8, 9].includes(id) ? 2 :
[10, 11, 12].includes(id) ? 3 :
[13, 14].includes(id) ? 5 :
[15, 16].includes(id) ? 4 :
[17, 18, 19, 21, 22].includes(id) ?
[13, 14].includes(myItems) ? 6 :
5 :
id == 20 ?
[13, 14].includes(myItems) ? 7 :
6 :
undefined;
}
}
for (let i = 0; i < this.list.length; ++i) {
this.list[i].id = i;
if (this.list[i].pre) this.list[i].pre = i - this.list[i].pre;
}
}
// projectiles
function Projectile(players, ais, objectManager, items, config, Utils, server) {
this.init = function (indx, x, y, dir, spd, dmg, rng, scl, owner) {
this.active = true;
this.tickActive = true;
this.indx = indx;
this.x = x;
this.y = y;
this.x2 = x;
this.y2 = y;
this.dir = dir;
this.skipMov = true;
this.speed = spd;
this.dmg = dmg;
this.scale = scl;
this.range = rng;
this.r2 = rng;
this.owner = owner;
};
this.accessories = [{
id: 12,
name: "Snowball",
price: 1000,
scale: 105,
xOff: 18,
desc: "no effect"
}, {
id: 9,
name: "Tree Cape",
price: 1000,
scale: 90,
desc: "no effect"
}, {
id: 10,
name: "Stone Cape",
price: 1000,
scale: 90,
desc: "no effect"
}, {
id: 3,
name: "Cookie Cape",
price: 1500,
scale: 90,
desc: "no effect"
}, {
id: 8,
name: "Cow Cape",
price: 2000,
scale: 90,
desc: "no effect"
}, {
id: 11,
name: "Monkey Tail",
price: 2000,
scale: 97,
xOff: 25,
desc: "Super speed but reduced damage",
spdMult: 1.35,
dmgMultO: 0.2
}, {
id: 17,
name: "Apple Basket",
price: 3000,
scale: 80,
xOff: 12,
desc: "slowly regenerates health over time",
healthRegen: 1
}, {
id: 6,
name: "Winter Cape",
price: 3000,
scale: 90,
desc: "no effect"
}, {
id: 4,
name: "Skull Cape",
price: 4000,
scale: 90,
desc: "no effect"
}, {
id: 5,
name: "Dash Cape",
price: 5000,
scale: 90,
desc: "no effect"
}, {
id: 2,
name: "Dragon Cape",
price: 6000,
scale: 90,
desc: "no effect"
}, {
id: 1,
name: "Super Cape",
price: 8000,
scale: 90,
desc: "no effect"
}, {
id: 7,
name: "Troll Cape",
price: 8000,
scale: 90,
desc: "no effect"
}, {
id: 14,
name: "Thorns",
price: 10000,
scale: 115,
xOff: 20,
desc: "no effect"
}, {
id: 15,
name: "Blockades",
price: 10000,
scale: 95,
xOff: 15,
desc: "no effect"
}, {
id: 20,
name: "Devils Tail",
price: 10000,
scale: 95,
xOff: 20,
desc: "no effect"
}, {
id: 16,
name: "Sawblade",
price: 12000,
scale: 90,
spin: true,
xOff: 0,
desc: "deal damage to players that damage you",
dmg: 0.15
}, {
id: 13,
name: "Angel Wings",
price: 15000,
scale: 138,
xOff: 22,
desc: "slowly regenerates health over time",
healthRegen: 3
}, {
id: 19,
name: "Shadow Wings",
price: 15000,
scale: 138,
xOff: 22,
desc: "increased movement speed",
spdMult: 1.1
}, {
id: 18,
name: "Blood Wings",
price: 20000,
scale: 178,
xOff: 26,
desc: "restores health when you deal damage",
healD: 0.2
}, {
id: 21,
name: "Corrupt X Wings",
price: 20000,
scale: 178,
xOff: 26,
desc: "deal damage to players that damage you",
dmg: 0.25
}];
};
// animals
function AiManager(ais, AI, players, items, objectManager, config, Utils,
scoreCallback, server) {
this.aiTypes = [{
id: 0,
src: "cow_1",
killScore: 150,
health: 500,
weightM: 0.8,
speed: 0.00095,
turnSpeed: 0.001,
scale: 72,
drop: ["food", 50]
}, {
id: 1,
src: "pig_1",
killScore: 200,
health: 800,
weightM: 0.6,
speed: 0.00085,
turnSpeed: 0.001,
scale: 72,
drop: ["food", 80]
}, {
id: 2,
name: "Bull",
src: "bull_2",
hostile: true,
dmg: 20,
killScore: 1000,
health: 1800,
weightM: 0.5,
speed: 0.00094,
turnSpeed: 0.00074,
scale: 78,
viewRange: 800,
chargePlayer: true,
drop: ["food", 100]
}, {
id: 3,
name: "Bully",
src: "bull_1",
hostile: true,
dmg: 20,
killScore: 2000,
health: 2800,
weightM: 0.45,
speed: 0.001,
turnSpeed: 0.0008,
scale: 90,
viewRange: 900,
chargePlayer: true,
drop: ["food", 400]
}, {
id: 4,
name: "Wolf",
src: "wolf_1",
hostile: true,
dmg: 8,
killScore: 500,
health: 300,
weightM: 0.45,
speed: 0.001,
turnSpeed: 0.002,
scale: 84,
viewRange: 800,
chargePlayer: true,
drop: ["food", 200]
}, {
id: 5,
name: "Quack",
src: "chicken_1",
dmg: 8,
killScore: 2000,
noTrap: true,
health: 300,
weightM: 0.2,
speed: 0.0018,
turnSpeed: 0.006,
scale: 70,
drop: ["food", 100]
}, {
id: 6,
name: "MOOSTAFA",
nameScale: 50,
src: "enemy",
hostile: true,
dontRun: true,
fixedSpawn: true,
spawnDelay: 60000,
noTrap: true,
colDmg: 100,
dmg: 40,
killScore: 8000,
health: 18000,
weightM: 0.4,
speed: 0.0007,
turnSpeed: 0.01,
scale: 80,
spriteMlt: 1.8,
leapForce: 0.9,
viewRange: 1000,
hitRange: 210,
hitDelay: 1000,
chargePlayer: true,
drop: ["food", 100]
}, {
id: 7,
name: "Treasure",
hostile: true,
nameScale: 35,
src: "crate_1",
fixedSpawn: true,
spawnDelay: 120000,
colDmg: 200,
killScore: 5000,
health: 20000,
weightM: 0.1,
speed: 0.0,
turnSpeed: 0.0,
scale: 70,
spriteMlt: 1.0
}, {
id: 8,
name: "MOOFIE",
src: "wolf_2",
hostile: true,
fixedSpawn: true,
dontRun: true,
hitScare: 4,
spawnDelay: 30000,
noTrap: true,
nameScale: 35,
dmg: 10,
colDmg: 100,
killScore: 3000,
health: 7000,
weightM: 0.45,
speed: 0.0015,
turnSpeed: 0.002,
scale: 90,
viewRange: 800,
chargePlayer: true,
drop: ["food", 1000]
}, {
id: 9,
name: "💀MOOFIE",
src: "wolf_2",
hostile: true,
fixedSpawn: true,
dontRun: true,
hitScare: 50,
spawnDelay: 60000,
noTrap: true,
nameScale: 35,
dmg: 12,
colDmg: 100,
killScore: 3000,
health: 9000,
weightM: 0.45,
speed: 0.0015,
turnSpeed: 0.0025,
scale: 94,
viewRange: 1440,
chargePlayer: true,
drop: ["food", 3000]
}, {
id: 10,
name: "💀Wolf",
src: "wolf_1",
hostile: true,
fixedSpawn: true,
dontRun: true,
hitScare: 50,
spawnDelay: 30000,
nameScale: 35,
dmg: 10,
killScore: 700,
health: 500,
weightM: 0.45,
speed: 0.00115,
turnSpeed: 0.0025,
scale: 88,
viewRange: 1440,
chargePlayer: true,
drop: ["food", 400]
}, {
id: 11,
name: "💀Bully",
src: "bull_1",
hostile: true,
fixedSpawn: true,
dontRun: true,
hitScare: 50,
spawnDelay: 100000,
nameScale: 35,
dmg: 20,
killScore: 5000,
health: 5000,
weightM: 0.45,
speed: 0.0015,
turnSpeed: 0.0025,
scale: 94,
viewRange: 1440,
chargePlayer: true,
drop: ["food", 800]
}];
};
function AI(sid, objectManager, players, items, Utils, config, scoreCallback,
server) {
this.sid = sid;
this.isAI = true;
this.nameIndex = Utils.randInt(0, config.cowNames.length - 1);
this.init = function (x, y, dir, index, data) {
this.x = x;
this.y = y;
this.startX = data.fixedSpawn ? x : null;
this.startY = data.fixedSpawn ? y : null;
this.xVel = 0;
this.yVel = 0;
this.zIndex = 0;
this.dir = dir;
this.dirPlus = 0;
this.index = index;
this.src = data.src;
if (data.name) this.name = data.name;
this.weightM = data.weightM;
this.speed = data.speed;
this.killScore = data.killScore;
this.turnSpeed = data.turnSpeed;
this.scale = data.scale;
this.maxHealth = data.health;
this.leapForce = data.leapForce;
this.health = this.maxHealth;
this.chargePlayer = data.chargePlayer;
this.viewRange = data.viewRange;
this.drop = data.drop;
this.dmg = data.dmg;
this.hostile = data.hostile;
this.dontRun = data.dontRun;
this.hitRange = data.hitRange;
this.hitDelay = data.hitDelay;
this.hitScare = data.hitScare;
this.spriteMlt = data.spriteMlt;
this.nameScale = data.nameScale;
this.colDmg = data.colDmg;
this.noTrap = data.noTrap;
this.spawnDelay = data.spawnDelay;
this.hitWait = 0;
this.waitCount = 1000;
this.moveCount = 0;
this.targetDir = 0;
this.active = true;
this.alive = true;
this.runFrom = null;
this.chargeTarget = null;
this.dmgOverTime = {};
};
let tmpRatio = 0;
let animIndex = 0;
this.animate = function (delta) {
if (this.animTime > 0) {
this.animTime -= delta;
if (this.animTime <= 0) {
this.animTime = 0;
this.dirPlus = 0;
tmpRatio = 0;
animIndex = 0;
} else {
if (animIndex == 0) {
tmpRatio += delta / (this.animSpeed * config.hitReturnRatio);
this.dirPlus = Utils.lerp(0, this.targetAngle, Math.min(1,
tmpRatio));
if (tmpRatio >= 1) {
tmpRatio = 1;
animIndex = 1;
}
} else {
tmpRatio -= delta / (this.animSpeed * (1 -
config.hitReturnRatio));
this.dirPlus = Utils.lerp(0, this.targetAngle, Math.max(0,
tmpRatio));
}
}
}
};
this.startAnim = function () {
this.animTime = this.animSpeed = 600;
this.targetAngle = Math.PI * 0.8;
tmpRatio = 0;
animIndex = 0;
};
};
// players
function Player(id, sid, config, Utils, projectileManager, objectManager, players,
ais, items, hats, accessories, server, scoreCallback, iconCallback) {
this.id = id;
this.sid = sid;
this.tmpScore = 0;
this.team = null;
this.latestSkin = 0;
this.oldSkinIndex = 0;
this.skinIndex = 0;
this.latestTail = 0;
this.oldTailIndex = 0;
this.tailIndex = 0;
this.hitTime = 0;
this.lastHit = 0;
this.tails = {};
for (let i = 0; i < accessories.length; ++i) {
if (accessories[i].price <= 0) this.tails[accessories[i].id] = 1;
}
this.skins = {};
for (let i = 0; i < hats.length; ++i) {
if (hats[i].price <= 0) this.skins[hats[i].id] = 1;
}
this.points = 0;
this.dt = 0;
this.hidden = false;
this.itemCounts = {};
this.isPlayer = true;
this.pps = 0;
this.moveDir = undefined;
this.skinRot = 0;
this.lastPing = 0;
this.iconIndex = 0;
this.skinColor = 0;
this.dist2 = 0;
this.aim2 = 0;
this.maxSpeed = 1;
this.chat = {
message: null,
count: 0
};
this.backupNobull = true;
this.cAngle = 0;
};
this.update = function(delta) {
if (this.active) {
let gear = {
skin: findID(hats, this.skinIndex),
tail: findID(accessories, this.tailIndex)
}
let spdMult = ((this.buildIndex >= 0) ? 0.5 : 1) *
(items.weapons[this.weaponIndex].spdMult || 1) * (gear.skin ? (gear.skin.spdMult ||
1) : 1) * (gear.tail ? (gear.tail.spdMult || 1) : 1) * (this.y <=
config.snowBiomeTop ? ((gear.skin && gear.skin.coldM) ? 1 : config.snowSpeed) : 1)
* this.slowMult;
this.maxSpeed = spdMult;
}
};
this.buildItemPosition = function(e, dir = (this.d2 || this.dir)) {
var mathCOS = Math.cos;
var mathSIN = Math.sin;
var t = this.scale + e.scale + (e.placeOffset || 0),
i = (this.x2 || this.x) + t * mathCOS(dir),
n = (this.y2 || this.x) + t * mathSIN(dir);
return {
x: i,
y: n
};
}
let tmpRatio = 0;
let animIndex = 0;
this.animate = function(delta) {
if (this.animTime > 0) {
this.animTime -= delta;
if (this.animTime <= 0) {
this.animTime = 0;
this.dirPlus = 0;
tmpRatio = 0;
animIndex = 0;
} else {
if (animIndex == 0) {
tmpRatio += delta / (this.animSpeed * config.hitReturnRatio);
this.dirPlus = Utils.lerp(0, this.targetAngle, Math.min(1,
tmpRatio));
if (tmpRatio >= 1) {
tmpRatio = 1;
animIndex = 1;
}
} else {
tmpRatio -= delta / (this.animSpeed * (1-
config.hitReturnRatio));
this.dirPlus = Utils.lerp(0, this.targetAngle, Math.max(0,
tmpRatio));
}
}
}
};
function soldierMult() {
return player.latestSkin == 6 ? 0.75 : 1;
}
function healthBased() {
if (player.health == 100) return 0;
if ((player.skinIndex != 45 && player.skinIndex != 56)) {
return Math.ceil((100 - player.health) /
items.list[player.items[0]].healing);
}
return 0;
}
function healer() {
for (let i = 0; i < healthBased(); i++) {
place(0, getAttackDir());
}
}
function heal(health) {
for (let i = ceil((100 - health) / items.list[player.items[0]].healing); i--;)
{
place(0, getAttackDir());
};
}
function healer33() {
for (let i = 0; i < healthBased(); i++) {
place(0, getAttackDir());
}
}
function healer1() {
place(0, getAttackDir());
return Math.ceil((100 - player.health) / items.list[player.items[0]].healing);
}
function noshameheal() {
place(0, getAttackDir());
if (player.shameCount >= 5) {
place(0, getAttackDir());
healer33();
}else{
if (player.shameCount <= 4 && player.skinIndex != 6 && player.skinIndex !=
22) {
healer33();
equipItem(6, 0);
}else{
if (player.shameCount >= 5 && player.skinIndex != 6 && player.skinIndex
!= 22) {
return Math.ceil((100 - player.health) /
items.list[player.items[0]].healing);
healer33();
}
}
}
}
function antiSyncHealing() {
//io.send('6', 'sync detect test');
asura.antiSync = true;
let healAnti = setInterval(() => {
if (player.shameCount < 5) {
place(0, getAttackDir());
}
}, 75);
setTimeout(() => {
clearInterval(healAnti);
setTimeout(() => {
asura.antiSync = false;
}, game.tickRate);
}, game.tickRate);
}
if (array1q == 1) {//lowest angle of the not allowed zone in the first quadrant
return true
} else {//is not in between
return false
}
}
}
}
}
function collisionDetection(obj1, obj2, scale) {
return Math.sqrt((obj1.x - obj2.x) ** 2 + (obj1.y - obj2.y) ** 2) < scale;
}
let potSpikeKB = {
x: null,
y: null
}
let isBullTicking = false;
function angleDist(angle1, angle2) {
if (angle1 < 0) angle1 += Math.PI * 2;
if (angle2 < 0) angle2 += Math.PI * 2;
return Math.abs(angle1 - angle2);
}
class Asuramaru {
constructor(Utils, items) {
// autobreak stuff
this.antiTrapped = false;
this.info = {};
this.notFast = function() {
return player.weapons[1] == 10 && ((this.info.health >
items.weapons[player.weapons[0]].dmg) || player.weapons[0] == 5);
}
// Asuramaru properties
this.playerTrapped = false;
this.dist = 0;
this.aim = 0;
this.reloaded = false;
this.waitHit = 0;
this.autoAim = false;
this.revAim = false;
this.ageInsta = true;
this.bullTick = 0;
this.antiSync = false;
this.lastDir = 0;
this.autoPush = false;
this.FPS = 0;
this.potentialDmg = [];
this.objHit = {
active: false,
x: 0,
y: 0,
scale: 0,
weapon: undefined,
color: null,
stop: null,
};
this.spikes = {
info: [],
breakSpike: false,
angle: 0,
};
this.movementDirs = [];
this.preplaceInfo = [];
//heal shit
this.lastHealTick = -2; //enable first healing
// automill stuff
this.autoMill = {
x: undefined,
y: undefined,
size: function (dicksize) {
return dicksize * 1.45;
},
dist: function (dicksize) {
return dicksize * 1.8;
},
active: false,
count: 0,
};
this.oldXY = {
x: 0,
y: 0,
};
// autoplace
this.mahirushiina = [];
this.place = [];
this.placeQueue = [];
}
safePrimary(tmpObj) {
return [0, 8].includes(tmpObj.primaryIndex);
}
safeSecondary(tmpObj) {
return [10, 11, 14].includes(tmpObj.secondaryIndex);
}
checkSpikeTick = function() {
try {
if (![3, 4, 5].includes(near.primaryIndex)) return false;
if ((asura.autoPush) ? false : near.primaryIndex == undefined ? true :
(near.reloads[near.primaryIndex] > game.tickRate)) return false;
if (near.dist2 <= items.weapons[near.primaryIndex || 5].range +
(near.scale * 1.8)) {
let item = items.list[9];
let tmpS = near.scale + item.scale + (item.placeOffset || 0);
let danger = 0;
let counts = {
attempts: 0,
block: `unblocked`
};
for (let i = -1; i <= 1; i += 1/10) {
counts.attempts++;
let relAim = Utils.getDirect(player, near, 2, 2) + i;
let tmpX = near.x2 + tmpS * Math.cos(relAim);
let tmpY = near.y2 + tmpS * Math.sin(relAim);
let cantPlace = gameObjects.find((tmp) => tmp.active &&
Utils.getDistance(tmpX, tmpY, tmp.x, tmp.y) < item.scale + (tmp.blocker ?
tmp.blocker : tmp.getScale(0.6, tmp.isItem)));
if (cantPlace) continue;
if (tmpY >= config.mapScale / 2 - config.riverWidth / 2 && tmpY
<= config.mapScale / 2 + config.riverWidth / 2) continue;
danger++;
counts.block = `blocked`;
break;
}
if (danger) {
return true;
}
}
} catch (err) {
return null;
}
return false;
}
getDist(e, t) {
try {
return Math.hypot((t.y2 || t.y) - (e.y2 || e.y), (t.x2 || t.x) - (e.x2
|| e.x));
} catch (e) {
return Infinity;
}
}
nigger = function(id, first = -(Math.PI / 2), repeat = (Math.PI / 2), plus =
(Math.PI / 18), radian, replacer, yaboi) {
try {
let item = items.list[player.items[id]];
let tmpS = player.scale + item.scale + (item.placeOffset || 0);
let counts = {
attempts: 0,
placed: 0
};
let tmpObjects = [];
gameObjects.forEach((p) => {
tmpObjects.push({
x: p.x,
y: p.y,
active: p.active,
blocker: p.blocker,
scale: p.scale,
isItem: p.isItem,
type: p.type,
colDiv: p.colDiv,
getScale: function(sM, ig) {
sM = sM||1;
return this.scale * ((this.isItem||this.type==2||
this.type==3||this.type==4) ? 1:(0.6*sM)) * (ig?1:this.colDiv);
},
});
});
for (let i = first; i < repeat; i += plus) {
counts.attempts++;
let relAim = radian + i;
let tmpX = player.x2 + tmpS * Math.cos(relAim);
let tmpY = player.y2 + tmpS * Math.sin(relAim);
let cantPlace = tmpObjects.find((tmp) => tmp.active &&
Utils.getDistance(tmpX, tmpY, tmp.x, tmp.y) < item.scale + (tmp.blocker ?
tmp.blocker : tmp.getScale(0.6, tmp.isItem)));
if (cantPlace) continue;
if (item.id != 18 && tmpY >= config.mapScale / 2 -
config.riverWidth / 2 && tmpY <= config.mapScale / 2 + config.riverWidth / 2)
continue;
if ((!replacer && yaboi)) {
if (yaboi.inTrap) {
if (Utils.getAngleDist(near.aim2 + Math.PI, relAim +
Math.PI) <= Math.PI) {
place(2, relAim, 1);
} else {
player.items[4] == 15 && place(4, relAim, 1);
}
} else {
if (Utils.getAngleDist(near.aim2, relAim) <=
config.gatherAngle / 1.5) {
place(2, relAim, 1);
} else {
player.items[4] == 15 && place(4, relAim, 1);
}
}
} else {
place(id, relAim, 1);
}
tmpObjects.push({
x: tmpX,
y: tmpY,
active: true,
blocker: item.blocker,
scale: item.scale,
isItem: true,
type: null,
colDiv: item.colDiv,
getScale: function() {
return this.scale;
},
});
if (Utils.getAngleDist(near.aim2, relAim) <= 1) {
counts.placed++;
}
}
if (counts.placed > 0 && replacer && item.dmg) {
if (near.dist2 <= items.weapons[player.weapons[0]].range +
(player.scale * 1.8)) {
instaC.canSpikeTick = true;
}
}
} catch (err) {
}
};
protect = function(aim) {
if (player.items[4] && near.dist2 <= 600) {
if(this.getDist(near, player) > this.getDist(near, this.info)) {
//behind u
if (near.dist2 <= 100) {
this.nigger(2, -(Math.PI / 2), (Math.PI / 2), (Math.PI / 18),
aim + Math.PI);
this.antiTrapped = true;
}
} else if(this.getDist(near, this.info) > this.getDist(near, player)) {
//infront of u
if (player.items[4]) {
this.nigger(2, -(Math.PI / 2), (Math.PI / 2), (Math.PI / 18),
aim + Math.PI);
this.antiTrapped = true;
}
} else {
if (near.dist2 <= 100) {
this.nigger(2, -(Math.PI / 2), (Math.PI / 2), (Math.PI / 18),
aim + Math.PI);
this.antiTrapped = true;
} else {
this.nigger(4, -(Math.PI / 2), (Math.PI / 2), (Math.PI / 18),
aim + Math.PI);
this.antiTrapped = true;
}
}
this.antiTrapped = true;
}
};
// angle scanning codes
createTempObject() {
return { x: 0, y: 0, scale: 0 }
};
getPosFromAngle(item, angle) {
let x, y, scale;
item = items.list[item];
x = player.x2 + (item.scale + player.scale + (item.placeOffset || 0)) *
Math.cos(angle);
y = player.y2 + (item.scale + player.scale + (item.placeOffset || 0)) *
Math.sin(angle);
scale = item.scale;
return {
x,
y,
scale
};
};
manageAngles(angles) {
angles.sort((a, b) => a[0] - b[0]);
let mergedAngles = [angles[0]];
for (let i = 1; i < angles.length; i++) {
let last = mergedAngles[mergedAngles.length - 1];
if (last[1] >= angles[i][0]) {
last[1] = Math.max(last[1], angles[i][1]);
} else {
mergedAngles.push(angles[i]);
}
}
return mergedAngles;
}
makeAngles(building, type) {
let buildings = building.filter(obj => Utils.getDist(obj, player, 0, 2) <=
player.scale + items.list[type].scale + obj.scale + 50 && obj.active);
let allAngles = [], scale, offset = player.scale + items.list[type].scale +
(items.list[type].placeOffset || 0);
for (let i = 0; i < buildings.length; i++) {
let scale
if (!buildings[i].isItem) {
if ((buildings[i].scale != 80 && buildings[i].scale != 85 &&
buildings[i].scale != 90 || buildings[i].type == 1)) {
scale = buildings[i].scale * 0.40
} else {
scale = buildings[i].scale
}
} else {
scale = buildings[i].scale
}
let angles = [], dist = (items.list[type].scale + scale + 1), dPTB =
Utils.getDist(buildings[i], player, 0, 2), cosLaw;
if (dPTB > dist + offset) {
cosLaw = Math.acos(((Math.pow(offset, 2) + Math.pow(dist, 2)) -
Math.pow(dPTB, 2)) / (2 * dist * offset))
cosLaw = Math.asin((dist * Math.sin(cosLaw)) / dPTB)
} else {
cosLaw = Math.acos(((Math.pow(offset, 2) + Math.pow(dPTB, 2)) -
Math.pow(dist, 2)) / (2 * dPTB * offset))
}
let aPTB = Math.atan2(buildings[i].y - player.y2, buildings[i].x -
player.x2)
let ang1 = (aPTB - cosLaw), ang2 = (aPTB + cosLaw)
if (!isNaN(cosLaw)) {
angles.push(ang1)
angles.push(ang2)
angles.push(buildings[i])
}
allAngles.push(angles)
}
}
if (!allAngles.length) {
allAngles = [0, 0.0001]
}
for (let i = 0; i < allAngles.length; i++) {
if (allAngles != false) {
if (!secondaryCheck(type, allAngles[i][0]) || !secondaryCheck(type,
allAngles[i][1])) {
allAngles = false
}
}
}
return allAngles
}
findNearestAngle(angles, targetAngle) {
let closestAngle = null;
let closestDist = Infinity;
for (let i = 0; i < angles.length; i++) {
let angle1 = angles[i][0];
let angle2 = angles[i][1];
let dist1 = Math.min(Math.abs(angle1 - targetAngle), 2 * Math.PI -
Math.abs(angle1 - targetAngle));
let dist2 = Math.min(Math.abs(angle2 - targetAngle), 2 * Math.PI -
Math.abs(angle2 - targetAngle));
if (dist1 < closestDist) {
closestDist = dist1;
closestAngle = angle1;
}
if (dist2 < closestDist) {
closestDist = dist2;
closestAngle = angle2;
}
}
return closestAngle;
}
calculateAngles(initAngleRad) {
let angles = [initAngleRad];
for (let i = 1; i < 4; i++) {
let angleOffset = (Math.PI / 2) * i;
let newAngle = (initAngleRad + angleOffset) % (2 * Math.PI);
angles.push(newAngle);
}
return angles;
}
calculateAngle(baseAngleRad, numOffsets = 1) {
numOffsets = Math.min(numOffsets, 3);
return Array.from({ length: numOffsets + 1 }, (_, i) => {
let angleOffset = (Math.PI / 2) * i;
return (baseAngleRad + angleOffset) % (2 * Math.PI);
});
}
refineAngles(type) {
const clampAngle = function(angle) {
while (angle < 0) {
angle += 2 * Math.PI;
}
while (angle >= 2 * Math.PI) {
angle -= 2 * Math.PI;
}
return angle;
}
let buildings = gameObjects.sort((a, b) => Math.hypot(player.y2 - a.y,
player.x2 - a.x) - Math.hypot(player.y2 - b.y, player.x2 - b.x));
let buildingsInRange = buildings.filter(obj => Utils.getDist(obj, player,
0, 2) <= player.scale + items.list[type].scale + obj.scale + 50 && obj.active);
let allAngles = [];
let offset = player.scale + items.list[type].scale +
(items.list[type].placeOffset || 0);
buildingsInRange.forEach(building => {
let scale = building.isItem ? building.scale : building.scale !== 80 &&
building.scale !== 85 && building.scale !== 90 || building.type === 1 ?
building.scale * 0.40 : building.scale;
let dist = items.list[type].scale + scale + 1;
let dPTB = Utils.getDist(building, player, 0, 2);
let cosLaw = (dPTB > dist + offset) ? Math.asin((dist *
Math.sin(Math.acos((offset ** 2 + dist ** 2 - dPTB ** 2) / (2 * dist * offset)))) /
dPTB) :
Math.acos((offset ** 2 + dPTB ** 2 - dist ** 2) / (2 * dPTB * offset));
let aPTB = Math.atan2(building.y - player.y2, building.x - player.x2);
let ang1 = clampAngle(aPTB - cosLaw);
let ang2 = clampAngle(aPTB + cosLaw);
// we sort angles based on proximity so we can avoid overlapping
if (!isNaN(ang1) && !isNaN(ang2)) {
allAngles.push([ang1, ang2]);
}
});
// now it should return atleast 1 valid angle
if (allAngles.length > 0) {
return allAngles.flatMap(anglePair => anglePair).filter(angle => typeof
angle === 'number');
} else {
return this.calculateAngles(Utils.getAngle(near, player, 2, 2)); //
just incase it allAngles cant find a valid angle
}
}
getClosestAngle(anglesArray, targetDirection) {
if (!anglesArray.length) return targetDirection;
let closestAngle = anglesArray.reduce((closest, current) => {
return Math.abs(current - targetDirection) < Math.abs(closest -
targetDirection) ? current : closest;
});
return closestAngle;
};
// placer codes
autoPlace = function() {
if (io.secPacket >= 75 || !getEl("autoplace").checked) return;
let enemyTrapped = gameObjects
.filter(tmp => tmp.trap && tmp.active && tmp.isTeamObject(player) &&
Utils.getDist(tmp, near, 0, 2) <= (near.scale + tmp.getScale() + 15))
.sort((a, b) => Utils.getDist(a, near, 0, 2) - Utils.getDist(b, near, 0,
2))[0];
const getDistance = (src, dest, srcType, destType) => {
let srcPos = {
x: srcType === 0 ? src.x : srcType === 1 ? src.x1 : srcType === 2 ?
src.x2 : srcType === 3 ? src.x3 : undefined,
y: srcType === 0 ? src.y : srcType === 1 ? src.y1 : srcType === 2 ?
src.y2 : srcType === 3 ? src.y3 : undefined
};
let destPos = {
x: destType === 0 ? dest.x : destType === 1 ? dest.x1 : destType
=== 2 ? dest.x2 : destType === 3 ? dest.x3 : undefined,
y: destType === 0 ? dest.y : destType === 1 ? dest.y1 : destType
=== 2 ? dest.y2 : destType === 3 ? dest.y3 : undefined
};
return Math.sqrt((destPos.x - srcPos.x) ** 2 + (destPos.y - srcPos.y)
** 2);
};
let buildings = gameObjects.sort((a, b) => Math.hypot(player.y2 - a.y,
player.x2 - a.x) - Math.hypot(player.y2 - b.y, player.x2 - b.x));
let nearbyBuildings = buildings.filter(obj => fgdo(obj, player) < 250);
let nearestTrap = gameObjects.filter(obj => obj.trap && obj.active &&
obj.owner.sid === player.sid && getDistance(obj, near, 0, 2) <= (player.scale +
obj.getScale() + 5))
.sort((a, b) => getDistance(a, near, 0, 2) - getDistance(b, near, 0, 2))
[0];
let dir = Math.atan2(near.y - player.y2, near.x - player.x2);
let placements = [];
let angles = [];
let nEIT = false; // nearest enemy in trap
// better angles
let spikeAngles = player.items[2] ? this.refineAngles(2) : [];
let trapAngles = player.items[4] ? this.refineAngles(4) : [];
// angle codes 1
// ⬇⬇⬇⬇⬇⬇⬇⬇⬇
const PIAA = (itemId, baseX, baseY, baseScale, angles) => {
return angles.map(angle => {
return {
x: baseX + Math.cos(angle) * (baseScale +
items.list[itemId].scale + (items.list[itemId].placeOffset || 0)),
y: baseY + Math.sin(angle) * (baseScale +
items.list[itemId].scale + (items.list[itemId].placeOffset || 0)),
scale: items.list[itemId].scale / 3,
isItem: true,
active: true,
};
});
};
const scanForAngles = (angle, enemyTrap) => {
let alternativeAngles = [];
let angleStep = Math.PI / 4;
for (let i = -2; i <= 2; i++) {
let alternativeAngle = angle + i * angleStep;
if (alternativeAngle >= 0 && alternativeAngle <= 2 * Math.PI) {
let pos = player.buildItemPosition(items.list[player.items[2]],
Utils.getDirect(angle, player, 0, 2));
if (objectManager.checkItemLocation(pos.x, pos.y,
items.list[player.items[2]].scale, 0, player.items[2], false, player)) {
alternativeAngles.push(alternativeAngle);
}
}
}
return alternativeAngles;
};
const PI = (objType, angles, processedAngles = new Set()) => {
angles.forEach(angle => {
let angleKey = angle.toFixed(5);
if (processedAngles.has(angleKey)) return;
processedAngles.add(angleKey);
let whatever = objType === 2 ? "spike" : objType === 4 ? "trap" :
null;
if (!whatever) {
return;
}
if (trapPredict.length > 0) {
let enemyTrap = predictions.enemyTrap.find(trap =>
Utils.getDist(trap, player.buildItemPosition(items.list[objType], angle)) <= 50 +
items.list[objType].scale);
if (enemyTrap) {
let alternativeAngles = scanForAngles(angle, enemyTrap);
if (alternativeAngles.length > 0) {
PI(objType, alternativeAngles, processedAngles);
}
} else {
let pos = player.buildItemPosition(items.list[objType],
angle);
if (objectManager.checkItemLocation(pos.x, pos.y,
items.list[objType].scale, 0, objType, false, player)) {
placements.push(...PIAA(objType, player.x2, player.y2,
player.scale, [angle]));
}
}
}
});
};
// start of placing logic
if (this.mahirushiina.length > 0) {
this.mahirushiina.forEach(p => {
let baseAngles = this.refineAngles(2);
PI("spike", baseAngles);
this.place.push(...baseAngles.map(angle => ["spike", angle]));
});
this.mahirushiina = [];
} else {
if (placements.length > 0) {
placements.forEach(p => {
let newObj = { ...p };
nearbyBuildings.push(newObj);
});
spikeAngles = player.items[2] ? this.refineAngles(2) : [];
}
if (nearestTrap && fgdo(player, near) < 200) {
if (spikeAngles.length > 0) {
let closestAngle = spikeAngles.reduce((prev, curr) => {
return Math.abs(curr - nearestTrap) < Math.abs(prev -
nearestTrap) ? curr : prev;
});
if (closestAngle) {
let bestAngle = (dir - closestAngle[0]) < (dir -
closestAngle[1]) ? closestAngle[0] : closestAngle[1];
let objPos = {
x: player.x2 + Math.cos(bestAngle) * (player.scale +
items.list[player.items[2]].scale + (items.list[player.items[2]].placeOffset ||
0)),
y: player.y2 + Math.sin(bestAngle) * (player.scale +
items.list[player.items[2]].scale + (items.list[player.items[2]].placeOffset || 0))
};
if (Utils.getDist(near, player, 2, 2) <= player.scale * 2 +
items.weapons[player.weaponIndex].range) {
let baseAngles = this.refineAngles(2);
let offset = -(Math.PI / 4);
this.place.push(...baseAngles.map(angle => ["spike",
angle + offset]));
}
}
} else {
console.warn("no spike angles.");
}
}
let enemyTrapped = objects.filter(tmp => tmp.trap && tmp.active &&
tmp.isTeamObject(player) && Utils.getDist(tmp, near, 0, 2) <= (near.scale +
tmp.getScale() + 15)).sort(function(a, b) {
return Utils.getDist(a, near, 0, 2) - Utils.getDist(b, near, 0, 2);
})[0];
if (enemyTrapped) {
angles = this.calculateAngles(Utils.getAngle(enemyTrapped, player,
0, 2));
nEIT = true;
} else {
nEIT = false
angles = this.calculateAngles(Utils.getAngle(near, player, 2, 2));
}
// lets prioritise spike placements
// ⬇⬇⬇⬇⬇⬇⬇⬇⬇
if (Utils.getDist(near, player, 2, 2) <= player.scale * 2 +
items.weapons[player.weaponIndex].range && !nEIT) {
let offset = -(Math.PI / 4);
angles.forEach((angle, index) => {
if (index === 2 || index === 3) {
this.place.push(["spike", angle + offset]);
this.place.push(["trap", angle + offset + Math.PI]);
}
});
}
angles.forEach((angle, index) => {
let object = { x: 0, y: 0, scale: 0 };
Object.assign(object, this.getPosFromAngle(player.items[2],
angle));
if (Utils.getDist(object, player, 0, 2) <=
items.weapons[player.weaponIndex].range * items.weapons[player.weaponIndex].knock +
object.scale) {
addMenuChText("Debug", `Kbing Enemy To Spike`, "green");
this.place.push(["spike", angle]);
//^^^^^^^^^^^^^^^
// place spike where they can be kbed to other spikes
}
});
// trap placement logic
if (fgdo(player, near) < 400) {
let posTrapAngle = trapAngles.filter(angle => !inBetween(dir,
angle));
if (posTrapAngle.length > 0 && this.place.length < 3 && !
(Utils.getDist(near, player, 2, 2) <= player.scale * 2 +
items.weapons[player.weaponIndex].range)) {
let baseAngles = this.refineAngles(4);
let TATP = baseAngles.length >= 4 ? baseAngles.slice(0, 4) :
baseAngles; // trap angle to place
PI("trap", TATP);
this.place.push(...TATP.map(angle => ["trap", angle]));
}
}
if (fgdo(player, near) < 400) {
let posTrapAngle = trapAngles.filter(angle => !inBetween(dir,
angle));
if (posTrapAngle.length > 0 && this.place.length < 3) {
let baseAngles = this.refineAngles(4);
let TATP = baseAngles.length >= 4 ? baseAngles.slice(0, 4) :
baseAngles; // trap angle to place
PI("trap", TATP);
this.place.push(...TATP.map(angle => ["trap", angle]));
}
}
}
};
getPosFromAngle(item, angle) {
let x, y, scale;
item = items.list[item];
x = player.x2 + (item.scale + player.scale + (item.placeOffset || 0)) *
cos(angle);
y = player.y2 + (item.scale + player.scale + (item.placeOffset || 0)) *
sin(angle);
scale = item.scale;
return {
x,
y,
scale
};
}
healInTrap(dick) {
let dmg = player.health - Math.abs(dick)
if (tmpObj == player) {
if (abs(asura.lastHealTick - game.tick) >= 2) {
asura.lastHealTick = game.tick;
if (player.health <= 49) {
heal()
} else setTimeout(() => {
heal(dmg);
}, 1e3 / 9);
} else {
game.tickBase(() => {
heal(dmg);
}, abs(asura.lastHealTick - game.tick))
};
}
}
checkIfCanInsta(nobull) {
if (!near) return false;
let mppd = 0; //max player potential damage
if (player.weapons[0] != undefined && player.reloads[player.weapons[0]] ==
0) {
mppd += items.weapons[player.weapons[0]].dmg * (nobull ? 1 : 1.5) *
sortWeaponVariant(near.weaponVariant);
}
if (player.weapons[1] != undefined && player.reloads[player.weapons[1]] ==
0) {
mppd += items.weapons[player.weapons[1]].Pdmg;
}
if (player.skins[53] && player.reloads[53] == 0 && near.skinIndex != 22) {
mppd += 25;
}
mppd *= near.skinIndex == 6 ? 0.75 : 1;
if (near.health - Math.round(mppd) <= 0 || near.shameCount >= 5) {
return true;
}
return false;
}
updateTick = function(data) {
//handleTick()
timesincetick = Date.now();
game.tick++;
enemies = [];
nears = [];
near = [];
this.spikes.breakSpike = false;
game.tickSpeed = performance.now() - game.lastTick;
game.lastTick = performance.now();
//lastTick = Date.now() - window.pingTime;
postTickTime = Date.now();
players.forEach((tmp) => {
tmp.forcePos = !tmp.visible;
tmp.visible = false;
});
for (let i = 0; i < data.length;) {
tmpObj = findPlayerBySID(data[i]);
if (tmpObj) {
tmpObj.t1 = (tmpObj.t2 === undefined) ? game.lastTick : tmpObj.t2;
tmpObj.t2 = game.lastTick;
tmpObj.x1 = tmpObj.x;
tmpObj.y1 = tmpObj.y;
tmpObj.lastX = tmpObj.x2;
tmpObj.lastY = tmpObj.y2;
tmpObj.x2 = data[i + 1];
tmpObj.y2 = data[i + 2];
tmpObj.x3 = tmpObj.x2 + (tmpObj.x2 - tmpObj.lastX);
tmpObj.y3 = tmpObj.y2 + (tmpObj.y2 - tmpObj.lastY);
tmpObj.d1 = (tmpObj.d2 === undefined) ? data[i + 3] : tmpObj.d2;
tmpObj.d2 = data[i + 3];
tmpObj.dt = 0;
tmpObj.buildIndex = data[i + 4];
tmpObj.weaponIndex = data[i + 5];
tmpObj.weaponVariant = data[i + 6];
tmpObj.team = data[i + 7];
tmpObj.isLeader = data[i + 8];
tmpObj.oldSkinIndex = tmpObj.skinIndex;
tmpObj.oldTailIndex = tmpObj.tailIndex;
tmpObj.skinIndex = data[i + 9];
tmpObj.tailIndex = data[i + 10];
tmpObj.iconIndex = data[i + 11];
tmpObj.zIndex = data[i + 12];
tmpObj.visible = true;
tmpObj.update(game.tickSpeed);
tmpObj.dist2 = Utils.getDist(tmpObj, player, 2, 2);
tmpObj.aim2 = Utils.getDirect(tmpObj, player, 2, 2);
tmpObj.dist3 = Utils.getDist(tmpObj, player, 3, 3);
tmpObj.aim3 = Utils.getDirect(tmpObj, player, 3, 3);
tmpObj.velX = tmpObj.x2 * 2 - tmpObj.lastX;
tmpObj.velY = tmpObj.y2 * 2 - tmpObj.lastY;
tmpObj.maxBuildDmg = items.weapons[tmpObj.weaponIndex].dmg *
(config.weaponVariants[player.weaponVariant].val ?
config.weaponVariants[player.weaponVariant].val : 1) *
(items.weapons[tmpObj.weaponIndex].sDmg || 1) * 3.3 //the tank updates r too fast
and who the FUCK breaks without tank
//mainPreplacer()
if (tmpObj.skinIndex == 45 && tmpObj.shameTimer <= 0) {
tmpObj.addShameTimer();
}
let R = player
niggers = players.filter(e => e.visible && (e.team != R.team ||
e.team === null) && e.sid != R.sid).sort((a, b) => Math.hypot(a.y2 - R.y2, a.x2 -
R.x2) - Math.hypot(b.y2 - R.y2, b.x2 - R.x2));
nearInfo = players.filter(tmpObj => tmpObj.visible &&
(tmpObj.team != player.team || tmpObj.team === null) && tmpObj.sid !=
player.sid).sort((a, b) => {
return Utils.getDist(a, player, 2, 2) - Utils.getDist(b,
player, 2, 2);
});
if (player) {
const playerX = player.x2;
const playerY = player.y2;
const now = Date.now();
const distSq = (x1, y1, x2, y2) => {
const dx = x2 - x1;
const dy = y2 - y1;
return dx * dx + dy * dy;
};
trapPredict = trapPredict.filter(trap => {
if (!trap) return false;
for (let t = 0; t < gameObjects.length; t++) {
let objects = gameObjects[t];
if (objects && objects.active) {
let dist = distSq(objects.x, objects.y, trap.x,
trap.y);
if (dist <= (trap.scale + objects.scale) ** 2) {
return false;
}
}
}
if (distSq(trap.x, trap.y, playerX, playerY) < trap.scale
** 2) {
return false;
}
if (now - trap.time >= 5000) {
return false;
}
predictions.enemyTrap.push(trap);
return true;
});
if (trapPredict.length > 3) {
trapPredict.sort((a, b) => a.time - b.time);
trapPredict = trapPredict.slice(1);
}
}
if (tmpObj == player) {
if (gameObjects.length) {
let nearTrap = gameObjects.filter(e => e.trap && e.active
&& Utils.getDist(e, tmpObj, 0, 2) <= (tmpObj.scale + e.getScale() + 5) && !
e.isTeamObject(tmpObj)).sort(function (a, b) {
return Utils.getDist(a, tmpObj, 0, 2) -
Utils.getDist(b, tmpObj, 0, 2);
})[0];
if (nearTrap) {
let spike = gameObjects.filter(e => (/spik/.test(e.name
|| e.dmg) && e.active && Utils.getDist(e, player, 0, 3) <= player.scale + e.scale +
20 && !e.isTeamObject(player))).sort((a, b) => {
return Utils.getDist(a, player, 0, 2) -
Utils.getDist(b, player, 0, 2);
})[0];
this.dist = Utils.getDist(nearTrap, tmpObj, 0, 2);
this.aim = Utils.getDirect(nearTrap, tmpObj, 0, 2);
if (!this.playerTrapped) {
this.protect(this.aim);
}
this.playerTrapped = true;
if (this.playerTrapped) {
this.spikeReplaceThreat = true;
game.tickBase(() => {
this.spikeReplaceThreat = false;
}, 2);
} else {
this.spikeReplaceThreat = false;
}
this.info = nearTrap;
if (spike) {
this.aim = Utils.getDirect(spike, tmpObj, 0, 2);
} else {
this.aim = Utils.getDirect(nearTrap, tmpObj, 0, 2);
}
} else {
this.playerTrapped = false;
this.info = {};
}
} else {
this.playerTrapped = false;
}
}
if (tmpObj == player) {
(!this.autoMill.x || !this.oldXY.x) && (this.autoMill.x =
this.oldXY.x = tmpObj.x2);
(!this.autoMill.y || !this.oldXY.y) && (this.autoMill.y =
this.oldXY.y = tmpObj.y2);
if (gameObjects.length) {
gameObjects.forEach((tmp) => {
tmp.onNear = false;
if (tmp.active) {
if (!tmp.onNear && Utils.getDist(tmp, tmpObj, 0, 2)
<= tmp.scale + items.weapons[tmpObj.weapons[0]].range) {
tmp.onNear = true;
}
}
});
}
}
if (tmpObj.weaponIndex < 9) {
tmpObj.primaryIndex = tmpObj.weaponIndex;
tmpObj.primaryVariant = tmpObj.weaponVariant;
} else if (tmpObj.weaponIndex > 8) {
tmpObj.secondaryIndex = tmpObj.weaponIndex;
tmpObj.secondaryVariant = tmpObj.weaponVariant;
}
tmpObj.hasAttackedThisTick = false;
tmpObj.hasFiredProjectileThisTick = false;
if (tmpObj._attackedThisTickTempVariable) {
tmpObj.hasAttackedThisTick = true;
tmpObj._attackedThisTickTempVariable = false;
}
if (tmpObj._firedThisTickTempVariable) {
tmpObj.hasFiredProjectileThisTick = true;
tmpObj._firedThisTickTempVariable = false;
}
}
i += 13;
}
if (textManager.stack.length) {
let stacks = [];
let notstacks = [];
let num = 0;
let num2 = 0;
let pos = {
x: null,
y: null
};
let pos2 = {
x: null,
y: null
}
textManager.stack.forEach((text) => {
if (text.value >= 0) {
if (num == 0) pos = {
x: text.x,
y: text.y
};
num += Math.abs(text.value);
} else {
if (num2 == 0) pos2 = {
x: text.x,
y: text.y
};
num2 += Math.abs(text.value);
}
});
if (num2 > 0) {
textManager.showText(pos2.x, pos2.y, Math.max(45, Math.min(50,
num2)), 0.18, 500, num2, "#8ecc51");
}
if (num > 0) {
textManager.showText(pos.x, pos.y, Math.max(45, Math.min(50, num)),
0.18, 500, num, "#fff");
}
textManager.stack = [];
}
if (runAtNextTick.length) {
runAtNextTick.forEach((tmp) => {
checkProjectileHolder(...tmp);
});
runAtNextTick = [];
}
for (let i = 0; i < data.length;) {
tmpObj = findPlayerBySID(data[i]);
if (tmpObj) {
if (!tmpObj.isTeam(player)) {
enemies.push(tmpObj);
if (tmpObj.dist2 <= items.weapons[tmpObj.primaryIndex ==
undefined ? 5 : tmpObj.primaryIndex].range + (player.scale * 2)) {
nears.push(tmpObj);
}
}
tmpObj.manageReload();
manageWeapons(tmpObj)
}
i += 13;
}
if (player && player.alive) {
predictReload()
if (player.alive && player.health < 100) {
if (player.isSafeHeal()) {
healer();
}
}
if (enemies.length) {
near = enemies.sort(function (tmp1, tmp2) {
return tmp1.dist2 - tmp2.dist2;
})[0];
}
if (game.tickQueue[game.tick]) {
game.tickQueue[game.tick].forEach((action) => {
action();
});
game.tickQueue[game.tick] = null;
}
players.forEach((tmp) => {
if (!tmp.visible && player != tmp) {
tmp.reloads = {
0: 0,
1: 0,
2: 0,
3: 0,
4: 0,
5: 0,
6: 0,
7: 0,
8: 0,
9: 0,
10: 0,
11: 0,
12: 0,
13: 0,
14: 0,
15: 0,
53: 0,
};
}
if (tmp.setBullTick) {
tmp.bullTimer = 0;
}
if (tmp.setPoisonTick) {
tmp.poisonTimer = 0;
}
tmp.updateTimer();
});
if (inGame) {
if (enemies.length) {
if (player.canEmpAnti) {
player.canEmpAnti = false;
if (near.dist2 <= 300 && !this.safePrimary(near) && !
this.safeSecondary(near)) {
if (near.reloads[53] == 0){
player.empAnti = true;
player.soldierAnti = false;
} else {
player.empAnti = false;
player.soldierAnti = true;
}
}
}
if ((canVelSyncHit() || canKBSyncHit() ||
canAutoKillerHit(near.health)) && !instaC.isTrue) {
if (player.weapons[1] == 15 && player.reloads[53] == 0) {
instaC.executeType("rev");
} else {
instaC.executeType("spike");
}
}
}
const plReload = function() {
return player.reloads[player.weapons[0]] <= 0 &&
player.reloads[player.weapons[1]] <= 0 && player.reloads[53] <= (player.weapons[1]
== 10 ? 0 : game.tickRate);
}
if ((this.checkIfCanInsta(true) ? this.checkIfCanInsta(true) :
this.checkIfCanInsta(false)) && near.dist2 <= items.weapons[player.weapons[1] == 10
? player.weapons[1] : player.weapons[0]].range + player.scale * 1.8 && !
this.waitHit && plReload && instaC.wait && !instaC.isTrue &&
player.reloads[player.weapons[0]] == 0 && player.reloads[player.weapons[1]] == 0) {
instaC.nobull = (this.checkIfCanInsta(true) ? true : false);
instaC.can = true;
} else {
instaC.can = false;
}
macro.f && place(4, getSafeDir());
macro.v && place(2, getSafeDir(), 1);
macro.y && place(5, getSafeDir());
macro.h && place(player.getItemType(22), getSafeDir());
macro.n && place(3, getSafeDir());
try {
let objectSize =
this.autoMill.size(items.list[player.items[3]].scale);
let objectDist =
this.autoMill.dist(items.list[player.items[3]].scale);
if (Utils.getDist(this.autoMill, player, 0, 2) > objectDist +
items.list[player.items[3]].placeOffset) {
if (mills.place) {
let millDir = Utils.getDirect(this.autoMill, player, 0,
2);
let plusXY = {
x: this.autoMill.x,
y: this.autoMill.y,
};
let Boom = Utils.getDirect(plusXY, player, 0, 2);
checkPlace(3, Boom);
checkPlace(3, Boom + Utils.toRad(objectSize));
checkPlace(3, Boom - Utils.toRad(objectSize));
this.autoMill.count = Math.max(0, this.autoMill.count -
1);
}
this.autoMill.x = player.x2;
this.autoMill.y = player.y2;
}
} catch (e) {}
if (instaC.can) {
instaC.executeType(player.weapons[1] == 10 ? "rev" :
instaC.nobull ? "nobull" : "normal");
}
if (instaC.canSpikeTick) {
instaC.canSpikeTick = false;
if (instaC.revTick) {
instaC.revTick = false;
if ([1, 2, 3, 4, 5, 6].includes(player.weapons[0]) &&
player.reloads[player.weapons[1]] == 0 && !instaC.isTrue) {
instaC.executeType("rev");
}
} else {
if ([1, 2, 3, 4, 5, 6].includes(player.weapons[0]) &&
player.reloads[player.weapons[0]] == 0 && !instaC.isTrue) {
instaC.executeType("spike");
if (instaC.syncHit) {
instaC.executeType("spike");
}
}
}
}
if (!clicks.middle && (clicks.left || clicks.right) && !
instaC.isTrue) {
if ((player.weaponIndex != (clicks.right && player.weapons[1]
== 10 ? player.weapons[1] : player.weapons[0])) || player.buildIndex > -1) {
selectWeapon(clicks.right && player.weapons[1] == 10 ?
player.weapons[1] : player.weapons[0]);
}
if (player.reloads[clicks.right && player.weapons[1] == 10 ?
player.weapons[1] : player.weapons[0]] == 0 && !this.waitHit) {
sendAutoGather();
this.waitHit = 1;
game.tickBase(() => {
sendAutoGather();
this.waitHit = 0;
}, 1);
}
}
if (getEl("autobullspam").checked && !clicks.left && !clicks.right
&& !instaC.isTrue && near.dist2 <= (items.weapons[player.weapons[0]].range +
near.scale * 1.8) && !this.playerTrapped) {
if ((player.weaponIndex != player.weapons[0]) ||
player.buildIndex > -1) {
selectWeapon(player.weapons[0]);
}
if (player.reloads[player.weapons[0]] == 0 && !this.waitHit) {
equipItem(7, 0);
sendAutoGather();
this.waitHit = 1;
game.tickBase(() => {
sendAutoGather();
this.waitHit = 0;
}, 1);
}
}
let spike = gameObjects.filter(obj => obj.active && (obj.dmg ||
obj.name == "pit trap") && (Utils.getDist(obj, player, 0, 2) - (player.scale *
1.8)) <= items.weapons[player.weapons[player.weapons[1] == 10 ? 1 : 0]].range && !
obj.isTeamObject(player)).sort((a, b) => Utils.getDist(a, player, 0, 2) -
Utils.getDist(b, player, 0, 2))[0];
if (this.playerTrapped) { // autobreak
if (!clicks.left && !clicks.right && !instaC.isTrue) {
if (player.weaponIndex != (this.notFast() ?
player.weapons[1] : player.weapons[0]) || player.buildIndex > -1) {
selectWeapon(this.notFast() ? player.weapons[1] :
player.weapons[0]);
}
if (player.reloads[this.notFast() ? player.weapons[1] :
player.weapons[0]] == 0 && !this.waitHit) {
sendAutoGather();
this.waitHit = 1;
game.tickBase(() => {
sendAutoGather();
this.waitHit = 0;
}, 1);
}
}
} else {
if (spike && getEl("safewalk").checked) {
if (!clicks.left && !clicks.right && !instaC.isTrue) {
this.spikes.breakSpike = true;
tracker.spikes.active = true;
tracker.spikes.x = spike.x;
tracker.spikes.y = spike.y;
tracker.spikes.scale = spike.scale;
if ((player.weaponIndex != (player.weapons[1] == 10 ?
player.weapons[1] : player.weapons[0]))) {
selectWeapon(player.weapons[1] == 10 ?
player.weapons[1] : player.weapons[0]);
}
this.spikes.angle = Utils.getDirect(spike, player, 0,
2);
if (player.reloads[player.weapons[1] == 10 ?
player.weapons[1] : player.weapons[0]] == 0 && !this.waitHit) {
sendAutoGather();
this.waitHit = 1;
game.tickBase(() => {
sendAutoGather();
this.waitHit = 0;
}, 1);
}
}
} else {
//some indicator resets
this.objHit.stop = null;
tracker.spikes.active = false;
}
}
if (clicks.middle && !this.playerTrapped) {
if (!instaC.isTrue && player.reloads[player.weapons[1]] == 0) {
if (this.ageInsta && player.weapons[0] != 4 &&
player.weapons[1] == 9 && player.age >= 9 && enemies.length) {
instaC.bowMovement();
} else {
if (player) {
sendChat("!FIRE!");
} else {
instaC.rangeType();
}
}
}
}
if (player.weapons[1] && !clicks.left && !clicks.right && !
this.playerTrapped && (spike ? false : true) && !instaC.isTrue) {
if (player.reloads[player.weapons[0]] == 0 &&
player.reloads[player.weapons[1]] == 0) {
if (!this.reloaded) {
this.reloaded = true;
let fastSpeed =
items.weapons[player.weapons[0]].spdMult < items.weapons[player.weapons[1]].spdMult
? 1 : 0;
if (player.weaponIndex != player.weapons[fastSpeed] ||
player.buildIndex > -1) {
selectWeapon(player.weapons[fastSpeed]);
}
}
} else {
this.reloaded = false;
if (player.reloads[player.weapons[0]] > 0) {
if (player.weaponIndex != player.weapons[0] ||
player.buildIndex > -1) {
selectWeapon(player.weapons[0]);
}
} else if (player.reloads[player.weapons[0]] == 0 &&
player.reloads[player.weapons[1]] > 0) {
if (player.weaponIndex != player.weapons[1] ||
player.buildIndex > -1) {
selectWeapon(player.weapons[1]);
}
}
}
}
this.placeQueue = this.place;
this.place = [];
if (this.placeQueue.length) {
for (let i = 0; i < this.placeQueue.length; i++) {
let objType = this.placeQueue[i][0] === "spike" ? 2 : 4;
if (objType !== undefined && player.itemCounts[objType] ?
(player.itemCounts[objType] < 99) : true) {
let angle = this.placeQueue[i][1];
checkPlace(objType, angle);
}
}
}
if (!instaC.isTrue && !this.playerTrapped) {
this.autoPlace();
}
if (!macro.q && !macro.f && !macro.v && !macro.h && !macro.n) {
io.send("D", getAttackDir());
}
let bullYick = 0;
let lastBullBleed = 0;
let startBullBleed = 0;
let bullTick = Math.abs(player.bullTick % 9 - 1000 % 9) < 2
function hatSystem() {
let bTick = Math.abs(bullYick % 9 - game.tick % 9) < 2;
let dist = nears.length ? Math.hypot(nears[0].x2 - player.x2,
nears[0].y2 - player.y2) <= 300 ? true : false : false;
let antispiketickthreat = asura.checkSpikeTick();
if (lagspike || canDeleteNearestZulu) { // safety measures so u
wont die
equipItem(6, 0);
}
if (spike && getEl("safewalk").checked) {
if (player.reloads[player.weapons[1] == 10 ?
player.weapons[1] : player.weapons[0]] == 0) {
equipItem(40, 0);
} else {
equipItem(player.empAnti || near.dist2 > 300 || !
enemies.length ? 6 : 6, 0);
}
} else {
if (player.shameCount && ((1000 - lastBullBleed) % 8 == 0
|| startBullBleed) && !dist && !asura.playerTrapped) {
startBullBleed++;
isBullTicking = true;
equipItem(7, 0);
}
if (clicks.right) {
equipItem(player.reloads[clicks.right &&
player.weapons[1] == 10 ? player.weapons[1] : player.weapons[0]] == 0 ? 40 :
player.empAnti ? 6 : player.soldierAnti ? 6 : biomeGear(1, 1), 0);
} else if (clicks.left) {
equipItem(getEl("autoGrind").checked ? 40 :
(player.reloads[player.weapons[0]] == 0 ? 7 : (player.empAnti ? 6 :
player.soldierAnti ? 6 : biomeGear(1, 1))),0);
} else if (asura.playerTrapped) {
if (asura.info.health <=
items.weapons[player.weaponIndex].dmg ? false : player.reloads[player.weapons[1] ==
10 ? player.weapons[1] : player.weapons[0]] == 0) {
// kusoi pls make a check if enemy is using bat or
dagger and prioritise fucking barb
equipItem(player.reloads[(player.weapons[1] ===
10 ? (!antispiketickthreat ? player.weapons[1] : player.weapons[0]) :
player.weapons[0])] === 0 ? 40 : 26, 6, 0);
} else {
equipItem(player.empAnti ? 6 : 6, 0);
}
} else if (player.shameCount && ((1000 - lastBullBleed) % 8
== 0 || startBullBleed) && !dist && !asura.playerTrapped) {
startBullBleed++;
isBullTicking = true;
equipItem(7, 0);
} else {
dist ? equipItem(6, 0) : biomeGear();
}
if (clicks.left || clicks.right) {
clicks.left ? equipItem(19, 1) : clicks.right &&
equipItem(11, 1); //lets be real, where tf is the use for CX wings anymore lmao
} else {
if (near.dist2 < 350 && !(player.primaryIndex == 7 ||
player.primaryIndex == 8)) {
equipItem(19, 1)
} else {
equipItem(11, 1);
}
}
}
}//plain and simple, handle clicks like normal otherwise if they
are not clicking check if the nearest enemy is in range and you dont have dh to sh
then equip shadow wings or monkey tail
if (storeMenu.style.display != "block" && !instaC.isTrue && !
instaC.ticking) {
hatSystem();
}
if (enemies.length && !this.playerTrapped && !instaC.ticking) {
autoPush();
} else {
if (this.autoPush) {
this.autoPush = false;
io.send("f", lastMoveDir||undefined, 1);
}
}
autoFarm()
autoBreakSpike();
if (!this.autoPush) {
autoBreakSpike(1);
}
if (instaC.syncHit) {
instaC.syncHit = false;
}
if (player.soldierAnti) {
player.soldierAnti = false;
}
if (this.antiTrapped) {
this.antiTrapped = false;
}
}
}
}
vectorDifference(point1, point2) {
return {
x: point2.x - point1.x,
y: point2.y - point1.y
};
}
dotProduct(vector1, vector2) {
return vector1.x * vector2.x + vector1.y * vector2.y;
}
magnitude(vector) {
return Math.sqrt(vector.x * vector.x + vector.y * vector.y);
}
calculateAngleUsingDotProduct(point1, point2) {
let diffVector = this.vectorDifference(point1, point2);
let playerDirection = {
x: Math.cos(player.dir),
y: Math.sin(player.dir)
};
let dotProd = this.dotProduct(playerDirection, diffVector);
let magnitudeProd = this.magnitude(playerDirection) *
this.magnitude(diffVector);
let cosTheta = dotProd / magnitudeProd;
let dynamicAngle = Math.acos(cosTheta);
dynamicAngle *= 180 / Math.PI;
if (dynamicAngle < 0) dynamicAngle += 360;
return dynamicAngle;
}
spikeKb = (objDir) => { // o1rds shit
Math.lineCircleIntersect = (lineStart, lineEnd, circleCenter, radius) => {
const dx = lineEnd.x - lineStart.x;
const dy = lineEnd.y - lineStart.y;
const fx = lineStart.x - circleCenter.x;
const fy = lineStart.y - circleCenter.y;
const a = dx * dx + dy * dy;
const b = 2 * (fx * dx + fy * dy);
const c = (fx * fx + fy * fy) - radius * radius;
let discriminant = b * b - 4 * a * c;
if (discriminant < 0) {
return false;
} else {
discriminant = Math.sqrt(discriminant);
return false;
}
}
const closestPoint = {
x: lineStart.x + lineDir.x * t,
y: lineStart.y + lineDir.y * t
};
return {
x: closestPoint.x + lineDir.x * offset,
y: closestPoint.y + lineDir.y * offset
};
}
if (player.reloads[player.weapons[0]] === 1) return;
const enemiesTrapped = objects
.filter(obj => obj.trap && obj.active)
.sort((a, b) => Math.getDist(near, a) - Math.getDist(near, b))
.find(trap => (player.sid === trap.ownerSID || trap.isTeamObject(player))
&& Math.getDist(near, trap) <= 50);
if (enemiesTrapped) return;
let placeDistance = items.list[player.items[2]].scale + player.scale +
items.list[player.items[2]].placeOffset;
let potSpike = {
x: player.x2 + Math.cos(objDir) * placeDistance,
y: player.y2 + Math.sin(objDir) * placeDistance
}
const straightAngle = Math.getDir(potSpike, near);
const outputKnockbackStrength = 1.5;
const outputKnockback = {
x: Math.cos(straightAngle) * outputKnockbackStrength,
y: Math.sin(straightAngle) * outputKnockbackStrength
};
let position = {
x: near.xVel + outputKnockback.x * 206,
y: near.yVel + outputKnockback.y * 206,
};
const pathStart = { x: near.x2, y: near.y2 };
const pathEnd = position;
const radius = player.scale + outputKnockbackStrength;
const buildings = objects.filter(obj => Math.getDist(position, obj) <=
radius + obj.scale && obj.dmg && obj.active);
let buildingDamage = 0;
const gameObjs = [...objects, ...buildings];
for (let i = 0; i < gameObjs.length; i++) {
const obj = gameObjs[i];
const objRadius = obj.scale + player.scale;
if (Math.lineCircleIntersect(pathStart, pathEnd, { x: obj.x, y:
obj.y }, objRadius) && (obj.trap ? (obj.ownerSID === player.sid ||
obj.isTeamObject(player)) : !obj.trap)) {
position = Math.getClosestPointOnLine(pathStart, pathEnd, { x:
obj.x, y: obj.y }, objRadius);
break;
}
}
potSpikeKB = {
x: position.x,
y: position.y
};
for (let i = 0; i < objects.length; i++) {
const trap = objects[i];
if (trap.trap && trap.active && (trap.ownerSID === player.sid ||
trap.isTeamObject(player))) {
const spikeNearby = objects.find(spike => spike.dmg && spike.active
&& Math.getDist(trap, spike) <= 87 && (spike.ownerSID === player.sid ||
spike.isTeamObject(player)));
const objectDist = Math.getDist(trap, position);
const spikeDist = Math.getDist(potSpike, near);
if (spikeNearby) {
if (near.dist2 <= trap.scale + player.scale * 2 +
items.list[player.items[2]].placeOffset && objectDist <= player.scale + trap.scale
&& spikeDist <= items.list[player.items[2]].scale + player.scale) {
return true;
}
}
}
}
for (let i = 0; i < objects.length; i++) {
const trap = objects[i];
if (trap.trap && trap.active) {
const spikeNearby = objects.find(spike => spike.dmg && spike.active
&& Math.getDist(trap, spike) <= 87 && (spike.ownerSID === player.sid ||
spike.isTeamObject(player)));
const objectDist = Math.getDist(trap, position);
const spikeDist = Math.getDist(potSpike, near);
if (spikeNearby) {
if (near.dist2 <= trap.scale + player.scale * 2 +
items.list[player.items[2]].placeOffset && objectDist <= player.scale + trap.scale
&& spikeDist <= items.list[player.items[2]].scale + player.scale) {
return true;
}
}
}
}
for (let i = 0; i < buildings.length; i++) {
const building = buildings[i];
const objectDist = Math.getDist(building, position);
const spikeDist = Math.getDist(potSpike, near);
if (near.dist2 <= building.scale + player.scale * 2 +
items.list[player.items[2]].placeOffset && spikeDist <=
items.list[player.items[2]].scale + player.scale && objectDist <= player.scale +
building.scale && (building.ownerSID === player.sid ||
building.isTeamObject(player))) {
return true;
}
}
return false;
}
canSpikeKB = function(findObj) {
//lets get into the actuall math now
if (Utils.getDist(findObj, player, 0, 2) > 85) return false;
let unSafeSpikes = gameObjects.filter(tmp => (tmp.dmg || tmp.cactus) &&
tmp.active && Utils.getDist(tmp, player, 0, 2) < 800)
let spikes = unSafeSpikes.filter(e => e.isTeamObject(player));
let totalDamage = 0;
if (spikes.length) for (let i = spikes.length; i--;) {
const SCOPE = spikes[i];
const DIST = Utils.getDist(SCOPE, player, 0, 2);
const ANGLE = Utils.getDirect(SCOPE, player, 0, 2);
const AngleToBrokenObject = Utils.getDirect(findObj, player, 0, 2);
const EnemyToSpikeDist = Utils.getDist(SCOPE, near, 0, 2);
const EnemyToSpikeAngle = Utils.getDirect(SCOPE, near, 0, 2);
const DistanceBetweenPlacedSpikeAndEnemy =
Utils.getDist(tmpSpikeObject, near, 0); //use lerp
const AngleBetweenPlacedSpikeAndEnemy = Utils.getDirect(tmpSpikeObject,
near, 0); //lerp again no need cause they were just intrap
if (tmpInt <= 0) {
const decelValue = 0.75;
let velocity = Utils.getDist(near, near, 2, 3);
//should always be true byt just in case
let tmpPos = {
//where the enemy will be after hitting a spike
x: SCOPE.x + SCALE *
Math.cos(AngleBetweenPlacedSpikeAndEnemy),
y: SCOPE.y + SCALE *
Math.sin(AngleBetweenPlacedSpikeAndEnemy),
}
//reset velocity
velocity = Utils.getDist(near, near, 2, 3);
/* angles */
const direction = Utils.getDirect(findObj, player, 0, 2)
const direction2 = near.aim2
/* angle scanning */
let buildings = gameObjects.filter(object => Utils.getDist(object, player,
0, 2) <= 300);
let spikeAngles = this.makeAngles(buildings, player.items[2])
let trapAngles = []
if (player.items[4]) {
trapAngles = this.makeAngles(buildings, player.items[4])
}
/* object filtering */
let enemyTrapped = gameObjects.filter(tmp => tmp.trap && tmp.active &&
tmp.isTeamObject(player) && Utils.getDist(tmp, near, 0, 2) <= (near.scale +
tmp.getScale() + 5)).sort(function(a, b) {
return Utils.getDist(a, near, 0, 2) - Utils.getDist(b, near, 0, 2);
})[0];
let nearAliveSpikes = [];
if (brokenTrapScan) {
nearAliveSpikes = gameObjects.filter(tmp => tmp.dmg && tmp.active &&
tmp.isTeamObject(player) && Utils.getDist(tmp, brokenTrapScan, 0, 0) <= (near.scale
+ brokenTrapScan.scale + tmp.scale + 5)).sort(function(a, b) {
return Utils.getDist(a, near, 0, 2) - Utils.getDist(b, near, 0, 2);
})[0];
}
if (enemyTrapped) {
let nearestAngle = undefined
let trapFound = false
for (let i = 0; i < spikeAngles.length; i++) {
if (!trapFound) {
for (let j = 2; j < spikeAngles[i].length; j++) {
if (enemyTrapped == spikeAngles[i][j]) {
trapFound = true
nearestAngle = ((spikeAngles[i][0] - direction) <
(spikeAngles[i][1] - direction) ? spikeAngles[i][0] : spikeAngles[i][1])
}
}
}
}
if (trapFound) {
let objectX = player.x2 + (Math.cos(nearestAngle) * (player.scale +
items.list[player.items[2]].scale + (items.list[player.items[2]].placeOffset ||
0)))
let objectY = player.y2 + (Math.sin(nearestAngle) * (player.scale +
items.list[player.items[2]].scale + (items.list[player.items[2]].placeOffset ||
0)))
if (Math.hypot(objectY - near.y2, objectX - near.x2) <
(player.scale + items.list[player.items[2]].scale + 8)) {
place(2, nearestAngle);
addMenuChText("Replacer", `Replaced spike nearestAngle: $
{nearestAngle}`, "lightBlue");
}
} else {
if (secondaryCheck(player.items[4], direction)) {
place(4, direction);
addMenuChText("Replacer", `Replaced trap direct: ${direction}`,
"lightBlue");
} else {
for (let i = 0; i < trapAngles.length; i++) {
let closest = (direction - trapAngles[i][0] <= direction -
trapAngles[i][1] ? trapAngles[i][0] : trapAngles[i][1])
if (Math.abs(closest - direction) < Math.PI &&
secondaryCheck(player.items[4], closest)) {
place(4, closest);
addMenuChText("Replacer", `Replaced trap closest: $
{closest}`, "lightBlue");
}
}
}
}
let inRange = near.dist2 <= items.weapons[player.weapons[0]].range +
player.scale * 1.8
let spiketickthreat = this.checkSpikeTick()
if (inRange && !spiketickthreat && asura.preplaceInfo[0] !== "trap") {
instaC.executeType("spike");
place(2, objAim)
}
} else if (this.canSpikeKB(findObj)) {
place(2, Utils.getDirect(findObj, player, 0, 2))
addMenuChText("Replacer", `SPIKESYNC`, "lightBlue");
} else if (brokenTrapScan) {
if (nearAliveSpikes || this.inTrap) {
if (secondaryCheck(player.items[4], direction2)) {
place(4, direction2);
addMenuChText("Replacer", `Replaced trap direct: $
{direction2}`, "lightBlue");
} else {
for (let i = 0; i < trapAngles.length; i++) {
let closest = (direction - trapAngles[i][0] <= direction -
trapAngles[i][1] ? trapAngles[i][0] : trapAngles[i][1])
if (Math.abs(closest - direction) < Math.PI &&
secondaryCheck(player.items[4], closest)) {
place(4, closest);
addMenuChText("Replacer", `Replaced trap closest: $
{closest}`, "lightBlue");
}
}
}
} else {
if (secondaryCheck(player.items[2], direction2)) {
place(2, direction2);
instaC.canSpikeTick = true;
addMenuChText("Replacer", `Replaced spike direct: $
{direction2}`, "lightBlue");
} else {
for (let i = 0; i < spikeAngles.length; i++) {
let closest = (direction - spikeAngles[i][0] <= direction -
spikeAngles[i][1] ? spikeAngles[i][0] : spikeAngles[i][1])
if (Math.abs(closest - direction) < Math.PI &&
secondaryCheck(player.items[2], closest)) {
place(2, closest);
addMenuChText("Replacer", `Replaced spike closest: $
{closest}`, "lightBlue");
}
}
}
}
} else {
if (secondaryCheck(player.items[4], direction)) {
place(4, direction);
addMenuChText("Replacer", `Replaced trap direct: ${direction}`,
"lightBlue");
} else {
for (let i = 0; i < trapAngles.length; i++) {
let closest = (direction - trapAngles[i][0] <= direction -
trapAngles[i][1] ? trapAngles[i][0] : trapAngles[i][1])
if (Math.abs(closest - direction) < Math.PI &&
secondaryCheck(player.items[4], closest)) {
place(4, closest);
addMenuChText("Replacer", `Replaced trap closest: $
{closest}`, "lightBlue");
}
}
}
}
};
/*autoReplace = function(findObj) {
if (!getEl("autoreplace").checked) return
const toRad = function (angle) {
return angle * (Math.PI / 180);
}
let objAim = Math.atan2(findObj.y - player.y2, findObj.x - player.x2)
let objDst = Math.hypot(findObj.y - player.y2, findObj.x - player.x2)
if (near.dist2 <= 350 && objDst <= 486) {
if (fgdo(near, player) <= 250) {
let tmpCount = -1;
for (let i = -90; i < 0; i += 90) {
tmpCount++;
if (tmpCount == 1 && objDst <= 200) {
place(2, objAim);
} else {
place(2, objAim + toRad(i));
}
let inRange = near.dist2 <=
items.weapons[player.weapons[0]].range + player.scale * 1.8
let spiketickthreat = this.checkSpikeTick()
if (inRange && !spiketickthreat && asura.preplaceInfo[0] !==
"trap") {
instaC.executeType("spike");
place(2, objAim)
}
}
} else if (near.dist2 <= 350 && objDst <= 486) {
let tmpCount = -1;
for (let i = 0; i < Math.PI * 2; i += Math.PI) {
if (player.items[4] == 15) {
tmpCount++;
if (tmpCount == 0 && objDst <= 200) {
place(4, objAim);
} else {
place(4, objAim + i);
}
}
let inRange = near.dist2 <=
items.weapons[player.weapons[0]].range + player.scale * 1.8
if (!asura.checkSpikeTick() && asura.preplaceInfo.length) {
if (findObj == asura.preplaceInfo[1]) {
if (asura.preplaceInfo[0] == "spike") {
if ([1, 2, 3, 4, 5, 6].includes(player.weapons[0]))
{
if (Utils.getAngleDist(near.aim2,
Utils.getDirect(asura.preplaceInfo[1], player, 0, 2)) <= 1 && inRange) {
instaC.executeType("spike");
textManager.showText(player.x, player.y,
30, 0.15, 1850, 'PreSpikeTick', '#7289DA', 2);
}
}
}
}
}
if (asura.preplaceInfo.length) {
if (findObj == asura.preplaceInfo[1]) {
if (asura.preplaceInfo[0] == "trap") {
let spikeAngles = this.makeAngles(objects,
player.items[2]);
let dynamicAngle =
this.calculateAngleUsingDotProduct(player, findObj);
let nearestSpikeAngle =
this.findNearestAngle(spikeAngles, dynamicAngle);
place(2, nearestSpikeAngle, objAim);
}
}
}
}
}
}
}*/
/*potentialBuildDamage = function (b, u) {
let wI = u.weapons[1] === 10 && !player.reloads[u.weapons[1]] ? 1 : 0;
let w = u.weapons[wI];
if (player.reloads[w]) return 0;
let iW = items.weapons[w];
let inD = this.d(b.x, b.y, u.x2, u.y2) <= b.getScale() + iW.range;
return u.visible && inD ? iW.dmg * (iW.sDmg || 1) * 3.3 : 0;
};*/
potentialBuildDamage = function(object, singlePlayer) { // potential dmg
try {
let selectedWeapon = singlePlayer.weapons[player.weapons[1] == 10 ? 1 :
0];
let weaponInfo =
items.weapons[singlePlayer.weapons[singlePlayer.weapons[1] == 10 ? 1 : 0]];
let isWithinRange = Utils.getDist(object, singlePlayer, 0, 2) <=
object.getScale() + weaponInfo.range;
return singlePlayer.visible && isWithinRange &&
Utils.getAngleDist(Utils.getDirect(object, singlePlayer, 0, 2), singlePlayer.dir)
<= config.gatherAngle ? weaponInfo.dmg *
(config.weaponVariants[singlePlayer.weaponVariant].val ?
config.weaponVariants[singlePlayer.weaponVariant].val : 1) * (weaponInfo.sDmg || 1)
* 3.3 : 0;
} catch (e) {
}
}
preplaceAngle = function (filteredGameObjects, objWithLowestHealth) {
let priorityResults = [];
let trapCandidates = [];
let spikeCandidates = [];
let buildings = gameObjects.filter(object => Utils.getDist(object, player,
0, 2) <= 300);
//let spikeAngles = this.makeAngles(buildings, player.items[2]);
let spikeAngles = this.refineAngles(2);
let trapAngles = [];
if (player.items[4]) {
trapAngles = this.makeAngles(buildings, player.items[4]);
}
if (asura.playerTrapped) {
spikeCandidates = filteredGameObjects
.filter(obj => obj.dmg && obj.active && Utils.getDist(obj,
this.info, 0, 0) <= (player.scale + this.info.scale + obj.scale + 5))
.sort((a, b) => Utils.getDist(a, player, 0, 2) - Utils.getDist(b,
player, 0, 2));
if (spikeCandidates.length > 0) {
let spikeAngle = this.getClosestAngle(spikeAngles,
Utils.getDirect(spikeCandidates[0], player, 0, 2));
priorityResults.push(["spike", spikeCandidates[0], spikeAngle]);
} else {
trapCandidates = filteredGameObjects
.filter(obj => obj.trap && obj.active &&
obj.isTeamObject(player) && Utils.getDist(obj, near, 0, 2) <= (near.scale +
obj.getScale() + 15))
.sort((a, b) => Utils.getDist(a, near, 0, 2) - Utils.getDist(b,
near, 0, 2));
if (trapCandidates.length > 0) {
let trapAngle = this.getClosestAngle(trapAngles,
Utils.getDirect(trapCandidates[0], player, 0, 2));
priorityResults.push(["trap", trapCandidates[0], trapAngle]);
} else {
let spikeAngle = this.getClosestAngle(spikeAngles,
Utils.getDirect(objWithLowestHealth, player, 0, 2));
priorityResults.push(["spike", objWithLowestHealth,
spikeAngle]);
}
}
} else {
trapCandidates = filteredGameObjects
.filter(obj => obj.trap && obj.active && obj.isTeamObject(player)
&& Utils.getDist(obj, near, 0, 2) <= (near.scale + obj.getScale() + 15))
.sort((a, b) => Utils.getDist(a, near, 0, 2) - Utils.getDist(b,
near, 0, 2));
if (trapCandidates.length > 0) {
let trapAngle = this.getClosestAngle(trapAngles,
Utils.getDirect(trapCandidates[0], player, 0, 2));
priorityResults.push(["trap", trapCandidates[0], trapAngle]);
spikeCandidates = filteredGameObjects
.filter(obj => obj.dmg && obj.active &&
obj.isTeamObject(player) && Utils.getDist(obj, trapCandidates[0], 0, 0) <=
(near.scale + trapCandidates[0].scale + obj.scale + 5))
.sort((a, b) => Utils.getDist(a, near, 0, 2) - Utils.getDist(b,
near, 0, 2));
if (spikeCandidates.length > 0) {
let spikeAngle = this.getClosestAngle(spikeAngles,
Utils.getDirect(spikeCandidates[0], player, 0, 2));
priorityResults.push(["spike", spikeCandidates[0],
spikeAngle]);
}
} else {
let spikeAngle = this.getClosestAngle(spikeAngles,
Utils.getDirect(objWithLowestHealth, player, 0, 2));
priorityResults.push(["spike", objWithLowestHealth, spikeAngle]);
let secondaryObject = filteredGameObjects.find(obj => obj !==
objWithLowestHealth && obj.health > 0);
if (secondaryObject) {
let trapAngle = this.getClosestAngle(trapAngles,
Utils.getDirect(secondaryObject, player, 0, 2));
priorityResults.push(["trap", secondaryObject, trapAngle]);
}
}
}
} else if (isWeapon) {
Utils.generateElement({
class: "itemInfoReq",
text: !item.type ? "primary" : "secondary",
parent: itemInfoHolder
});
} else {
for (let i = 0; i < item.req.length; i += 2) {
Utils.generateElement({
class: "itemInfoReq",
html: item.req[i] + "<span class='itemInfoReqVal'> x" +
item.req[i + 1] + "</span>",
parent: itemInfoHolder
});
}
if (item.group.limit) {
Utils.generateElement({
class: "itemInfoLmt",
text: (player.itemCounts[item.group.id] || 0) + "/" +
(config.isSandbox ? 99 : item.group.limit),
parent: itemInfoHolder
});
}
}
} else {
itemInfoHolder.classList.remove("visible");
}
}
window.addEventListener("resize", Utils.checkTrusted(resize));
function resize() {
screenWidth = window.innerWidth;
screenHeight = window.innerHeight;
let scaleFillNative = Math.max(screenWidth / maxScreenWidth, screenHeight /
maxScreenHeight) * pixelDensity;
gameCanvas.width = screenWidth * pixelDensity;
gameCanvas.height = screenHeight * pixelDensity;
gameCanvas.style.width = screenWidth + "px";
gameCanvas.style.height = screenHeight + "px";
mainContext.setTransform(
scaleFillNative, 0,
0, scaleFillNative,
(screenWidth * pixelDensity - (maxScreenWidth * scaleFillNative)) / 2,
(screenHeight * pixelDensity - (maxScreenHeight * scaleFillNative)) / 2
);
}
resize();
let usingTouch;
const mals = document.getElementById('touch-controls-fullscreen');
mals.style.display = 'block';
mals.addEventListener("mousemove", gameInput, false);
function gameInput(e) {
mouseX = e.clientX;
mouseY = e.clientY;
}
let clicks = {
left: false,
middle: false,
right: false,
};
mals.addEventListener("mousedown", mouseDown, false);
function mouseDown(e) {
if (attackState != 1) {
attackState = 1;
if (e.button == 0) {
clicks.left = true;
} else if (e.button == 1) {
clicks.middle = true;
} else if (e.button == 2) {
clicks.right = true;
}
}
}
mals.addEventListener("mouseup", Utils.checkTrusted(mouseUp));
function mouseUp(e) {
if (attackState != 0) {
attackState = 0;
if (e.button == 0) {
clicks.left = false;
} else if (e.button == 1) {
clicks.middle = false;
} else if (e.button == 2) {
clicks.right = false;
}
}
}
mals.addEventListener("wheel", wheel, false);
let wbe = 1;
function wheel(e) {
e.preventDefault();
let delta = Math.max(-1, Math.min(1, (e.deltaY || -e.detail)));
let step = 0.05 * delta;
let newWbe = Math.min(Math.max(wbe + step, 0.5), 2);
zoom(newWbe);
}
function zoom(newWbe) {
let startWbe = wbe;
let increment = 0.05;
let timer = setInterval(function() {
if (startWbe < newWbe) {
startWbe += increment;
if (startWbe >= newWbe) clearInterval(timer);
} else {
startWbe -= increment;
if (startWbe <= newWbe) clearInterval(timer);
}
wbe = startWbe;
updateZoom();
}, 20);
}
function updateZoom() {
maxScreenWidth = config.maxScreenWidth * wbe;
maxScreenHeight = config.maxScreenHeight * wbe;
resize();
}
function getMoveDir() {
let dx = 0;
let dy = 0;
for (let key in moveKeys) {
let tmpDir = moveKeys[key];
dx += !!keys[key] * tmpDir[0];
dy += !!keys[key] * tmpDir[1];
}
return dx == 0 && dy == 0 ? undefined : Math.atan2(dy, dx);
}
function getSafeDir() {
if (!player)
return 0;
if (!player.lockDir) {
lastDir = Math.atan2(mouseY - (screenHeight / 2), mouseX - (screenWidth /
2));
}
return lastDir || 0;
}
function getAttackDir(debug) {
if (debug) {
if (!player)
return "0";
if (asura.autoAim || ((clicks.left) && player.reloads[player.weapons[0]] ==
0))
lastDir = enemies.length ? asura.revAim ? "(near.aim2 + Math.PI)" :
"near.aim2" : "getSafeDir()";
else
if (clicks.right && player.reloads[player.weapons[1] == 10 ?
player.weapons[1] : player.weapons[0]] == 0)
lastDir = "getSafeDir()";
else
if (asura.playerTrapped)
lastDir = "asura.aim";
else
if (asura.spikes.breakSpike && player.reloads[player.weapons[1] == 10 ?
player.weapons[1] : player.weapons[0]] == 0)
lastDir = "asura.spikes.angle";
else
if (!player.lockDir) {
if (inGame) return "undefined";
lastDir = "getSafeDir()";
}
return lastDir;
} else {
if (!player)
return 0;
if (asura.autoAim || ((clicks.left) && player.reloads[player.weapons[0]] ==
0))
lastDir = enemies.length ? asura.revAim ? (near.aim2 + Math.PI) :
near.aim2 : getSafeDir();
else
if (clicks.right && player.reloads[player.weapons[1] == 10 ?
player.weapons[1] : player.weapons[0]] == 0)
lastDir = getSafeDir();
else
if (asura.playerTrapped && player.reloads[asura.notFast() ?
player.weapons[1] : player.weapons[0]] == 0)
lastDir = asura.aim;
else
if (asura.spikes.breakSpike && player.reloads[player.weapons[1] == 10 ?
player.weapons[1] : player.weapons[0]] == 0)
lastDir = asura.spikes.angle;
else
if (!player.lockDir) {
if (inGame) return undefined;
lastDir = getSafeDir();
}
return lastDir || 0;
}
}
function getVisualDir() {
if (!player)
return 0;
if (asura.autoAim || ((clicks.left) && player.reloads[player.weapons[0]] == 0))
lastDir = getEl("autoGrind").checked ? getSafeDir() : enemies.length ?
asura.revAim ? (near.aim2 + Math.PI) : near.aim2 : getSafeDir();
else
if (clicks.right && player.reloads[player.weapons[1] == 10 ?
player.weapons[1] : player.weapons[0]] == 0)
lastDir = getSafeDir();
else
if (asura.playerTrapped)
lastDir = asura.aim;
else
if (!player.lockDir) {
lastDir = getSafeDir();
}
return lastDir || 0;
}
function debug() {
asura.waitHit = 0;
asura.autoAim = false;
instaC.isTrue = false;
asura.inTrap = false;
asura.autoPush = false;
itemSprites = [];
objSprites = [];
gameObjectSprites = [];
};
function keysActive() {
return allianceMenu.style.display != "block" && chatHolder.style.display !=
"block" && !menuCBFocus;
}
let blockedEnemies = new Set();
const block = {
description: "{enemy sid}",
execute(args) {
if (args.length < 2) {
textManager.showText(player.x2, player.y2, 30, 0.15, 1850,
"Usage: .block <enemysid>", "#ff0000", 2);
return;
}
let enemySid = parseInt(args[1], 10);
if (isNaN(enemySid)) {
textManager.showText(player.x2, player.y2, 30, 0.15, 1850, "Invalid
SID. Please enter a valid number.", "#ff0000", 2);
return;
}
if (blockedEnemies.has(enemySid)) {
addMenuChText("Debug", `Enemy with SID ${enemySid} is already blocked`,
"orange");
textManager.showText(player.x2, player.y2, 30, 0.15, 1850, `Enemy with
SID ${enemySid} is already blocked`, "#ff0000", 2);
} else {
addMenuChText("Debug", `Blocked enemy with SID ${enemySid}`, "orange");
blockedEnemies.add(enemySid);
textManager.showText(player.x2, player.y2, 30, 0.15, 1850, `Blocked
enemy with SID ${enemySid}`, "#ff0000", 2);
}
}
};
const unblock = {
description: "{enemy sid}",
execute(args) {
if (args.length < 2) {
textManager.showText(player.x2, player.y2, 30, 0.15, 1850,
"Usage: .unblock <enemysid>", "#ff0000", 2);
return;
}
let enemySid = parseInt(args[1], 10);
if (isNaN(enemySid)) {
textManager.showText(player.x2, player.y2, 30, 0.15, 1850, "Invalid
SID. Please enter a valid number.", "#ff0000", 2);
return;
}
if (blockedEnemies.delete(enemySid)) {
addMenuChText("Debug", `Unblocked enemy with SID ${enemySid}`,
"orange");
textManager.showText(player.x2, player.y2, 30, 0.15, 1850, `Unblocked
enemy with SID ${enemySid}`, "#ff0000", 2);
} else {
addMenuChText("Debug", `Enemy with SID ${enemySid} was not blocked`,
"orange");
textManager.showText(player.x2, player.y2, 30, 0.15, 1850, `Enemy with
SID ${enemySid} was not blocked`, "#ff0000", 2);
}
}
};
function toggleMenuChat() {
if (menuChatDiv.style.display != "none") {
chatHolder.style.display = "none";
if (menuChatBox.value != "") {
if (menuChatBox.value.startsWith(".")) {
const commandArgs = menuChatBox.value.slice(1).split(" ");
const command = commandArgs[0].toLowerCase();
if (command === "block") {
block.execute(commandArgs);
} else if (command === "unblock") {
unblock.execute(commandArgs);
} else {
textManager.showText(player.x2, player.y2, 30, 0.15, 1850,
`Unknown command: ${command}`, "#ff0000", 2);
}
} else {
sendChat(menuChatBox.value);
}
menuChatBox.value = "";
menuChatBox.blur();
} else {
if (menuCBFocus) {
menuChatBox.blur();
} else {
menuChatBox.focus();
}
}
}
}
function keyDown(event) {
let keyNum = event.which || event.keyCode || 0;
if (keysActive()) {
if (menuCBFocus || menuChatBox === document.activeElement) {
return;
}
if (player && player.alive && keysActive()) {
if (!keys[keyNum]) {
keys[keyNum] = 1;
macro[event.key] = 1;
if (keyNum == 67) {
updateMapMarker();
} else if (keyNum == 69) {
sendAutoGather();
} else if (player.weapons[keyNum - 49] != undefined) {
player.weaponCode = player.weapons[keyNum - 49];
} else if (moveKeys[keyNum]) {
sendMoveDir();
} else if (keyNum == 82) {
instaC.wait = !instaC.wait;
} else if (keyNum == 32) {
io.send("F", 1, getSafeDir(), 1);
io.send("F", 0, getSafeDir(), 1);
} else if (event.key == "z") {
mills.place = !mills.place;
} else if (event.key == "Z") {
debug();
}
}
}
}
}
addEventListener("keydown", Utils.checkTrusted(keyDown));
function keyUp(event) {
if (menuCBFocus || menuChatBox === document.activeElement) {
return;
}
if (player && player.alive) {
let keyNum = event.which || event.keyCode || 0;
if (keyNum == 13) {
toggleMenuChat();
} else if (keysActive()) {
if (keys[keyNum]) {
keys[keyNum] = 0;
macro[event.key] = 0;
if (moveKeys[keyNum]) {
sendMoveDir();
} else if (event.key == ",") {
player.sync = false;
}
}
}
}
}
window.addEventListener("keyup", Utils.checkTrusted(keyUp));
function sendMoveDir() {
let newMoveDir = getMoveDir();
if (lastMoveDir == undefined || newMoveDir == undefined || Math.abs(newMoveDir
- lastMoveDir) > 0.3) {
if (!asura.autoPush && !found) {
io.send("f", newMoveDir, 1);
}
lastMoveDir = newMoveDir;
}
}
function caf(t, n) {
try {
return Math.atan2((n.y2 || n.y) - (t.y2 || t.y), (n.x2 || n.x) - (t.x2 ||
t.x))
} catch (i) {
return 0
}
}
function cdf(t, n) {
try {
return Math.hypot((n.y2 || n.y) - (t.y2 || t.y), (n.x2 || n.x) - (t.x2 ||
t.x))
} catch (i) {
return 1 / 0
}
}
function autoPush() {
let enemiesTrapped = objects
.filter(tmp => tmp.trap && tmp.active && tmp.isTeamObject(player) &&
Utils.getDist(tmp, near, 0, 2) <= (near.scale + tmp.getScale() + 15))
.sort((a, b) => Utils.getDist(a, near, 0, 2) - Utils.getDist(b, near, 0, 2))
[0];
if (!enemiesTrapped) { // useless check 1
asura.autoPush = false;
return;
}
let enemiesSpike = objects.some(tmp => tmp.dmg && tmp.active && !
tmp.isTeamObject(player) && Utils.getDist(tmp, enemiesTrapped, 0, 0) <= (near.scale
+ tmp.scale + 40));
if (enemiesSpike) {
equipItem(6, 0); // instead of completely turning autopush off just use
soldier so u wont die to spiketick
}
let spike = objects.filter(tmp => tmp.dmg && tmp.active &&
tmp.isTeamObject(player) && Utils.getDist(tmp, enemiesTrapped, 0, 0) <= (near.scale
+ tmp.scale + 40)).sort((a, b) => Utils.getDist(a, near, 0, 2) - Utils.getDist(b,
near, 0, 2))[0];
if (!spike || Utils.getDist(spike, enemiesTrapped, 0, 0) <= 0) { // useless
check 2
asura.autoPush = false;
return;
}
let pos = {
x: spike.x + (250 * Math.cos(Utils.getDirect(near, spike, 2, 0))),
y: spike.y + (250 * Math.sin(Utils.getDirect(near, spike, 2, 0))),
x2: spike.x + ((Utils.getDist(near, spike, 2, 0) + player.scale) *
Math.cos(Utils.getDirect(near, spike, 2, 0))),
y2: spike.y + ((Utils.getDist(near, spike, 2, 0) + player.scale) *
Math.sin(Utils.getDirect(near, spike, 2, 0)))
};
if (near.dist2 <= 170) {
asura.autoPush = true;
let angle = Math.atan2(near.y2 - spike.y, near.x2 - spike.x);
let point = {
x: near.x2 + Math.cos(angle) * 53,
y: near.y2 + Math.sin(angle) * 53
};
let distanceToSpike = Utils.getDist(near, spike, 2, 0);
let scale = (player.scale / 10);
if (distanceToSpike >= 105) {
if (Utils.lineInRect(player.x2 - scale, player.y2 - scale, player.x2 +
scale, player.y2 + scale, near.x2, near.y2, pos.x, pos.y)) {
io.send("f", near.aim2, 1);
} else {
io.send("f", Utils.getDirect(pos, player, 2, 2), 1);
}
} else {
io.send("f", Math.atan2(point.y - player.y2, point.x - player.x2), 1);
}
} else {
io.send("f", Utils.getDirect(near, spike, 2, 0), 1);
}
}
function dist(a, b) {
return Math.hypot((a.y2 || a.y) - (b.y2 || b.y), (a.x2 || a.x) - (b.x2 ||
b.x));
}
function setInitData(data) {
alliances = data.teams;
}
let currentStoreIndex = 0;
function changeStoreIndex(index) {
if (currentStoreIndex != index) {
currentStoreIndex = index;
generateStoreList();
}
}
function generateStoreList() {
if (player) {
Utils.removeAllChildren(storeHolder);
var index = currentStoreIndex;
var tmpArray = index ? accessories : hats;
for (var i = 0; i < tmpArray.length; ++i) {
if (!tmpArray[i].dontSell) {
(function(i) {
var tmp = Utils.generateElement({
id: "storeDisplay" + i,
class: "storeItem",
onmouseout: function() {
showItemInfo();
},
onmouseover: function() {
showItemInfo(tmpArray[i], false, true);
},
parent: storeHolder,
});
Utils.hookTouchEvents(tmp, true);
Utils.generateElement({
tag: "img",
class: "hatPreview",
src: "../img/" + (index ? "accessories/access_" :
"hats/hat_") + tmpArray[i].id + (tmpArray[i].topSprite ? "_p" : "") + ".png",
parent: tmp,
});
Utils.generateElement({
tag: "span",
text: tmpArray[i].name,
parent: tmp,
});
if (index ? !player.tails[tmpArray[i].id] : !
player.skins[tmpArray[i].id]) {
Utils.generateElement({
class: "joinAlBtn",
style: "margin-top: 5px",
text: "Buy",
onclick: function() {
storeBuy(tmpArray[i].id, index);
},
hookTouch: true,
parent: tmp,
});
Utils.generateElement({
tag: "span",
class: "itemPrice",
text: tmpArray[i].price,
parent: tmp,
});
} else if ((index ? player.tailIndex : player.skinIndex) ==
tmpArray[i].id) {
Utils.generateElement({
class: "joinAlBtn",
style: "margin-top: 5px",
text: "Unequip",
onclick: function() {
storeEquip(0, index);
},
hookTouch: true,
parent: tmp,
});
} else {
Utils.generateElement({
class: "joinAlBtn",
style: "margin-top: 5px",
text: "Equip",
onclick: function() {
storeEquip(tmpArray[i].id, index);
},
hookTouch: true,
parent: tmp,
});
}
}
)(i);
}
}
}
}
function toggleStoreMenu() {
if (storeMenu.style.display != "block") {
storeMenu.style.display = "block";
allianceMenu.style.display = "none";
closeChat();
generateStoreList();
} else {
storeMenu.style.display = "none";
}
}
function toggleSettings() {
if (guideCard.classList.contains("showing")) {
guideCard.classList.remove("showing");
settingsButtonTitle.innerText = "Settings";
} else {
guideCard.classList.add("showing");
settingsButtonTitle.innerText = "Close";
}
}
function showLoadingText(text) {
mainMenu.style.display = "block";
gameUI.style.display = "none";
menuCardHolder.style.display = "none";
diedText.style.display = "none";
loadingText.style.display = "block";
loadingText.innerHTML = text + "<a
href='javascript:window.location.href=window.location.href'
class='ytLink'>reload</a>";
}
function bindEvents() {
enterGameButton.onclick = Utils.checkTrusted(function() {
enterGame();
});
Utils.hookTouchEvents(enterGameButton);
settingsButton.onclick = Utils.checkTrusted(function() {
toggleSettings();
});
Utils.hookTouchEvents(settingsButton);
// removed half of the shit because they are useless
}
bindEvents()
function enterGame() {
if (!inGame) {
inGame = true;
showLoadingText("Loading...");
io.connect()
}
}
function setupGame(yourSID) {
keys = {};
macro = {};
playerSID = yourSID;
attackState = 0;
inGame = true;
io.send("f", 0, getAttackDir(), 1);
asura.ageInsta = true;
if (firstSetup) {
firstSetup = false;
gameObjects.length = 0;
objects.length = 0;
//tickLoop()
}
}
function updateTick() {
let currentTime = performance.now();
if (!enemies.length) return; //save some calculation time
for (let i = 0; i < players.length; ++i) {
let tmpObj = players[i]
if (tmpObj == player) {
//zeptosecondPreplacer()
}
}
}
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function tickLoop() {
let startTime = performance.now();
updateTick();
let oldTime = performance.now() - startTime;
let remainingTime = Math.max(1000 / 9 - (oldTime % (1000 / 9)), 0);
delay(remainingTime).then(() => {
tickLoop();
});
}
function addPlayer(data, isYou) {
let tmpPlayer = findPlayerByID(data[0]);
if (!tmpPlayer) {
tmpPlayer = new Player(data[0], data[1], config, Utils, projectileManager,
objectManager, players, ais, items, hats, accessories);
players.push(tmpPlayer);
if (data[1] != playerSID) {
}
} else {
if (data[1] != playerSID) {
}
}
tmpPlayer.spawn(isYou ? true : null);
tmpPlayer.visible = false;
tmpPlayer.lastX = tmpPlayer.lastY = void 0;
tmpPlayer.x2 = undefined;
tmpPlayer.y2 = undefined;
tmpPlayer.x3 = undefined;
tmpPlayer.y3 = undefined;
tmpPlayer.setData(data);
if (isYou) {
if (!player) {
prepareIngameUI(tmpPlayer);
}
player = tmpPlayer;
camX = player.x;
camY = player.y;
asura.lastDir = 0;
updateItems();
updateAge();
}
}
function removePlayer(id) {
for (let i = 0; i < players.length; i++) {
if (players[i].id == id) {
players.splice(i, 1);
break;
}
}
}
Math.getDist = function (e, t) {
try {
let x1 = (t.x2 || t.x);
let y1 = (t.y2 || t.y);
let autos = {
insta: {
todo: false,
wait: false,
count: 4,
shame: 5
},
bull: false,
antibull: 0,
reloaded: false,
stopspin: true
}
let lastPos = { x: 0, y: 0 };
function fgdo(a, b) {
return Math.sqrt(Math.pow((b.y - a.y), 2) + Math.pow((b.x - a.x), 2));
}
break;
}
}
}
}
function gatherAnimation(sid, didHit, index) {
tmpObj = findPlayerBySID(sid);
if (tmpObj) {
tmpObj.startAnim(didHit, index);
if (index < 9) {
tmpObj.primaryReload = -game.tickRate / items.weapons[index].speed
} else {
tmpObj.secondaryReload = -game.tickRate / items.weapons[index].speed
}
tmpObj.gatherIndex = index;
tmpObj.gathering = 1;
tmpObj._attackedThisTickTempVariable = true;
if (didHit) {
let tmpObjects = objectManager.hitObj;
objectManager.hitObj = [];
game.tickBase(() => {
// refind
tmpObj = findPlayerBySID(sid);
let val = items.weapons[index].dmg *
(config.weaponVariants[tmpObj[(index < 9 ? "prima" : "seconda") +
"ryVariant"]].val) * (items.weapons[index].sDmg || 1) * (tmpObj.skinIndex == 40 ?
3.3 : 1);
tmpObjects.forEach((healthy) => {
healthy.health -= val;
//textManager.showText(healthy.x, healthy.y, 20, 0, 500,
Math.abs(val.toString().includes(".") ? Utils.fixTo(val, 3) : val), "#f00", true);
});
}, 1);
}
}
}
tmpCanvas.width*tmpMlt*tmpPad*config.iconPad,
tmpCanvas.height*tmpMlt*config.iconPad);
tmpContext.fillStyle = "rgba(0, 0, 70, 0.1)";
tmpContext.globalCompositeOperation = "source-atop";
tmpContext.fillRect(-tmpCanvas.width / 2, -tmpCanvas.height /
2, tmpCanvas.width, tmpCanvas.height);
getEl('actionBarItem' + i).style.backgroundImage = "url(" +
tmpCanvas.toDataURL() + ")";
};
tmpSprite.src = "./../img/weapons/" + items.weapons[i].src +
".png";
let tmpUnit = getEl('actionBarItem' + i);
tmpUnit.onmouseover = Utils.checkTrusted(function() {
showItemInfo(items.weapons[i], true);
});
tmpUnit.onclick = Utils.checkTrusted(function() {
selectWeapon(tmpObj.weapons[items.weapons[i].type]);
});
Utils.hookTouchEvents(tmpUnit);
} else {
let tmpSprite = renderPlayerObject(items.list[i-
items.weapons.length], true);
let tmpScale = Math.min(tmpCanvas.width - config.iconPadding,
tmpSprite.width);
tmpContext.globalAlpha = 1;
tmpContext.drawImage(tmpSprite, -tmpScale / 2, -tmpScale / 2,
tmpScale, tmpScale);
tmpContext.fillStyle = "rgba(0, 0, 70, 0.1)";
tmpContext.globalCompositeOperation = "source-atop";
tmpContext.fillRect(-tmpScale / 2, -tmpScale / 2, tmpScale,
tmpScale);
getEl('actionBarItem' + i).style.backgroundImage = "url(" +
tmpCanvas.toDataURL() + ")";
let tmpUnit = getEl('actionBarItem' + i);
tmpUnit.onmouseover = Utils.checkTrusted(function() {
showItemInfo(items.list[i - items.weapons.length]);
});
tmpUnit.onclick = Utils.checkTrusted(function() {
selectToBuild(tmpObj.items[tmpObj.getItemType(i -
items.weapons.length)]);
});
Utils.hookTouchEvents(tmpUnit);
}
})(i);
}
};
function updateItems(data, wpn) {
if (data) {
if (wpn) {
player.weapons = data;
player.primaryIndex = player.weapons[0];
player.secondaryIndex = player.weapons[1];
if (!instaC.isTrue) {
selectWeapon(player.weapons[0]);
}
} else {
player.items = data;
}
}
for (let i = 0; i < items.list.length; i++) {
let tmpI = items.weapons.length + i;
getEl("actionBarItem" + tmpI).style.display =
player.items.indexOf(items.list[i].id) >= 0 ? "inline-block" : "none";
}
for (let i = 0; i < items.weapons.length; i++) {
getEl("actionBarItem" + i).style.display =
player.weapons[items.weapons[i].type] == items.weapons[i].id ? "inline-block" :
"none";
}
}
function addProjectile(x, y, dir, range, speed, indx, layer, sid) {
projectileManager.addProjectile(x, y, dir, range, speed, indx, null, null,
layer, inWindow).sid = sid;
runAtNextTick.push(Array.prototype.slice.call(arguments));
setAdvCooldown(x, y, dir, range, speed)
}
function setAdvCooldown(e, t, n, i, r) {
let min = Infinity;
let id = -1;
for (let i = 0; i < players.length; i++) {
(tmpObj = players[i]) && tmpObj.visible && tmpObj.secondaryIndex &&
items.weapons[tmpObj.secondaryIndex].projectile !== undefined &&
items.projectiles[items.weapons[tmpObj.secondaryIndex].projectile].speed == r &&
min > (tmpObj.x2 * 1.5 - tmpObj.x1 / 2 - e + Math.cos(n) * 80) ** 2 +
(tmpObj.y2 * 1.5 - tmpObj.y1 / 2 - t + Math.sin(n) * 80) ** 2
&& (id = tmpObj.sid, min = (tmpObj.x2 * 1.5 - tmpObj.x1 / 2 - e +
Math.cos(n) * 80) ** 2 + (tmpObj.y2 * 1.5 - tmpObj.y1 / 2 - t + Math.sin(n) * 80)
** 2)
}
if (Math.sqrt(min) > 60) {
if (r == 1.5) {
for (let i = 0; i < players.length; i++) {
(tmpObj = players[i]) && tmpObj.visible &&
min > (tmpObj.x2 * 1.5 - tmpObj.x1 / 2 - e + Math.cos(n) * 10)
** 2 + (tmpObj.y2 * 1.5 - tmpObj.y1 / 2 - t + Math.sin(n) * 10) ** 2
&& (id = tmpObj.sid, min = (tmpObj.x2 * 1.5 - tmpObj.x1 / 2 - e +
Math.cos(n) * 10) ** 2 + (tmpObj.y2 * 1.5 - tmpObj.y1 / 2 - t + Math.sin(n) * 10)
** 2)
}
if (Math.sqrt(min) < 60) {
tmpObj.turretReload = -0.0444;
}
} else {
for (let i = 0; i < players.length; i++) {
(tmpObj = players[i]) && tmpObj.visible && tmpObj.secondaryIndex &&
min > (tmpObj.x2 * 1.5 - tmpObj.x1 / 2 - e + Math.cos(n) * 80)
** 2 + (tmpObj.y2 * 1.5 - tmpObj.y1 / 2 - t + Math.sin(n) * 80) ** 2
&& (id = tmpObj.sid, min = (tmpObj.x2 * 1.5 - tmpObj.x1 / 2 - e +
Math.cos(n) * 80) ** 2 + (tmpObj.y2 * 1.5 - tmpObj.y1 / 2 - t + Math.sin(n) * 80)
** 2)
}
tmpObj = findPlayerBySID(id);
setTimeout(() => {
tmpObj.secondaryReload = 0
});
}
} else {
if (id != -1) {
tmpObj = findPlayerBySID(id);
tmpObj.secondaryReload = -game.tickRate /
items.weapons[tmpObj.secondaryIndex].speed;
}
}
}
function remProjectile(sid, range) {
for (let i = 0; i < projectiles.length; ++i) {
if (projectiles[i].sid == sid) {
projectiles[i].range = range;
let tmpObjects = objectManager.hitObj;
objectManager.hitObj = [];
game.tickBase(() => {
let val = projectiles[i].dmg;
tmpObjects.forEach((healthy) => {
if (healthy.projDmg) {
healthy.health -= val;
}
});
}, 1);
}
}
}
function setPlayerTeam(team, isOwner) {
if (player) {
player.team = team;
player.isOwner = isOwner;
if (team == null)
alliancePlayers = [];
}
}
function setAlliancePlayers(data) {
alliancePlayers = data;
}
function updateStoreItems(type, id, index) {
if (index) {
if (!type)
player.tails[id] = 1;
else {
player.latestTail = id;
}
} else {
if (!type) {
player.skins[id] = 1
} else {
player.latestSkin = id;
}
}
}
function receiveChat(sid, message) {
var tmpPlayer = findPlayerBySID(sid);
if (tmpPlayer) {
addMenuChText(`${tmpPlayer.name} {${tmpPlayer.sid}}`, message, "white");
tmpPlayer.chatMessage = message;
tmpPlayer.chatCountdown = config.chatCountdown;
if (!tmpPlayer.chatMessages) {
tmpPlayer.chatMessages = [];
}
tmpPlayer.chatMessages.push({ message: message, time: Date.now(), alpha:
1 }); // so it will save and stack message
if (tmpPlayer.chatMessages.length > 3) {
tmpPlayer.chatMessages.shift(); // remove oldest chat
}
} else {
addMenuChText(`${"Anonymous"} {null}`, message, "white");
}
}
function updateMinimap(data) {
minimapData = data;
}
function showText(x, y, value, type) {
if (!getEl("rendertxt").checked) return
if (getEl("stack").checked) {
textManager.stack.push({x: x, y: y, value: value});
} else {
textManager.showText(x, y, 50, 0.18, 1500, Math.abs(value),
(value>=0)?"#fff":"#8ecc51");
}
}
function renderLeaf(x, y, l, r, ctxt) {
let endX = x + (l * Math.cos(r));
let endY = y + (l * Math.sin(r));
let width = l * 0.4;
ctxt.moveTo(x, y);
ctxt.beginPath();
ctxt.quadraticCurveTo(((x + endX) / 2) + (width * Math.cos(r + Math.PI / 2)),
((y + endY) / 2) + (width * Math.sin(r + Math.PI / 2)),
endX, endY);
ctxt.quadraticCurveTo(((x + endX) / 2) - (width * Math.cos(r + Math.PI / 2)),
((y + endY) / 2) - (width * Math.sin(r + Math.PI / 2)),
x, y);
ctxt.closePath();
ctxt.fill();
ctxt.stroke();
}
items.projectiles[items.weapons[obj.weaponIndex].projectile], mainContext);
}
}
ctxt.fillStyle = config.skinColors[obj.skinColor];
renderCircle(obj.scale * Math.cos(handAngle), (obj.scale *
Math.sin(handAngle)), 14);
renderCircle((obj.scale * oHandDist) * Math.cos(-handAngle * oHandAngle),
(obj.scale * oHandDist) * Math.sin(-handAngle * oHandAngle), 14);
if (obj.buildIndex < 0 && items.weapons[obj.weaponIndex].aboveHand) {
renderTool(items.weapons[obj.weaponIndex],
config.weaponVariants[obj.weaponVariant].src, obj.scale, 0, ctxt);
if (items.weapons[obj.weaponIndex].projectile != undefined && !
items.weapons[obj.weaponIndex].hideProjectile) {
renderProjectile(obj.scale, 0,
items.projectiles[items.weapons[obj.weaponIndex].projectile], mainContext);
}
}
if (obj.buildIndex >= 0) {
let tmpSprite = renderPlayerObject(items.list[obj.buildIndex]);
ctxt.drawImage(tmpSprite, obj.scale -
items.list[obj.buildIndex].holdOffset, -tmpSprite.width / 2);
}
renderCircle(0, 0, obj.scale, ctxt);
if (obj.skinIndex > 0) {
ctxt.rotate(Math.PI/2);
renderSkin(obj.skinIndex, ctxt, null, obj);
}
}
let skinSprites = {};
let skinPointers = {};
let tmpSkin;
function renderSkin(index, ctxt, parentSkin, owner) {
tmpSkin = skinSprites[index];
if (!tmpSkin) {
let tmpImage = new Image();
tmpImage.onload = function() {
this.isLoaded = true;
this.onload = null;
};
tmpImage.src = "https://moomoo.io/img/hats/hat_" + index + ".png";
skinSprites[index] = tmpImage;
tmpSkin = tmpImage;
}
let tmpObj = parentSkin || skinPointers[index];
if (!tmpObj) {
for (let i = 0; i < hats.length; ++i) {
if (hats[i].id == index) {
tmpObj = hats[i];
break;
}
}
skinPointers[index] = tmpObj;
}
if (tmpSkin.isLoaded) ctxt.drawImage(tmpSkin, -tmpObj.scale / 2, -
tmpObj.scale / 2, tmpObj.scale, tmpObj.scale);
if (!parentSkin && tmpObj.topSprite) {
ctxt.save();
ctxt.globalAlpha = .7;
ctxt.rotate(owner.skinRot);
renderSkin(index + "_top", ctxt, tmpObj, owner);
ctxt.restore();
}
}
let accessSprites = {};
let accessPointers = {};
let txt = true;
function renderTail(index, ctxt, owner) {
tmpSkin = accessSprites[index];
if (!tmpSkin) {
let tmpImage = new Image();
tmpImage.onload = function() {
this.isLoaded = true;
this.onload = null;
};
tmpImage.src = "https://moomoo.io/img/accessories/access_" + index +
".png";
accessSprites[index] = tmpImage;
tmpSkin = tmpImage;
}
let tmpObj = accessPointers[index];
if (!tmpObj) {
for (let i = 0; i < accessories.length; ++i) {
if (accessories[i].id == index) {
tmpObj = accessories[i];
break;
}
}
accessPointers[index] = tmpObj;
}
if (tmpSkin.isLoaded) {
ctxt.save();
ctxt.translate(-20 - (tmpObj.xOff || 0), 0);
if (tmpObj.spin) ctxt.rotate(owner.skinRot);
ctxt.drawImage(tmpSkin, -(tmpObj.scale / 2), -(tmpObj.scale / 2),
tmpObj.scale, tmpObj.scale);
ctxt.restore();
}
}
let toolSprites = {};
function renderTool(obj, variant, x, y, ctxt) {
let tmpSrc = obj.src + (variant||"");
let tmpSprite = toolSprites[tmpSrc];
if (!tmpSprite) {
tmpSprite = new Image();
tmpSprite.onload = function() {
this.isLoaded = true;
}
tmpSprite.src = ".././img/weapons/" + tmpSrc + ".png";
toolSprites[tmpSrc] = tmpSprite;
}
if (tmpSprite.isLoaded) ctxt.drawImage(tmpSprite, x+obj.xOff-(obj.length/2),
y+obj.yOff-(obj.width/2), obj.length, obj.width);
}
//tmpContext.shadowBlur = null;
//tmpContext.shadowColor = null;
tmpContext.fillStyle = "#89a54c";
renderCircle(0, 0, obj.scale * 0.55, tmpContext);
tmpContext.fillStyle = "#a5c65b";
renderCircle(0, 0, obj.scale * 0.3, tmpContext, true);
} else {
renderBush(tmpContext, 6, tmpObj.scale, tmpObj.scale * 0.7);
tmpContext.fillStyle = biomeID ? "#e3f1f4" : "#89a54c";
tmpContext.fill();
tmpContext.stroke();
//tmpContext.shadowBlur = null;
//tmpContext.shadowColor = null;
maxScreenHeight));
}
if (tmpObj.blocker) {
mainContext.strokeStyle = "#db6e6e";
mainContext.globalAlpha = 0.3;
mainContext.lineWidth = 6;
renderCircle(0, 0, tmpObj.blocker, mainContext, false,
true);
}
mainContext.restore();
} else {
CHv4Tree(tmpObj, tmpX, tmpY);
tmpSprite = getResSprite(tmpObj);
mainContext.drawImage(tmpSprite, tmpX - (tmpSprite.width / 2),
tmpY - (tmpSprite.height / 2));
}
}
if (!tmpObj.alive && tmpObj.alpha > 0) {
tmpObj.alpha -= 0.01;
}
if (layer == 3 && inGame && getEl("buildhp").checked) {
if (tmpObj.active && tmpObj.health > 0) {
if (tmpObj.health < tmpObj.maxHealth && Utils.getDist(tmpObj,
player, 0, 2) <= 400) {
// HEALTH HOLDER:
mainContext.fillStyle = darkOutlineColor;
mainContext.roundRect(tmpX - config.healthBarWidth / 2 -
config.healthBarPad, tmpY - config.healthBarPad, config.healthBarWidth +
config.healthBarPad * 2, 17, 8);
mainContext.fill();
// HEALTH BAR:
mainContext.fillStyle = !tmpObj.isTeamObject(player) ?
"#C12D5F" : "#2187C0";
mainContext.roundRect(tmpX - config.healthBarWidth / 2,
tmpY, config.healthBarWidth * (tmpObj.health / tmpObj.maxHealth), 17 -
config.healthBarPad * 2, 7);
mainContext.fill();
}
if (Utils.getDist(tmpObj, player, 0, 2) <= 400) {
// PLAYER SID OWNER
mainContext.font = "16px Hammersmith One";
mainContext.fillStyle = !tmpObj.isTeamObject(player) ?
"#C12D5F" : "#2187C0";
mainContext.textBaseline = "middle";
mainContext.textAlign = "center";
mainContext.strokeStyle = "#000";
mainContext.lineWidth = 8;
mainContext.lineJoin = "round";
mainContext.strokeText(tmpObj.owner.sid, tmpObj.x -
xOffset, (tmpObj.y - yOffset + 30));
mainContext.fillText(tmpObj.owner.sid, tmpObj.x - xOffset,
(tmpObj.y - yOffset + 30));
}
}
}
}
});
if (layer == 0) {
if (showPlace.length) {
showPlace.forEach((places) => {
tmpX = places.x - xOffset;
tmpY = places.y - yOffset;
markObject(places, tmpX, tmpY);
});
}
}
}
function renderPhantomObject(obj, tmpContext, tmpX, tmpY) {
tmpContext.lineWidth = 3;
tmpContext.globalAlpha = 1;
tmpContext.strokeStyle = outlineColor;
tmpContext.save();
tmpContext.translate(tmpX, tmpY);
tmpContext.rotate(obj.dir);
if (obj.name == "wood wall" || obj.name == "stone wall" || obj.name == "castle
wall") {
let sides = obj.name == "castle wall" ? 4 : 3;
renderHealthStar(tmpContext, sides, obj.scale * 1.1, obj.scale * 1.1);
tmpContext.stroke();
} else if (obj.name == "spikes" || obj.name == "greater spikes" || obj.name ==
"poison spikes" || obj.name == "spinning spikes") {
let tmpScale = obj.scale * 0.6;
renderHealthStar(tmpContext, obj.name == "spikes" ? 5 : 6, obj.scale,
tmpScale);
tmpContext.stroke();
} else if (obj.name == "windmill" || obj.name == "faster windmill" || obj.name
== "power mill") {
renderHealthCircle(0, 0, obj.scale, tmpContext, false, true);
} else if (obj.name == "mine") {
renderHealthStar(tmpContext, 3, obj.scale, obj.scale);
tmpContext.stroke();
} else if (obj.name == "sapling") {
let tmpScale = obj.scale * 0.7;
renderHealthStar(tmpContext, 7, obj.scale, tmpScale);
tmpContext.stroke();
} else if (obj.name == "pit trap") {
renderHealthStar(tmpContext, 3, obj.scale * 1.1, obj.scale * 1.1);
tmpContext.stroke();
} else if (obj.name == "boost pad") {
renderHealthRect(0, 0, obj.scale * 2, obj.scale * 2, tmpContext, false,
true);
} else if (obj.name == "turret") {
renderHealthCircle(0, 0, obj.scale, tmpContext, false, true);
} else if (obj.name == "platform") {
renderHealthRect(0, 0, obj.scale * 2, obj.scale * 2, tmpContext, false,
true);
} else if (obj.name == "healing pad") {
renderHealthRect(0, 0, obj.scale * 2, obj.scale * 2, tmpContext, false,
true);
} else if (obj.name == "spawn pad") {
renderHealthRect(0, 0, obj.scale * 2, obj.scale * 2, tmpContext, false,
true);
} else if (obj.name == "blocker") {
renderHealthCircle(0, 0, obj.scale, tmpContext, false, true);
} else if (obj.name == "teleporter") {
renderHealthCircle(0, 0, obj.scale, tmpContext, false, true);
}
tmpContext.fillStyle = "rgba(0, 0, 0, 0.2)"
tmpContext.fill();
tmpContext.restore();
}
function markObject(tmpObj, tmpX, tmpY) {
if (tmpObj.isPreplacer) {
yen(tmpObj, tmpX, tmpY);
} else {
renderPhantomObject(tmpObj, mainContext, tmpX, tmpY);
}
}
function yen(tmpObj, x, y) {
mainContext.fillStyle = /spik/.test(tmpObj.name) ? "rgba(255, 0, 0, 0.6)" :
"rgba(0, 255, 255, 0.6)";
mainContext.beginPath();
mainContext.arc(x, y, 55, 0, Math.PI * 2);
mainContext.fill();
mainContext.closePath();
mainContext.globalAlpha = 1;
}
function MapPing(color, scale) {
let mapPing = {
init: function (x, y) {
this.scale = 0;
this.x = x;
this.y = y;
this.active = true;
},
update: function (ctxt, delta) {
if (this.active) {
this.scale += 0.05 * delta;
if (this.scale >= scale) {
this.active = false;
} else {
ctxt.globalAlpha = (1 - Math.max(0, this.scale / scale));
ctxt.beginPath();
ctxt.arc((this.x / config.mapScale) * mapDisplay.width, (this.y
/ config.mapScale)
* mapDisplay.width, this.scale, 0, 2 * Math.PI);
ctxt.stroke();
}
}
},
color: color
};
return mapPing;
}
function pingMap(x, y) {
tmpPing = mapPings.find(pings => !pings.active);
if (!tmpPing) {
tmpPing = new MapPing("#fff", config.mapPingScale);
mapPings.push(tmpPing);
}
tmpPing.init(x, y);
}
function updateMapMarker() {
mapMarker.x = player.x;
mapMarker.y = player.y;
}
function renderMinimap(delta) {
if (player && player.alive) {
mapContext.clearRect(0, 0, mapDisplay.width, mapDisplay.height);
mapContext.lineWidth = 4;
for (let i = 0; i < mapPings.length; ++i) {
tmpPing = mapPings[i];
mapContext.strokeStyle = tmpPing.color;
tmpPing.update(mapContext, delta);
}
mapContext.globalAlpha = 1;
mapContext.fillStyle = "#ff0000";
mapContext.globalAlpha = 1;
mapContext.fillStyle = "#fff";
renderCircle((player.x/config.mapScale)*mapDisplay.width,
(player.y/config.mapScale)*mapDisplay.height, 7, mapContext,
true);
mapContext.fillStyle = "rgba(255,255,255,0.35)";
if (player.team && minimapData) {
for (let i = 0; i < minimapData.length;) {
renderCircle((minimapData[i]/config.mapScale)*mapDisplay.width,
(minimapData[i+1]/config.mapScale)*mapDisplay.height,
7, mapContext, true);
i+=2;
}
}
if (lastDeath) {
mapContext.fillStyle = "#fc5553";
mapContext.font = "34px Hammersmith One";
mapContext.textBaseline = "middle";
mapContext.textAlign = "center";
mapContext.fillText("x",
(lastDeath.x/config.mapScale)*mapDisplay.width,
(lastDeath.y/config.mapScale)*mapDisplay.height);
}
if (mapMarker) {
mapContext.fillStyle = "#fff";
mapContext.font = "34px Hammersmith One";
mapContext.textBaseline = "middle";
mapContext.textAlign = "center";
mapContext.fillText("x",
(mapMarker.x/config.mapScale)*mapDisplay.width,
(mapMarker.y/config.mapScale)*mapDisplay.height);
}
}
}
let crossHairs = [
"https://upload.wikimedia.org/wikipedia/commons/9/95/Crosshairs_Red.svg",
"https://upload.wikimedia.org/wikipedia/commons/9/95/Crosshairs_Red.svg",
"https://upload.wikimedia.org/wikipedia/commons/9/95/Crosshairs_Red.svg",
"https://upload.wikimedia.org/wikipedia/commons/9/95/Crosshairs_Red.svg" //
https://media.discordapp.net/attachments/1204579824190890036/1215749681813000253/
image_2024-03-08_145454224-removebg-preview.png?
ex=65fde21f&is=65eb6d1f&hm=05d452595878eecbb1dfefb660186f3e3a6337f554064f1b39b5b59e
7b308d58&=&format=webp&quality=lossless&width=633&height=610
];
let crossHairSprites = {};
let iconSprites = {
crown: new Image(),
skull: new Image(),
trust: new Image()
};
function loadIcons() {
iconSprites.crown.onload = function () {
this.isLoaded = true;
};
iconSprites.crown.src = "./../img/icons/crown.png"; // https://cdn-icons-
png.flaticon.com/512/5556/5556657.png
iconSprites.skull.onload = function () {
this.isLoaded = true;
};
iconSprites.skull.src = "./../img/icons/skull.png";
iconSprites.trust.onload = function () {
this.isLoaded = true;
};
iconSprites.trust.src =
"https://media.discordapp.net/attachments/904703116404998196/921671387716931625/
trust-icon-png-17.jpg?width=494&height=494";
for (let i = 0; i < crossHairs.length; ++i) {
let tmpSprite = new Image();
tmpSprite.onload = function () {
this.isLoaded = true;
};
tmpSprite.src = crossHairs[i];
crossHairSprites[i] = tmpSprite;
}
}
loadIcons();
var renderVolcano = (x, y) => {
let offsetX = x, offsetY = y;
config.volcano.animationTime += config.volcano.animationSpeed;
config.volcano.animationTime %= config.volcano.AnimDuration;
let halfDuration = config.volcano.AnimDuration / 2;
let scaleMultiplier = 1.7 + 0.3 * (Math.abs(halfDuration -
config.volcano.animationTime) / halfDuration);
let innerLavaScale = config.volcano.innerScale * scaleMultiplier;
let centerX = config.volcano.x - offsetX, centerY = config.volcano.y - offsetY;
renderPolygon(mainContext, 8, config.volcano.outerScale, centerX, centerY,
"#7f7f7f", darkOutlineColor, 6);//this outervac
renderPolygon(mainContext, 8, innerLavaScale, centerX, centerY, "#f54e16",
"#f56f16", 20);//this inner Lava!
};
let postTickTime = 0;
function updateGame() {
asura.FPS++;
setTimeout(() => {
asura.FPS--;
}, 1000);
if(gameObjects.length && inGame) {
gameObjects.forEach((tmp) => {
if(Utils.getDistance(tmp.x, tmp.y, player.x, player.y) <= 1400) {
if(!objects.includes(tmp)) {
objects.push(tmp);
tmp.render = true;
}
} else {
if(objects.includes(tmp)) {
if(Utils.getDistance(tmp.x, tmp.y, player.x, player.y) >= 1400)
{
tmp.render = false;
const index = objects.indexOf(tmp);
if (index > -1) { // only splice array when item is found
objects.splice(index, 1); // 2nd parameter means remove
one item only
}
}
} else if(Utils.getDistance(tmp.x, tmp.y, player.x, player.y) >=
1400) {
tmp.render = false;
const index = objects.indexOf(tmp);
if (index > -1) { // only splice array when item is found
objects.splice(index, 1); // 2nd parameter means remove one
item only
}
} else {
tmp.render = false;
const index = objects.indexOf(tmp);
if (index > -1) { // only splice array when item is found
objects.splice(index, 1); // 2nd parameter means remove one
item only
}
}
}
})
}
if (true) {
if (player) {
if (false) {
camX = player.x;
camY = player.y;
} else {
let tmpDist = Utils.getDistance(camX, camY, player.x, player.y);
let tmpDir = Utils.getDirection(player.x, player.y, camX, camY);
let camSpd = Math.min(tmpDist * 0.01 * delta, tmpDist);
if (tmpDist > 0.05) {
camX += camSpd * Math.cos(tmpDir);
camY += camSpd * Math.sin(tmpDir);
} else {
camX = player.x;
camY = player.y;
}
}
} else {
camX = config.mapScale / 2;
camY = config.mapScale / 2;
}
/*if (true) {
const originalScales = {
width: 1920,
height: 1080
};
if (player) {
let targetScreenWidth, targetScreenHeight;
const smoothness = 0.05;
const isCloseToPlayer = near.dist2 <= 1000 && inGame;
const px = player.x;
const py = player.y;
if (isCloseToPlayer) {
targetScreenWidth = originalScales.width;
targetScreenHeight = originalScales.height;
} else {
targetScreenWidth = originalScales.width * 1.4;
targetScreenHeight = originalScales.height * 1.4;
}
maxScreenWidth += (targetScreenWidth - maxScreenWidth) * smoothness;
maxScreenHeight += (targetScreenHeight - maxScreenHeight) * smoothness;
camX = (camX * 24 + px) / 25;
camY = (camY * 24 + py) / 25;
resize();
} else {
camX = config.mapScale / 2;
camY = config.mapScale / 2;
}*/
resize();
const lastTime = now - (1000 / config.serverUpdateRate);
let tmpDiff;
for (let i = 0; i < players.length + ais.length; i++) {
const tmpObj = players[i] || ais[i - players.length];
if (tmpObj && tmpObj.visible) {
if (tmpObj.forcePos) {
tmpObj.x = tmpObj.x2;
tmpObj.y = tmpObj.y2;
tmpObj.dir = tmpObj.d2;
} else {
const total = tmpObj.t2 - tmpObj.t1;
const fraction = lastTime - tmpObj.t1;
const ratio = fraction / total;
const rate = 170;
tmpObj.dt += delta;
const tmpRate = Math.min(1.7, tmpObj.dt / rate);