Skip to content
This repository was archived by the owner on Nov 28, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"name": "Open Source Arras",
"name": "open-source-arras",
"version": "1.0.0",
"main": "server/index.js",
"scripts": {
"startOptimized": "node --optimize-for-size --no-lazy --gc_interval=120 server/index",
"restartOnSaveOptimized": "node --optimize-for-size --no-lazy --gc_interval=120 --watch server/index",
"startOptimized": "node --no-lazy server/index",
"restartOnSaveOptimized": "node --no-lazy --watch server/index",
"start": "node server/index",
"restartOnSave": "node --watch server/index",
"host": "node standaloneClient/index",
Expand Down
2 changes: 1 addition & 1 deletion public/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,7 @@ function startGame() {
}
// initialize canvas.
window.canvas.socket = global.socket;
setInterval(() => moveCompensation.iterate(global.motion), 1000 / 30);
setInterval(() => moveCompensation.iterate(global.motion), 1000 / 40);
canvas.init();
document.getElementById("gameCanvas").focus();
window.onbeforeunload = () => true;
Expand Down
42 changes: 26 additions & 16 deletions public/lib/gameDraw.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,33 @@ var gameDraw = {
hex2decimal: (h) => {
return parseInt(h, 16);
}, // convert a hex value to decimal
mixColors: (color_2, color_1, weight = 0.5) => {
if (weight === 1) return color_1;
if (weight === 0) return color_2;
var col = "#";
for (var i = 1; i <= 6; i += 2) {
// loop through each of the 3 hex pairs—red, green, and blue, skip the '#'
var v1 = gameDraw.hex2decimal(color_1.substr(i, 2)), // extract the current pairs
v2 = gameDraw.hex2decimal(color_2.substr(i, 2)),
// combine the current pairs from each source color, according to the specified weight
val = gameDraw.decimal2hex(Math.floor(v2 + (v1 - v2) * weight));
while (val.length < 2) {
val = "0" + val;
} // prepend a '0' if val results in a single digit
col += val; // concatenate val to our new color string
mixColors: (function () {
const mixCache = new Map();
const intCache = new Map();
return function mixColor(hex1, hex2, mix = 0.5) {
let c1 = intCache.get(hex1);
if (c1 === undefined) {
c1 = parseInt(hex1.slice(1), 16);
intCache.set(hex1, c1);
}
let c2 = intCache.get(hex2);
if (c2 === undefined) {
c2 = parseInt(hex2.slice(1), 16);
intCache.set(hex2, c2);
}
const key = c1 * (1 << 29) + c2 * (1 << 5) + Math.round(mix * 31);
if (mixCache.has(key)) {
return mixCache.get(key);
}
const r1 = (c1 >> 16) & 0xFF;
const g1 = (c1 >> 8) & 0xFF;
const b1 = c1 & 0xFF;
const result = ((1 << 24) | (((r1 + (((c2 >> 16) & 0xFF) - r1) * mix) | 0) << 16) | (((g1 + (((c2 >> 8) & 0xFF) - g1) * mix) | 0) << 8) | ((b1 + ((c2 & 0xFF) - b1) * mix) | 0));
const hex = '#' + (result & 0xFFFFFF).toString(16).padStart(6, '0');
mixCache.set(key, hex);
return hex;
}
return col; // PROFIT!
},
})(),
hslToRgb: (h, s, l) => {
let r, g, b;
if (s === 0) {
Expand Down
4 changes: 2 additions & 2 deletions public/lib/socketInit.js
Original file line number Diff line number Diff line change
Expand Up @@ -517,8 +517,8 @@ const process = (z = {}) => {
lastRender: global.player.time,
x: z.x,
y: z.y,
lastx: z.x - global.metrics.rendergap * settings.roomSpeed * (1000 / 30) * z.vx,
lasty: z.y - global.metrics.rendergap * settings.roomSpeed * (1000 / 30) * z.vy,
lastx: z.x - global.metrics.rendergap * settings.roomSpeed * (1000 / 40) * z.vx,
lasty: z.y - global.metrics.rendergap * settings.roomSpeed * (1000 / 40) * z.vy,
lastvx: z.vx,
lastvy: z.vy,
lastf: z.facing,
Expand Down
140 changes: 69 additions & 71 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,7 @@ util.log(room.width + " x " + room.height + " room initalized.");

// Collision stuff
const auraCollideTypes = ["miniboss", "tank", "food", "crasher"]
function collide(collision) {
// Pull the two objects from the collision grid
let instance = collision[0],
other = collision[1];
function collide(instance, other) {
if (instance.noclip || other.noclip) {
return 0;
}
Expand All @@ -43,10 +40,9 @@ function collide(collision) {
util.error("x: " + other.x + " y: " + other.y);
util.error(other.collisionArray);
util.error("health: " + other.health.amount);
if (grid.checkIfInHSHG(other)) {
if (other.isInGrid) {
other.kill();
util.warn("Ghost removed.");
grid.removeObject(other);
}
return 0;
}
Expand All @@ -56,10 +52,9 @@ function collide(collision) {
util.error("x: " + instance.x + " y: " + instance.y);
util.error(instance.collisionArray);
util.error("health: " + instance.health.amount);
if (grid.checkIfInHSHG(instance)) {
if (instance.isInGrid) {
other.kill();
util.warn("Ghost removed.");
grid.removeObject(instance);
}
return 0;
}
Expand Down Expand Up @@ -106,10 +101,10 @@ function collide(collision) {
break;
case instance.team !== other.team ||
(instance.team === other.team &&
(
instance.healer ||
other.healer
)):
(
instance.healer ||
other.healer
)):
// Exits if the aura is not hitting a boss, tank, food, or crasher
if (instance.type === "aura") {
if (!(auraCollideTypes.includes(other.type))) return;
Expand Down Expand Up @@ -193,63 +188,61 @@ function collide(collision) {

// The most important loop. Lots of looping.
let ticks = 0;
const regenTickRate = Math.max(1, Math.round(room.regenerateTick / room.cycleSpeed));
const gameloop = () => {
logs.loops.tally();
logs.master.startTracking();
logs.activation.startTracking();
const isRegenTick = (ticks % regenTickRate === 0);
logs.activation.endTracking();
// Do collisions
logs.collide.startTracking();
if (entities.length > 1) {
// Load the grid
grid.update();
// Run collisions in each grid
const pairs = grid.queryForCollisionPairs();
for (let i = 0; i < pairs.length; i++) {
collide(pairs[i]);
logs.entities.startTracking();
grid.clear();
for (const instance of entities.values()) {
if (instance.contemplationOfMortality() === 1) {
instance.destroy();
continue;
}
if (isRegenTick) {
if (instance.shield.max) {
instance.shield.regenerate();
}
if (instance.health.max) {
instance.health.regenerate((instance.shield.max && instance.shield.max === instance.shield.amount) ? 1 : 0);
}
}
if (instance.activation.active || instance.isPlayer) {
if (instance.bond == null) {
instance.physics();
}
instance.friction();
instance.confinementToTheseEarthlyShackles();
}
instance.updateAABB(instance.activation.active);
if (instance.activation.active) {
grid.insert(instance, instance.minX, instance.minY, instance.maxX, instance.maxY);
}
}
logs.collide.endTracking();
// Do entities life
logs.entities.startTracking();
for (let my of entities) {
// Consider death.
if (my.contemplationOfMortality()) {
my.destroy();
} else {
if (my.activation.active || my.isPlayer) {
if (my.bond == null) {
// Resolve the physical behavior from the last collision cycle.
logs.physics.startTracking();
my.physics();
logs.physics.endTracking();
for (const instance of entities.values()) {
if (!instance.isDead() && (instance.activation.active || instance.isPlayer)) {
instance.life();
instance.collisionArray = [];
for (const other of grid.query(instance.minX, instance.minY, instance.maxX, instance.maxY).values()) {
if (instance.id !== other.id) {
collide(instance, other);
}
logs.entities.tally();
// Think about my actions.
logs.life.startTracking();
my.life();
logs.life.endTracking();
// Apply friction.
my.friction();
my.confinementToTheseEarthlyShackles();
logs.selfie.startTracking();
my.takeSelfie();
logs.selfie.endTracking();
}
// Update collisions.
my.collisionArray = [];
// Activation
my.activation.update();
my.updateAABB(my.activation.active);
}
// Update collisions.
my.collisionArray = [];
my.emit('tick', { body: my });
instance.activation.update();
instance.takeSelfie();
instance.emit('tick', { body: instance });
const tile = room.getAt(instance);
if (tile) {
tile.entities.push(instance);
}
}
logs.entities.endTracking();
logs.master.endTracking();
// Remove dead entities
purgeEntities();
room.lastCycle = performance.now();
ticks++;
if (ticks & 1) {
Expand All @@ -265,17 +258,6 @@ setTimeout(closeArena, 24 * 60 * 60 * 1000); // Restart every 2 hours
global.naturallySpawnedBosses = [];
global.bots = [];
let bossTimer = 0;
let regenerateHealthAndShield = () => {
for (let i = 0; i < entities.length; i++) {
let instance = entities[i];
if (instance.shield.max) {
instance.shield.regenerate();
}
if (instance.health.max) {
instance.health.regenerate(instance.shield.max && instance.shield.max === instance.shield.amount);
}
}
}
const maintainloop = () => {
// Update the grid
if (!naturallySpawnedBosses.length && bossTimer++ > Config.BOSS_SPAWN_COOLDOWN) {
Expand Down Expand Up @@ -315,7 +297,7 @@ const maintainloop = () => {
o.skill.score += Config.BOT_XP;
}
o.skill.maintain();
o.skillUp([ "atk", "hlt", "spd", "str", "pen", "dam", "rld", "mob", "rgn", "shi" ][ran.chooseChance(...Config.BOT_SKILL_UPGRADE_CHANCES)]);
o.skillUp(["atk", "hlt", "spd", "str", "pen", "dam", "rld", "mob", "rgn", "shi"][ran.chooseChance(...Config.BOT_SKILL_UPGRADE_CHANCES)]);
if (o.leftoverUpgrades && o.upgrade(ran.irandomRange(0, o.upgrades.length))) {
o.leftoverUpgrades--;
}
Expand Down Expand Up @@ -367,13 +349,29 @@ if (Config.REPL_WINDOW) {

// Bring it to life
let counter = 0;
setInterval(() => {
regenerateHealthAndShield();
}, room.regenerateTick);
setInterval(() => {
gameloop();
gamemodeLoop();
roomLoop();
for (let y = 0; y < room.setup.length; y++) {
for (let x = 0; x < room.setup[y].length; x++) {
let tile = room.setup[y][x];
tile.tick(tile);
tile.entities = [];
}
}

for (let y = 0; y < room.setup.length; y++) {
for (let x = 0; x < room.setup[y].length; x++) {
let tile = room.setup[y][x];
tile.tick(tile);
tile.entities = [];
}
}

if (room.sendColorsToClient) {
room.sendColorsToClient = false;
sockets.broadcastRoom();
}

if (counter++ / Config.runSpeed > 30) {
chatLoop();
Expand Down
Loading