more optimizations
12
index.html
@ -6,6 +6,18 @@
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Aclonica" rel="stylesheet" />
|
||||
<title>Bastion: The Watcher's Lament</title>
|
||||
<meta property="og:title" content="Bastion: The Watcher's Lament" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="A free, open source, browser based, tower defense game inspired by GemCraft: Frostborn Wrath. Playable NOW on PC!"
|
||||
/>
|
||||
<meta property="og:image" content="https://bastion.overflow.fun/faivcon.png" />
|
||||
<meta property="og:url" content="https://bastion.overflow.fun" />
|
||||
<meta name="twitter:title" content="Bastion: The Watcher's Lament" />
|
||||
<meta
|
||||
name="twitter:description"
|
||||
content="A free, open source, browser based, tower defense game inspired by GemCraft: Frostborn Wrath. Playable NOW on PC!"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 8.1 KiB |
BIN
public/assets/gems/Fire_spritesheet.png
Normal file
After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 8.0 KiB |
Before Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 5.0 KiB |
BIN
public/assets/gems/Soulforge_spritesheet.png
Normal file
After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 6.4 KiB |
BIN
public/assets/gems/Titalium_spritesheet.png
Normal file
After Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 6.9 KiB |
BIN
public/assets/gems/Yeti_spritesheet.png
Normal file
After Width: | Height: | Size: 52 KiB |
@ -1,7 +1,7 @@
|
||||
[
|
||||
{
|
||||
"name": "Fire Gem",
|
||||
"description": "Forged from molten lava, the Fire Gem imbues your tower's attacks and add extra fire damage. It can be merged with any gem and is common.",
|
||||
"description": "Forged from molten lava, the Fire Gem imbues your tower's attacks and add extra fire damage. Well researched and common.",
|
||||
"color": "red",
|
||||
"type": "Fire",
|
||||
"totalLevels": 9,
|
||||
@ -16,14 +16,6 @@
|
||||
"rangeUp": 0,
|
||||
"timeToLiveUp": 0,
|
||||
"pierceUp": 0,
|
||||
"gemValueUp": 50
|
||||
},
|
||||
{
|
||||
"damageUp": 2,
|
||||
"attackSpeedUp": 0,
|
||||
"rangeUp": 0,
|
||||
"timeToLiveUp": 0,
|
||||
"pierceUp": 1,
|
||||
"gemValueUp": 100
|
||||
},
|
||||
{
|
||||
@ -32,7 +24,7 @@
|
||||
"rangeUp": 0,
|
||||
"timeToLiveUp": 0,
|
||||
"pierceUp": 1,
|
||||
"gemValueUp": 100
|
||||
"gemValueUp": 150
|
||||
},
|
||||
{
|
||||
"damageUp": 2,
|
||||
@ -40,7 +32,7 @@
|
||||
"rangeUp": 0,
|
||||
"timeToLiveUp": 0,
|
||||
"pierceUp": 1,
|
||||
"gemValueUp": 100
|
||||
"gemValueUp": 250
|
||||
},
|
||||
{
|
||||
"damageUp": 2,
|
||||
@ -48,7 +40,7 @@
|
||||
"rangeUp": 0,
|
||||
"timeToLiveUp": 0,
|
||||
"pierceUp": 1,
|
||||
"gemValueUp": 100
|
||||
"gemValueUp": 400
|
||||
},
|
||||
{
|
||||
"damageUp": 2,
|
||||
@ -56,7 +48,7 @@
|
||||
"rangeUp": 0,
|
||||
"timeToLiveUp": 0,
|
||||
"pierceUp": 1,
|
||||
"gemValueUp": 100
|
||||
"gemValueUp": 650
|
||||
},
|
||||
{
|
||||
"damageUp": 2,
|
||||
@ -64,7 +56,7 @@
|
||||
"rangeUp": 0,
|
||||
"timeToLiveUp": 0,
|
||||
"pierceUp": 1,
|
||||
"gemValueUp": 100
|
||||
"gemValueUp": 750
|
||||
},
|
||||
{
|
||||
"damageUp": 2,
|
||||
@ -72,7 +64,7 @@
|
||||
"rangeUp": 0,
|
||||
"timeToLiveUp": 0,
|
||||
"pierceUp": 1,
|
||||
"gemValueUp": 100
|
||||
"gemValueUp": 900
|
||||
},
|
||||
{
|
||||
"damageUp": 2,
|
||||
@ -80,10 +72,25 @@
|
||||
"rangeUp": 0,
|
||||
"timeToLiveUp": 0,
|
||||
"pierceUp": 1,
|
||||
"gemValueUp": 100
|
||||
"gemValueUp": 1000
|
||||
},
|
||||
{
|
||||
"damageUp": 2,
|
||||
"attackSpeedUp": 0,
|
||||
"rangeUp": 0,
|
||||
"timeToLiveUp": 0,
|
||||
"pierceUp": 1,
|
||||
"gemValueUp": 1200
|
||||
}
|
||||
],
|
||||
"gemResistanceModifications": [
|
||||
{
|
||||
"physical": 0,
|
||||
"divine": 0,
|
||||
"fire": 0.05,
|
||||
"ice": 0,
|
||||
"frostfire": 0
|
||||
},
|
||||
{
|
||||
"physical": 0,
|
||||
"divine": 0,
|
||||
@ -94,7 +101,14 @@
|
||||
{
|
||||
"physical": 0,
|
||||
"divine": 0,
|
||||
"fire": 0.25,
|
||||
"fire": 0.15,
|
||||
"ice": 0,
|
||||
"frostfire": 0
|
||||
},
|
||||
{
|
||||
"physical": 0,
|
||||
"divine": 0,
|
||||
"fire": 0.2,
|
||||
"ice": 0,
|
||||
"frostfire": 0
|
||||
},
|
||||
@ -115,14 +129,7 @@
|
||||
{
|
||||
"physical": 0,
|
||||
"divine": 0,
|
||||
"fire": 0.3,
|
||||
"ice": 0,
|
||||
"frostfire": 0
|
||||
},
|
||||
{
|
||||
"physical": 0,
|
||||
"divine": 0,
|
||||
"fire": 0.3,
|
||||
"fire": 0.35,
|
||||
"ice": 0,
|
||||
"frostfire": 0
|
||||
},
|
||||
@ -139,19 +146,12 @@
|
||||
"fire": 0.45,
|
||||
"ice": 0,
|
||||
"frostfire": 0
|
||||
},
|
||||
{
|
||||
"physical": 0,
|
||||
"divine": 0,
|
||||
"fire": 0.5,
|
||||
"ice": 0,
|
||||
"frostfire": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Yeti Gem",
|
||||
"description": "Yeti gem description. Something something, write this while drunk or something.",
|
||||
"description": "Crafted from the essence of the frozen bears, the Yeti Gem enhances your tower's attacks with the chilling power of ice. It gives ice damage and is known for its rarity.",
|
||||
"color": "#32e4fc",
|
||||
"type": "Yeti",
|
||||
"totalLevels": 8,
|
||||
@ -286,7 +286,7 @@
|
||||
},
|
||||
{
|
||||
"name": "Titalium Gem",
|
||||
"description": "Titalium gem description. Something something zombie creeps working for you something something.",
|
||||
"description": "Created from distilled creep eyes, the Titalium gem is known for boosting tower range, at the sacrifice for other stats.",
|
||||
"color": "pink",
|
||||
"type": "Titalium",
|
||||
"totalLevels": 7,
|
||||
@ -406,7 +406,7 @@
|
||||
},
|
||||
{
|
||||
"name": "Soulforge Gem",
|
||||
"description": "Soulforge gem description, have to write later.",
|
||||
"description": "Made from the wandering souls of the damned, the Soulforge gem accelerates your towers cooldowns and acts as a repellant for all things unholy.",
|
||||
"color": "gray",
|
||||
"type": "Soulforge",
|
||||
"totalLevels": 2,
|
||||
@ -541,7 +541,7 @@
|
||||
},
|
||||
{
|
||||
"name": "Golden Gem",
|
||||
"description": "An inherently useless gem, but high monetary value. Perhaps someone would pay a lot for this.",
|
||||
"description": "An inherently useless gem, providing no tower buffs, but high in monetary value. Highly sought after by all rich people.",
|
||||
"color": "gold",
|
||||
"type": "Gold",
|
||||
"totalLevels": 1,
|
||||
@ -571,14 +571,14 @@
|
||||
},
|
||||
{
|
||||
"name": "Artifact",
|
||||
"description": "A wildly rare gem, packed with power. No monetary value, yet your towers oddly resonate stronger with it.",
|
||||
"description": "An insanely rare gem of unknown origin, packed with power. No one knows how it works, yet your towers oddly resonate stronger with it.",
|
||||
"color": "blue",
|
||||
"type": "Artifact",
|
||||
"totalLevels": 1,
|
||||
"textures": [],
|
||||
"cantCombineWith": [],
|
||||
"specialCombine": [],
|
||||
"initialGemValue": 0,
|
||||
"initialGemValue": 1000,
|
||||
"genericImprovements": [
|
||||
{
|
||||
"damageUp": 10,
|
||||
|
@ -26,7 +26,7 @@
|
||||
"projectile": "blue",
|
||||
"projectileTextures": [],
|
||||
"projectileTexturesArrayLength": 4,
|
||||
"description": "If you feel a little circular.",
|
||||
"description": "If you feel like shooting in a circle around you, projectiles may miss.",
|
||||
"stats": {
|
||||
"damage": 3,
|
||||
"cooldown": 4000,
|
||||
@ -45,7 +45,7 @@
|
||||
"projectile": "yellow",
|
||||
"projectileTextures": [],
|
||||
"projectileTexturesArrayLength": 4,
|
||||
"description": "Zap zap zap!",
|
||||
"description": "Zap zap zap! This towers shots connect to other enemies!",
|
||||
"stats": {
|
||||
"damage": 3,
|
||||
"cooldown": 3500,
|
||||
|
@ -49,9 +49,8 @@ export default class GameAssets {
|
||||
private static text;
|
||||
private static counter = 0;
|
||||
private static async Load(src) {
|
||||
this.text.text = 'Loading asset: ' + src;
|
||||
this.text.text = `Loading asset: ${src} (${this.counter}/99)`;
|
||||
this.counter++;
|
||||
console.log(this.counter);
|
||||
return await PIXI.Assets.load({
|
||||
src: src,
|
||||
});
|
||||
@ -88,7 +87,6 @@ export default class GameAssets {
|
||||
Engine.app.stage.addChild(this.text);
|
||||
|
||||
await Promise.all([
|
||||
this.Load('./aclonica.woff2'),
|
||||
this.Load('./assets/gui/button_01.png').then((texture) => (this.Button01Texture = texture)),
|
||||
this.Load('./assets/gui/button_02.png').then((texture) => (this.Button02Texture = texture)),
|
||||
this.Load('./assets/gui/frame_01.png').then((texture) => (this.Frame01Texture = texture)),
|
||||
@ -138,9 +136,27 @@ export default class GameAssets {
|
||||
|
||||
for (let idx = 0; idx < gems.length; idx++) {
|
||||
const gem = this.Gems[idx];
|
||||
const texture = await this.Load(`./assets/gems/${gem.type}_spritesheet.png`);
|
||||
for (let i = 1; i <= gem.totalLevels; i++) {
|
||||
const texture = await this.Load(`./assets/gems/${gem.type}/${i}.png`);
|
||||
gem.textures[i - 1] = texture;
|
||||
const spritesheet = new PIXI.Spritesheet(texture, {
|
||||
frames: {
|
||||
[`${gem.type}_${i}.png`]: {
|
||||
frame: { x: (i - 1) * 64, y: 0, w: 64, h: 64 },
|
||||
rotated: false,
|
||||
trimmed: false,
|
||||
spriteSourceSize: { x: 0, y: 0, w: 64, h: 64 },
|
||||
sourceSize: { w: 64, h: 64 },
|
||||
},
|
||||
},
|
||||
meta: {
|
||||
image: `./assets/gems/${gem.type}_spritesheet.png`,
|
||||
format: 'RGBA8888',
|
||||
size: { w: 64 * gem.totalLevels, h: 64 },
|
||||
scale: '1',
|
||||
},
|
||||
});
|
||||
await spritesheet.parse();
|
||||
gem.textures[i - 1] = spritesheet.textures[`${gem.type}_${i}.png`];
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < 7; i++) {
|
||||
@ -154,8 +170,8 @@ export default class GameAssets {
|
||||
this.Creeps = creeps;
|
||||
for (let idx = 0; idx < this.Creeps.length; idx++) {
|
||||
const creep = this.Creeps[idx];
|
||||
for (let i = 0; i < creep.textureArrayLength; i++) {
|
||||
const texture = await this.Load(`./assets/creeps/${creep.sprite}_spritesheet.png`);
|
||||
for (let i = 0; i < creep.textureArrayLength; i++) {
|
||||
const spritesheet = new PIXI.Spritesheet(texture, {
|
||||
frames: {
|
||||
[`${creep.sprite}_${i}.png`]: {
|
||||
@ -197,6 +213,8 @@ export default class GameAssets {
|
||||
for (let idx = 0; idx < this.Towers.length; idx++) {
|
||||
const tower = this.Towers[idx];
|
||||
for (let i = 0; i < tower.projectileTexturesArrayLength; i++) {
|
||||
// My only grievance is that projectiles have to load like this, not like a spritesheet
|
||||
// due to them not being a fixed w/h.
|
||||
const projTexture = await this.Load(`./assets/projectiles/${tower.projectile}/${i}.png`);
|
||||
tower.projectileTextures[i] = projTexture;
|
||||
}
|
||||
@ -210,7 +228,7 @@ export default class GameAssets {
|
||||
private static async LoadMission(missionUrl: string) {
|
||||
const res = await fetch(missionUrl);
|
||||
const mission = await res.json();
|
||||
console.log(`Loading mission: ${missionUrl} [${mission.name} / ${mission.mapImage.url}]`);
|
||||
// console.log(`Loading mission: ${missionUrl} [${mission.name} / ${mission.mapImage.url}]`);
|
||||
GameAssets.Missions.push(mission);
|
||||
GameAssets.MissionBackgrounds.push(await this.Load(mission.mapImage.url));
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ export class Engine {
|
||||
Engine.TowerManager.ToggleChoosingTowerLocation('RESET');
|
||||
Engine.TowerManager.PlaceTower(tower, 6, 10, tower.behaviour, true);
|
||||
for (let i = 0; i < 29; i++) {
|
||||
this.GameScene.MissionStats.giveGem(new Gem(i % 4), true);
|
||||
this.GameScene.MissionStats.giveGem(new Gem(i % 6), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,11 +62,11 @@ export function computeGemImprovements(tower: Tower) {
|
||||
gemPierceUp += improvements.pierceUp;
|
||||
|
||||
let resistances = gem.currentGemResistanceModifications();
|
||||
tower.totalGemResistanceModifications.physical += resistances.physical;
|
||||
tower.totalGemResistanceModifications.ice += resistances.ice;
|
||||
tower.totalGemResistanceModifications.fire += resistances.fire;
|
||||
tower.totalGemResistanceModifications.divine += resistances.divine;
|
||||
tower.totalGemResistanceModifications.frostfire += resistances.frostfire;
|
||||
tower.totalGemResistanceModifications.physical += Number(resistances.physical.toFixed(2));
|
||||
tower.totalGemResistanceModifications.ice += Number(resistances.ice.toFixed(2));
|
||||
tower.totalGemResistanceModifications.fire += Number(resistances.fire.toFixed(2));
|
||||
tower.totalGemResistanceModifications.divine += Number(resistances.divine.toFixed(2));
|
||||
tower.totalGemResistanceModifications.frostfire += Number(resistances.frostfire.toFixed(2));
|
||||
});
|
||||
|
||||
tower.computedDamageToDeal = tower.definition.stats.damage + gemDamage;
|
||||
@ -84,14 +84,21 @@ export function computeGemImprovements(tower: Tower) {
|
||||
tower.computedTimeToLive += Number((buffedBy.computedTimeToLive / 5).toFixed(1));
|
||||
tower.computedPierce += Number((buffedBy.computedPierce / 4).toFixed(1));
|
||||
|
||||
tower.totalGemResistanceModifications.physical +=
|
||||
(buffedBy.totalGemResistanceModifications.physical * 100) / 2 / 100;
|
||||
tower.totalGemResistanceModifications.ice += (buffedBy.totalGemResistanceModifications.ice * 100) / 2 / 100;
|
||||
tower.totalGemResistanceModifications.fire += (buffedBy.totalGemResistanceModifications.fire * 100) / 2 / 100;
|
||||
tower.totalGemResistanceModifications.divine +=
|
||||
(buffedBy.totalGemResistanceModifications.divine * 100) / 2 / 100;
|
||||
tower.totalGemResistanceModifications.frostfire +=
|
||||
(buffedBy.totalGemResistanceModifications.frostfire * 100) / 2 / 100;
|
||||
tower.totalGemResistanceModifications.physical += Number(
|
||||
(buffedBy.totalGemResistanceModifications.physical / 2).toFixed(2)
|
||||
);
|
||||
tower.totalGemResistanceModifications.ice += Number(
|
||||
(buffedBy.totalGemResistanceModifications.ice / 2).toFixed(2)
|
||||
);
|
||||
tower.totalGemResistanceModifications.fire += Number(
|
||||
(buffedBy.totalGemResistanceModifications.fire / 2).toFixed(2)
|
||||
);
|
||||
tower.totalGemResistanceModifications.divine += Number(
|
||||
(buffedBy.totalGemResistanceModifications.divine / 2).toFixed(2)
|
||||
);
|
||||
tower.totalGemResistanceModifications.frostfire += Number(
|
||||
(buffedBy.totalGemResistanceModifications.frostfire / 2).toFixed(2)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,7 +119,9 @@ export default class EndGameDialog extends ModalDialogBase {
|
||||
override close(button?: string): void {
|
||||
if (button === EndGameDialogButtons.Confirm) {
|
||||
if (this.playerNameTextInput.getText().length == 0) {
|
||||
MessageBox.show('Please enter your name.', ['OK']);
|
||||
MessageBox.show('Please enter your name.\n(Just start typing, input bar is automatically selected.)', [
|
||||
'OK',
|
||||
]);
|
||||
} else {
|
||||
this.highScore.addScore({
|
||||
playerName: this.playerNameTextInput.getText(),
|
||||
|
@ -14,7 +14,7 @@ export class MainScene extends Scene {
|
||||
this.addMainBackground();
|
||||
|
||||
const NewGameButton = {
|
||||
caption: 'New Game',
|
||||
caption: 'Play',
|
||||
rect: new PIXI.Rectangle(Engine.app.canvas.width / 2 - 300 / 2, 400 + 0 * 70, 300, 60),
|
||||
|
||||
texture: ButtonTexture.Button01,
|
||||
|