SC CODE: // Copyright 2024. Civilware. All rights reserved.
// TELA Decentralized Web Document (TELA-DOC-1)
Function InitializePrivate() Uint64
10 IF init() == 0 THEN GOTO 30
20 RETURN 1
30 STORE("nameHdr", "game.js")
31 STORE("descrHdr", "Game JS file")
32 STORE("iconURLHdr", "")
33 STORE("dURL", "game.js")
34 STORE("docType", "TELA-JS-1")
35 STORE("subDir", "")
36 STORE("fileCheckC", "1d182cf0203cc9d836b0f41973279418c2d5562246c8210e5cbdf98fcd5187aa")
37 STORE("fileCheckS", "19f6eeb9f72b46542cff8dc23a0b8a1b66f859d79c485fbe356707a085771730")
100 RETURN 0
End Function
Function init() Uint64
10 IF EXISTS("owner") == 0 THEN GOTO 30
20 RETURN 1
30 STORE("owner", address())
50 STORE("docVersion", "1.0.0")
60 STORE("hash", HEX(TXID()))
70 STORE("likes", 0)
80 STORE("dislikes", 0)
100 RETURN 0
End Function
Function address() String
10 DIM s as String
20 LET s = SIGNER()
30 IF IS_ADDRESS_VALID(s) THEN GOTO 50
40 RETURN "anon"
50 RETURN ADDRESS_STRING(s)
End Function
Function Rate(r Uint64) Uint64
10 DIM addr as String
15 LET addr = address()
16 IF r < 100 && EXISTS(addr) == 0 && addr != "anon" THEN GOTO 30
20 RETURN 1
30 STORE(addr, ""+r+"_"+BLOCK_HEIGHT())
40 IF r < 50 THEN GOTO 70
50 STORE("likes", LOAD("likes")+1)
60 RETURN 0
70 STORE("dislikes", LOAD("dislikes")+1)
100 RETURN 0
End Function
/*const svg = document.getElementById("game");
const map = document.getElementById("map");
const hud = document.getElementById("hud");
let keys = {};
function startMission(mission) {
game = createInitialGameState();
scenario = {};
const scenarios = getScenario();
for (const key in scenarios) {
if (scenarios[key].id === mission) {
scenario = scenarios[key];
}
}
if (scenario == {}) return;
worldObjects = generateTerrain(scenario.seed);
game.bases = scenario.bases;
game.mission = mission;
if(scenario.StartX && scenario.StartY){
game.player.x = scenario.StartX;
game.player.y = scenario.StartY;
}
if(scenario.StartAngle){
game.player.angle = scenario.StartAngle * Math.PI / 180;
}
setState(STATE.PLAYING);
}
let levelSelector = 1;// for gp
function togglePause() {
if (game.state === STATE.PLAYING) {
game.state = STATE.PAUSED;
} else if (game.state === STATE.PAUSED) {
game.state = STATE.PLAYING;
}
}
let zoom = 1;
const WORLD_W = 5000;
const WORLD_H = 5000;
// pick a good size for minimap
const screenW = window.innerWidth;
const screenH = window.innerHeight;
const minimapSize = Math.min(screenW, screenH) * 0.25; // 25% of shortest side
map.style.width = minimapSize + "px";
map.style.height = minimapSize + "px";
const MAP_W = minimapSize;
const MAP_H = minimapSize;
const mapScaleX = MAP_W / WORLD_W;
const mapScaleY = MAP_H / WORLD_H;
const STATE = {
MENU: 0,
PLAYING: 1,
PAUSED: 2,
DEAD: 3,
WIN: 4,
GAMEOVER: 5
};
function createInitialGameState() {
return {
player: {
x: 2500,
y: 2500,
poly: [
// FRONT (facing right)
{x: 26.25, y: -20}, // top front corner
{x: 30, y: -8}, // pulled in point
{x: 33.75, y: 0}, // front tip
{x: 30, y: 8}, // pulled in point
{x: 26.25, y: 20}, // bottom front corner
// BACK (facing left)
{x: -33.75, y: 20}, // bottom back corner
{x: -28.75, y: 0}, // back notch
{x: -33.75, y: -20} // top back corner
],
angle: 0,
speed: 0.2,
hp: 100,
maxHp: 100,
ammo: 50,
maxAmmo: 50,
cooldown: 0,
//invuln: 0,
state: "alive",
turnInput:0,
moveInput:0,
turret: {
angle: 0,
turnSpeed:0.004,
offset: 0,
cooldown: 0,
poly: [
{x: -10, y: -5},
{x: 20, y: -5},
{x: 20, y: 5},
{x: -10, y: 5}
]
}
},
projectiles: [],
enemies: [],
particles: [],
bases: [],
time: 0
};
}
let game = createInitialGameState();
let scenario = {};
function getScenario() {
return {
forestSkirmish: {
id:1,
seed: 1337,
terrain: "forest",
mission: "Forrest Folley",
bases: [
{
x: 3000, y: 800, angle: 140, // center
poly: [ // vertices relative to center
{x:-80, y:-40},
{x: 80, y:-40},
{x: 80, y: 40},
{x:-80, y: 40}
],
hp: 200, spawnInterval: 45, maxEnemies: 10,
enemyTypes: ["chaser","strafer"]
},
{
x: 3000, y: 2800, angle: 140, // center
poly: [ // vertices relative to center
{x:-40, y:-30},
{x: 40, y:-30},
{x: 40, y: 0},
{x: 15, y: 0},
{x: 15, y: 30},
{x:-15, y: 30},
{x:-15, y: 0},
{x:-40, y: 0}
],
hp: 80, spawnInterval: 45, maxEnemies: 10,
enemyTypes: ["chaser"]
}
],
objective: "destroyBases"
},
desertGauntlet: {
id:2,
seed: 999,
terrain: "desert",
mission: "Desert Gauntlet",
StartAngle: 320,
bases: [
{
x: 1200, y: 800, angle: 0,
poly: [
{x:-60, y:-40},
{x: 60, y:-40},
{x: 60, y: 40},
{x:-60, y: 40}
],
hp: 80, spawnInterval: 90, maxEnemies: 5,
enemyTypes: ["chaser","strafer"]
},
{
x: 3000, y: 1800, angle: 20,
poly: [
{x:-40, y:-30},
{x: 40, y:-30},
{x: 40, y: 30},
{x: 0, y: 30},
{x: 0, y: 0},
{x:-40, y: 0}
],
hp: 100, spawnInterval: 60, maxEnemies: 5,
enemyTypes: ["chaser","tank"]
},
{
x: 1000, y: 2800, angle: 160,
poly: [
{x:-40, y:-30},
{x: 40, y:-30},
{x: 40, y: 20},
{x: 10, y: 30},
{x:-40, y: 30}
],
hp: 100, spawnInterval: 90, maxEnemies: 5,
enemyTypes: ["chaser","strafer","tank"]
}
],
objective: "destroyBases"
},
snowStorm: {
id:3,
seed: 234,
terrain: "snowy",
mission: "Snow Storm",
StartAngle: 250,
bases: [
{
x: 200, y: 800, angle: 0,
poly: [
{x:-60, y:-40},
{x: 60, y:-40},
{x: 60, y: 40},
{x:-60, y: 40}
],
hp: 80, spawnInterval: 60, maxEnemies: 5,
enemyTypes: ["chaser"]
},
{
x: 1000, y: 200, angle: 45,
poly: [
{x:-40, y:-30},
{x: 40, y:-30},
{x: 40, y: 30},
{x: 0, y: 30},
{x: 0, y: 0},
{x:-40, y: 0}
],
hp: 100, spawnInterval: 45, maxEnemies: 5,
enemyTypes: ["chaser","strafer"]
},
{
x: 1800, y: 800, angle: 160,
poly: [
{x:-40, y:-30},
{x: 40, y:-30},
{x: 40, y: 20},
{x: 10, y: 30},
{x:-40, y: 30}
],
hp: 100, spawnInterval: 45, maxEnemies: 5,
enemyTypes: ["chaser","tank"]
}
],
objective: "destroyBases"
},
underWorld: {
id:4,
seed: 772,
terrain: "rocky",
mission: "Battle Down Under",
StartX: 1000,
StartY: 4000,
bases: [
{
x: 2500, y: 2800, angle: 0,
poly: [
{x:-60, y:-40},
{x: 60, y:-40},
{x: 60, y: 40},
{x:-60, y: 40}
],
hp: 80, spawnInterval: 60, maxEnemies: 5,
enemyTypes: ["chaser"]
},
{
x: 2600, y: 2700, angle: 20,
poly: [
{x:-40, y:-30},
{x: 40, y:-30},
{x: 40, y: 30},
{x: 0, y: 30},
{x: 0, y: 0},
{x:-40, y: 0}
],
hp: 100, spawnInterval: 45, maxEnemies: 5,
enemyTypes: ["strafer"]
},
{
x: 2800, y: 2800, angle: 160,
poly: [
{x:-40, y:-30},
{x: 40, y:-30},
{x: 40, y: 20},
{x: 10, y: 30},
{x:-40, y: 30}
],
hp: 100, spawnInterval: 60, maxEnemies: 5,
enemyTypes: ["tank"]
},
{
x: 2500, y: 2500, angle: 130,
poly: [
{x:-80, y:-40},
{x: 80, y:-40},
{x: 80, y: 40},
{x:-80, y: 40}
],
hp: 200, spawnInterval: 60, maxEnemies: 10,
enemyTypes: ["chaser","strafer","tank"]
}
],
objective: "destroyBases"
}
};
};
//Enemies
const enemyTypes = {
chaser: {
speed: 0.08,
hp: 40,
fireRate: 500,
weight: 2,
poly: [
{x:-18, y:-12},
{x: 10, y:-12},
{x: 15, y: 0}, // nose
{x: 10, y: 12},
{x:-18, y: 12},
],
windshield: [
{x: 10, y: -8},
{x: 12, y: 0},
{x: 10, y: 8},
]
},
strafer: {
speed: 0.07,
hp: 60,
fireRate: 700,
weight: 3,
poly: [
{x:-28, y:-18},
{x: 22, y:-18},
{x: 28, y: 0}, // front wedge
{x: 22, y: 18},
{x:-28, y: 18}
],
windshield: [
{x: 20, y: -14},
{x: 22, y: 0},
{x: 20, y: 14},
]
},
tank: {
speed: 0.05,
hp: 150,
fireRate: 1200,
weight: 4,
poly: [
{x:-32, y:-22},
{x: 0, y:-22},
{x: 28, y:-10},
{x: 28, y: 10},
{x: 0, y: 22},
{x:-32, y: 22}
],
turretPoly: [
{x: -10, y: -5},
{x: 20, y: -5},
{x: 20, y: 5},
{x: -10, y: 5}
],
cooldown: 0,
turretTurnSpeed: 0.05,
hullTurnSpeed: 0.03,
idealRange: 350,
}
};
//Terrain
const treePoly={}
treePoly.forest = [
{x: 0, y: -28},
{x: 18, y: -20},
{x: 26, y: -5},
{x: 22, y: 12},
{x: 10, y: 24},
{x: -4, y: 28},
{x: -18, y: 22},
{x: -26, y: 10},
{x: -28, y: -4},
{x: -20, y: -18},
{x: -8, y: -26}
];
treePoly.desert = [
{x: -10, y: -40},
{x: -5, y: -10},
{x: -25, y: -10},
{x: -25, y: 20},
{x: -10, y: 20},
{x: -10, y: 40},
{x: 10, y: 40},
{x: 10, y: 20},
{x: 25, y: 20},
{x: 25, y: -10},
{x: 5, y: -10},
{x: 10, y: -40}
];
treePoly.snowy = [
{x: 0, y: -30}, // outer (top)
{x: 10, y: -18}, // inner (branch gap)
{x: 26, y: -10}, // outer (upper right)
{x: 16, y: -2}, // inner
{x: 24, y: 14}, // outer (right)
{x: 8, y: 20}, // inner
{x: -4, y: 28}, // outer (bottom)
{x: -14, y: 18}, // inner
{x: -26, y: 8}, // outer (left)
{x: -18, y: -4}, // inner
{x: -20, y: -20}, // outer (upper left)
{x: -8, y: -24} // inner
];
function makeFungalCap(radius, points = 12) {
const arr = [];
for (let i = 0; i < points; i++) {
const angle = (i / points) * Math.PI * 2;
let r = radius;
if (i % 3 === 0) r *= 1.2; // outward spike
if (i % 3 === 1) r *= 0.8; // inward dent
arr.push({
x: Math.cos(angle) * r,
y: Math.sin(angle) * r
});
}
return arr;
};
treePoly.rocky = makeFungalCap(40);
let rockPoly = [
{x: -20, y: -10},
{x: 10, y: -25},
{x: 25, y: -5},
{x: 15, y: 20},
{x: -15, y: 25},
{x: -30, y: 5}
];
let camCenter = { x: game.player.x, y: game.player.y };
let camLeft = 0;
let camTop = 0;
let camRight = 0;
let camBottom = 0;
let sw = 0;
let sh = 0;
let worldObjects = [];
function scalePoly(poly, s) {
return poly.map(p => ({ x: p.x * s, y: p.y * s }));
}
function mulberry32(a) {
return function() {
a |= 0; a = a + 0x6D2B79F5 | 0;
let t = Math.imul(a ^ a >>> 15, 1 | a);
t ^= t + Math.imul(t ^ t >>> 7, 61 | t);
return ((t ^ t >>> 14) >>> 0) / 4294967296;
}
}
function generateTerrain(seed = 12345) {
const randMul = mulberry32(seed);
function rand(min = 0, max = 1) {
return randMul() * (max - min) + min;
}
const objects = [];
for (let i = 0; i < 200; i++) {
const s = randMul(2, 1.5);
const angle = rand(0, Math.PI * 2);
objects.push({
type: "tree",
x: randMul() * WORLD_W,
y: randMul() * WORLD_H,
angle,
poly: scalePoly(treePoly[scenario.terrain], s),
hp: Math.ceil(s * 30)
});
}
for (let i = 0; i < 80; i++) {
const s = randMul(1, 1.4);
const angle = rand(0, Math.PI * 2);
objects.push({
type: "rock",
x: randMul() * WORLD_W,
y: randMul() * WORLD_H,
angle,
poly: scalePoly(rockPoly, s),
hp: Math.ceil(s * 60)
});
}
return objects;
}
const bgDefs={}
const bgColors={}
const treeColors={}
bgDefs.forest = `
<defs>
<filter id="forest">
<feTurbulence type="fractalNoise" baseFrequency="0.8" numOctaves="3" result="noise"/>
<feColorMatrix type="saturate" values="0"/>
<feBlend in="SourceGraphic" in2="noise" mode="multiply"/>
</filter>
</defs>`;
bgDefs.desert = `
<defs>
<filter id="desert">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" result="noise"/>
<feColorMatrix type="matrix" values="
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0" />
<feBlend in="SourceGraphic" in2="noise" mode="multiply"/>
</filter>
</defs>`;
bgDefs.snowy = `
<defs>
<filter id="snowy" x="0" y="0" width="100%" height="100%">
<feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="4" seed="234" result="noise"/>
<feColorMatrix type="matrix" values="
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 0.25 0" result="softNoise"/>
<feBlend in="SourceGraphic" in2="softNoise" mode="overlay"/>
</filter>
</defs>`;
bgDefs.rocky = `
<defs>
<filter id="rocky">
<feTurbulence type="fractalNoise" baseFrequency="0.8" numOctaves="4" />
<feColorMatrix type="matrix"
values="0.2 0 0 0 0
0 0.2 0 0 0
0 0 0.25 0 0
0 0 0 1 0" />
</filter>
</defs>`;
bgColors.forest = "#4a7f3a";
bgColors.desert = "#d8c28a";
bgColors.snowy = "#ffffff";
bgColors.rocky = "2b2b2e";
treeColors.forest = "green";
treeColors.desert = "green";
treeColors.snowy = "brown";
treeColors.rocky = "#3a3a3f";*/ |
| SC Arguments: [Name:SC_ACTION Type:uint64 Value:'1' Name:SC_CODE Type:string Value:'// Copyright 2024. Civilware. All rights reserved.
// TELA Decentralized Web Document (TELA-DOC-1)
Function InitializePrivate() Uint64
10 IF init() == 0 THEN GOTO 30
20 RETURN 1
30 STORE("nameHdr", "game.js")
31 STORE("descrHdr", "Game JS file")
32 STORE("iconURLHdr", "")
33 STORE("dURL", "game.js")
34 STORE("docType", "TELA-JS-1")
35 STORE("subDir", "")
36 STORE("fileCheckC", "1d182cf0203cc9d836b0f41973279418c2d5562246c8210e5cbdf98fcd5187aa")
37 STORE("fileCheckS", "19f6eeb9f72b46542cff8dc23a0b8a1b66f859d79c485fbe356707a085771730")
100 RETURN 0
End Function
Function init() Uint64
10 IF EXISTS("owner") == 0 THEN GOTO 30
20 RETURN 1
30 STORE("owner", address())
50 STORE("docVersion", "1.0.0")
60 STORE("hash", HEX(TXID()))
70 STORE("likes", 0)
80 STORE("dislikes", 0)
100 RETURN 0
End Function
Function address() String
10 DIM s as String
20 LET s = SIGNER()
30 IF IS_ADDRESS_VALID(s) THEN GOTO 50
40 RETURN "anon"
50 RETURN ADDRESS_STRING(s)
End Function
Function Rate(r Uint64) Uint64
10 DIM addr as String
15 LET addr = address()
16 IF r < 100 && EXISTS(addr) == 0 && addr != "anon" THEN GOTO 30
20 RETURN 1
30 STORE(addr, ""+r+"_"+BLOCK_HEIGHT())
40 IF r < 50 THEN GOTO 70
50 STORE("likes", LOAD("likes")+1)
60 RETURN 0
70 STORE("dislikes", LOAD("dislikes")+1)
100 RETURN 0
End Function
/*const svg = document.getElementById("game");
const map = document.getElementById("map");
const hud = document.getElementById("hud");
let keys = {};
function startMission(mission) {
game = createInitialGameState();
scenario = {};
const scenarios = getScenario();
for (const key in scenarios) {
if (scenarios[key].id === mission) {
scenario = scenarios[key];
}
}
if (scenario == {}) return;
worldObjects = generateTerrain(scenario.seed);
game.bases = scenario.bases;
game.mission = mission;
if(scenario.StartX && scenario.StartY){
game.player.x = scenario.StartX;
game.player.y = scenario.StartY;
}
if(scenario.StartAngle){
game.player.angle = scenario.StartAngle * Math.PI / 180;
}
setState(STATE.PLAYING);
}
let levelSelector = 1;// for gp
function togglePause() {
if (game.state === STATE.PLAYING) {
game.state = STATE.PAUSED;
} else if (game.state === STATE.PAUSED) {
game.state = STATE.PLAYING;
}
}
let zoom = 1;
const WORLD_W = 5000;
const WORLD_H = 5000;
// pick a good size for minimap
const screenW = window.innerWidth;
const screenH = window.innerHeight;
const minimapSize = Math.min(screenW, screenH) * 0.25; // 25% of shortest side
map.style.width = minimapSize + "px";
map.style.height = minimapSize + "px";
const MAP_W = minimapSize;
const MAP_H = minimapSize;
const mapScaleX = MAP_W / WORLD_W;
const mapScaleY = MAP_H / WORLD_H;
const STATE = {
MENU: 0,
PLAYING: 1,
PAUSED: 2,
DEAD: 3,
WIN: 4,
GAMEOVER: 5
};
function createInitialGameState() {
return {
player: {
x: 2500,
y: 2500,
poly: [
// FRONT (facing right)
{x: 26.25, y: -20}, // top front corner
{x: 30, y: -8}, // pulled in point
{x: 33.75, y: 0}, // front tip
{x: 30, y: 8}, // pulled in point
{x: 26.25, y: 20}, // bottom front corner
// BACK (facing left)
{x: -33.75, y: 20}, // bottom back corner
{x: -28.75, y: 0}, // back notch
{x: -33.75, y: -20} // top back corner
],
angle: 0,
speed: 0.2,
hp: 100,
maxHp: 100,
ammo: 50,
maxAmmo: 50,
cooldown: 0,
//invuln: 0,
state: "alive",
turnInput:0,
moveInput:0,
turret: {
angle: 0,
turnSpeed:0.004,
offset: 0,
cooldown: 0,
poly: [
{x: -10, y: -5},
{x: 20, y: -5},
{x: 20, y: 5},
{x: -10, y: 5}
]
}
},
projectiles: [],
enemies: [],
particles: [],
bases: [],
time: 0
};
}
let game = createInitialGameState();
let scenario = {};
function getScenario() {
return {
forestSkirmish: {
id:1,
seed: 1337,
terrain: "forest",
mission: "Forrest Folley",
bases: [
{
x: 3000, y: 800, angle: 140, // center
poly: [ // vertices relative to center
{x:-80, y:-40},
{x: 80, y:-40},
{x: 80, y: 40},
{x:-80, y: 40}
],
hp: 200, spawnInterval: 45, maxEnemies: 10,
enemyTypes: ["chaser","strafer"]
},
{
x: 3000, y: 2800, angle: 140, // center
poly: [ // vertices relative to center
{x:-40, y:-30},
{x: 40, y:-30},
{x: 40, y: 0},
{x: 15, y: 0},
{x: 15, y: 30},
{x:-15, y: 30},
{x:-15, y: 0},
{x:-40, y: 0}
],
hp: 80, spawnInterval: 45, maxEnemies: 10,
enemyTypes: ["chaser"]
}
],
objective: "destroyBases"
},
desertGauntlet: {
id:2,
seed: 999,
terrain: "desert",
mission: "Desert Gauntlet",
StartAngle: 320,
bases: [
{
x: 1200, y: 800, angle: 0,
poly: [
{x:-60, y:-40},
{x: 60, y:-40},
{x: 60, y: 40},
{x:-60, y: 40}
],
hp: 80, spawnInterval: 90, maxEnemies: 5,
enemyTypes: ["chaser","strafer"]
},
{
x: 3000, y: 1800, angle: 20,
poly: [
{x:-40, y:-30},
{x: 40, y:-30},
{x: 40, y: 30},
{x: 0, y: 30},
{x: 0, y: 0},
{x:-40, y: 0}
],
hp: 100, spawnInterval: 60, maxEnemies: 5,
enemyTypes: ["chaser","tank"]
},
{
x: 1000, y: 2800, angle: 160,
poly: [
{x:-40, y:-30},
{x: 40, y:-30},
{x: 40, y: 20},
{x: 10, y: 30},
{x:-40, y: 30}
],
hp: 100, spawnInterval: 90, maxEnemies: 5,
enemyTypes: ["chaser","strafer","tank"]
}
],
objective: "destroyBases"
},
snowStorm: {
id:3,
seed: 234,
terrain: "snowy",
mission: "Snow Storm",
StartAngle: 250,
bases: [
{
x: 200, y: 800, angle: 0,
poly: [
{x:-60, y:-40},
{x: 60, y:-40},
{x: 60, y: 40},
{x:-60, y: 40}
],
hp: 80, spawnInterval: 60, maxEnemies: 5,
enemyTypes: ["chaser"]
},
{
x: 1000, y: 200, angle: 45,
poly: [
{x:-40, y:-30},
{x: 40, y:-30},
{x: 40, y: 30},
{x: 0, y: 30},
{x: 0, y: 0},
{x:-40, y: 0}
],
hp: 100, spawnInterval: 45, maxEnemies: 5,
enemyTypes: ["chaser","strafer"]
},
{
x: 1800, y: 800, angle: 160,
poly: [
{x:-40, y:-30},
{x: 40, y:-30},
{x: 40, y: 20},
{x: 10, y: 30},
{x:-40, y: 30}
],
hp: 100, spawnInterval: 45, maxEnemies: 5,
enemyTypes: ["chaser","tank"]
}
],
objective: "destroyBases"
},
underWorld: {
id:4,
seed: 772,
terrain: "rocky",
mission: "Battle Down Under",
StartX: 1000,
StartY: 4000,
bases: [
{
x: 2500, y: 2800, angle: 0,
poly: [
{x:-60, y:-40},
{x: 60, y:-40},
{x: 60, y: 40},
{x:-60, y: 40}
],
hp: 80, spawnInterval: 60, maxEnemies: 5,
enemyTypes: ["chaser"]
},
{
x: 2600, y: 2700, angle: 20,
poly: [
{x:-40, y:-30},
{x: 40, y:-30},
{x: 40, y: 30},
{x: 0, y: 30},
{x: 0, y: 0},
{x:-40, y: 0}
],
hp: 100, spawnInterval: 45, maxEnemies: 5,
enemyTypes: ["strafer"]
},
{
x: 2800, y: 2800, angle: 160,
poly: [
{x:-40, y:-30},
{x: 40, y:-30},
{x: 40, y: 20},
{x: 10, y: 30},
{x:-40, y: 30}
],
hp: 100, spawnInterval: 60, maxEnemies: 5,
enemyTypes: ["tank"]
},
{
x: 2500, y: 2500, angle: 130,
poly: [
{x:-80, y:-40},
{x: 80, y:-40},
{x: 80, y: 40},
{x:-80, y: 40}
],
hp: 200, spawnInterval: 60, maxEnemies: 10,
enemyTypes: ["chaser","strafer","tank"]
}
],
objective: "destroyBases"
}
};
};
//Enemies
const enemyTypes = {
chaser: {
speed: 0.08,
hp: 40,
fireRate: 500,
weight: 2,
poly: [
{x:-18, y:-12},
{x: 10, y:-12},
{x: 15, y: 0}, // nose
{x: 10, y: 12},
{x:-18, y: 12},
],
windshield: [
{x: 10, y: -8},
{x: 12, y: 0},
{x: 10, y: 8},
]
},
strafer: {
speed: 0.07,
hp: 60,
fireRate: 700,
weight: 3,
poly: [
{x:-28, y:-18},
{x: 22, y:-18},
{x: 28, y: 0}, // front wedge
{x: 22, y: 18},
{x:-28, y: 18}
],
windshield: [
{x: 20, y: -14},
{x: 22, y: 0},
{x: 20, y: 14},
]
},
tank: {
speed: 0.05,
hp: 150,
fireRate: 1200,
weight: 4,
poly: [
{x:-32, y:-22},
{x: 0, y:-22},
{x: 28, y:-10},
{x: 28, y: 10},
{x: 0, y: 22},
{x:-32, y: 22}
],
turretPoly: [
{x: -10, y: -5},
{x: 20, y: -5},
{x: 20, y: 5},
{x: -10, y: 5}
],
cooldown: 0,
turretTurnSpeed: 0.05,
hullTurnSpeed: 0.03,
idealRange: 350,
}
};
//Terrain
const treePoly={}
treePoly.forest = [
{x: 0, y: -28},
{x: 18, y: -20},
{x: 26, y: -5},
{x: 22, y: 12},
{x: 10, y: 24},
{x: -4, y: 28},
{x: -18, y: 22},
{x: -26, y: 10},
{x: -28, y: -4},
{x: -20, y: -18},
{x: -8, y: -26}
];
treePoly.desert = [
{x: -10, y: -40},
{x: -5, y: -10},
{x: -25, y: -10},
{x: -25, y: 20},
{x: -10, y: 20},
{x: -10, y: 40},
{x: 10, y: 40},
{x: 10, y: 20},
{x: 25, y: 20},
{x: 25, y: -10},
{x: 5, y: -10},
{x: 10, y: -40}
];
treePoly.snowy = [
{x: 0, y: -30}, // outer (top)
{x: 10, y: -18}, // inner (branch gap)
{x: 26, y: -10}, // outer (upper right)
{x: 16, y: -2}, // inner
{x: 24, y: 14}, // outer (right)
{x: 8, y: 20}, // inner
{x: -4, y: 28}, // outer (bottom)
{x: -14, y: 18}, // inner
{x: -26, y: 8}, // outer (left)
{x: -18, y: -4}, // inner
{x: -20, y: -20}, // outer (upper left)
{x: -8, y: -24} // inner
];
function makeFungalCap(radius, points = 12) {
const arr = [];
for (let i = 0; i < points; i++) {
const angle = (i / points) * Math.PI * 2;
let r = radius;
if (i % 3 === 0) r *= 1.2; // outward spike
if (i % 3 === 1) r *= 0.8; // inward dent
arr.push({
x: Math.cos(angle) * r,
y: Math.sin(angle) * r
});
}
return arr;
};
treePoly.rocky = makeFungalCap(40);
let rockPoly = [
{x: -20, y: -10},
{x: 10, y: -25},
{x: 25, y: -5},
{x: 15, y: 20},
{x: -15, y: 25},
{x: -30, y: 5}
];
let camCenter = { x: game.player.x, y: game.player.y };
let camLeft = 0;
let camTop = 0;
let camRight = 0;
let camBottom = 0;
let sw = 0;
let sh = 0;
let worldObjects = [];
function scalePoly(poly, s) {
return poly.map(p => ({ x: p.x * s, y: p.y * s }));
}
function mulberry32(a) {
return function() {
a |= 0; a = a + 0x6D2B79F5 | 0;
let t = Math.imul(a ^ a >>> 15, 1 | a);
t ^= t + Math.imul(t ^ t >>> 7, 61 | t);
return ((t ^ t >>> 14) >>> 0) / 4294967296;
}
}
function generateTerrain(seed = 12345) {
const randMul = mulberry32(seed);
function rand(min = 0, max = 1) {
return randMul() * (max - min) + min;
}
const objects = [];
for (let i = 0; i < 200; i++) {
const s = randMul(2, 1.5);
const angle = rand(0, Math.PI * 2);
objects.push({
type: "tree",
x: randMul() * WORLD_W,
y: randMul() * WORLD_H,
angle,
poly: scalePoly(treePoly[scenario.terrain], s),
hp: Math.ceil(s * 30)
});
}
for (let i = 0; i < 80; i++) {
const s = randMul(1, 1.4);
const angle = rand(0, Math.PI * 2);
objects.push({
type: "rock",
x: randMul() * WORLD_W,
y: randMul() * WORLD_H,
angle,
poly: scalePoly(rockPoly, s),
hp: Math.ceil(s * 60)
});
}
return objects;
}
const bgDefs={}
const bgColors={}
const treeColors={}
bgDefs.forest = `
<defs>
<filter id="forest">
<feTurbulence type="fractalNoise" baseFrequency="0.8" numOctaves="3" result="noise"/>
<feColorMatrix type="saturate" values="0"/>
<feBlend in="SourceGraphic" in2="noise" mode="multiply"/>
</filter>
</defs>`;
bgDefs.desert = `
<defs>
<filter id="desert">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" result="noise"/>
<feColorMatrix type="matrix" values="
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0" />
<feBlend in="SourceGraphic" in2="noise" mode="multiply"/>
</filter>
</defs>`;
bgDefs.snowy = `
<defs>
<filter id="snowy" x="0" y="0" width="100%" height="100%">
<feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="4" seed="234" result="noise"/>
<feColorMatrix type="matrix" values="
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 0.25 0" result="softNoise"/>
<feBlend in="SourceGraphic" in2="softNoise" mode="overlay"/>
</filter>
</defs>`;
bgDefs.rocky = `
<defs>
<filter id="rocky">
<feTurbulence type="fractalNoise" baseFrequency="0.8" numOctaves="4" />
<feColorMatrix type="matrix"
values="0.2 0 0 0 0
0 0.2 0 0 0
0 0 0.25 0 0
0 0 0 1 0" />
</filter>
</defs>`;
bgColors.forest = "#4a7f3a";
bgColors.desert = "#d8c28a";
bgColors.snowy = "#ffffff";
bgColors.rocky = "2b2b2e";
treeColors.forest = "green";
treeColors.desert = "green";
treeColors.snowy = "brown";
treeColors.rocky = "#3a3a3f";*/'] |