Resource fixes!
authorxangelo <git@xangelo.ca>
Mon, 16 May 2022 18:48:31 +0000 (14:48 -0400)
committerxangelo <git@xangelo.ca>
Fri, 20 May 2022 03:02:50 +0000 (23:02 -0400)
A large rework of resources and how they interact

Fixes:
- ignore db files
- transfer gold -> credits
- transfer ore -> alloys
- transfer bushels -> food
- transfer logs -> energy
- add symbols to topbar
- transer land -> space
- fix cost display
- Display rate of change for food/energy since they are consumed per
  tick

17 files changed:
.gitignore
dump.sql
public/game.html
public/scifi.css
src/api.ts
src/render/costs.ts [new file with mode: 0644]
src/render/kingdom-overview.ts
src/render/land-development.ts
src/render/mail.ts
src/render/map.ts
src/render/topbar.ts
src/render/unit-training.ts
src/repository/buildings.ts
src/repository/city.ts
src/repository/unit.ts
src/tasks/fight.ts
src/tasks/tick.ts

index bfef57f989145c47276656ea1588f7fe8443ea17..51f4dbed0de153a4aa366d93aab47c37c8660326 100644 (file)
@@ -1,3 +1,4 @@
 *.js
 *.log
 node_modules/
+*.db
index 9330aa6294a19cf23187011d69b74d33f12a65f7..44ee69262b5d39d2e4acd6d6c97aa81e31f4dee2 100644 (file)
--- a/dump.sql
+++ b/dump.sql
@@ -11,10 +11,10 @@ CREATE TABLE IF NOT EXISTS "cities" (
   "icon" string,
        "totalSpace"    int,
        "usedSpace"     int,
-       "gold"  int,
-       "ore"   int,
-       "logs"  int,
-       "bushels"       int,
+       "credits"       int,
+       "alloys"        int,
+       "energy"        int,
+       "food"  int,
        "population"    int,
        "soliders"      int,
        "attackers"     int,
@@ -64,9 +64,9 @@ CREATE TABLE IF NOT EXISTS "unit_training_queue" (
 CREATE TABLE IF NOT EXISTS "buildings" (
        "slug"  text,
        "display"       text UNIQUE,
-       "gold"  int,
-       "ore"   int,
-       "logs"  int,
+       "credits"       int,
+       "alloys"        int,
+       "energy"        int,
        "land"  int,
        "time"  int,
        PRIMARY KEY("slug")
@@ -74,8 +74,8 @@ CREATE TABLE IF NOT EXISTS "buildings" (
 CREATE TABLE IF NOT EXISTS "units" (
        "slug"  ,
        "display"       ,
-       "gold"  ,
-       "bushels"       ,
+       "credits"       ,
+       "food"  ,
        "population"    ,
        "soldiers"      ,
        "attackers"     ,
index 3596ad2d0d0e3ed25f7746b36359c3942de05a20..054be5f4d59ef6721bafb729803d22bced34f6d1 100644 (file)
                 </div>
                 <div class="row">
                     <div class="col" id="info-bar">
-                        <span><b>Gold:</b> 10,000,0000</span>
-                        <span><b>Ore:</b> 10,000,000</span>
-                        <span><b>Logs:</b> 10,000,0000</span>
+                        <span><b>Credits:</b> 10,000,0000</span>
+                        <span><b>Alloys:</b> 10,000,000</span>
+                        <span><b>Food:</b> 10,000,0000</span>
+                        <span><b>Energy:</b> 10,000,0000</span>
                     </div>
                 </div>
             </div>
index c9e6da2846c542ae82b65f88737a01f10fb671b1..3c6c0b732baf7b06f368ff20c397cc12b78a807f 100644 (file)
@@ -5,6 +5,7 @@
     --green-bg: #193818;
     --green-border: #32821c;
     --red-border: #821c1c;
+    --red-bg: #381818;
 }
 
 input {
@@ -89,12 +90,18 @@ button::after, .btn::after {
     color: var(--border);
 }
 .danger {
-    background-color: #381818;
+    background-color: var(--red-bg);
     border-color: var(--red-border);
 }
 .danger::after {
     color: #821c1c
 }
+.danger-text {
+  color: var(--red-border);
+}
+.success-text {
+  color: var(--green-border);
+}
 .success {
     background-color: var(--green-bg);
     border-color: var(--green-border);
@@ -252,6 +259,21 @@ form > div {
     justify-content: space-evenly;
 }
 
+#info-bar > span {
+  display: inline-block;
+  line-height: 1.5rem; 
+}
+#info-bar b {
+  --aug-border-all: 1px;
+  --aug-border-bg: var(--border);
+  display: inline-block;
+  line-height: 2rem;
+  width: 30px;
+  text-align: center;
+  background-color: #0d2329;
+  cursor: default;
+}
+
 #overworld-map {
   width: auto;
   margin: 0 auto;
@@ -295,3 +317,18 @@ form > div {
 #sector-selector select {
   margin-left: 20px;
 }
+
+.cost-display {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: flex-start;
+}
+.cost-display > div {
+  margin: 0 0.5rem;
+}
+.rate-of-change.success-text::before {
+  content: '\25B2 ';
+}
+.rate-of-change.danger::before {
+  content: '\25BC ';
+}
index aba677b1f72ad8c1e6f6dc59a2ca8471481441e5..f59ec0e3a83a173840346cd289829b236c4942c6 100644 (file)
@@ -15,7 +15,9 @@ import { launchOffensive, listOperations, renderOverworldMap } from './render/ma
 import { createBullBoard } from '@bull-board/api';
 import { BullAdapter } from '@bull-board/api/bullAdapter';
 import _ from 'lodash';
-import { renderMailroom, renderMessage } from './render/mail';
+import { renderCost } from './render/costs';
+import {renderMailroom, renderMessage} from './render/mail';
+import {topbar} from './render/topbar';
 
 const server = new HttpServer(config.API_PORT);
 
@@ -95,7 +97,17 @@ server.get<{}, string>('/poll/overview', async req => {
        const account = await accountRepo.validate(req.authInfo.accountId, req.authInfo.token);
        const city = await cityRepo.getUsersCity(account.id);
 
-       return renderKingomOverview(city, account);
+  const usage = {
+    foodUsagePerTick: await cityRepo.foodUsagePerTick(city),
+    foodProductionPerTick: await cityRepo.foodProductionPerTick(city),
+    energyUsagePerTick: 0,
+    energyProductionPerTick: 0
+  }
+
+       return renderKingomOverview({
+    ...city,
+    ...usage
+  }, account) + topbar({...city, ...usage});
 });
 
 server.get<{}, string>('/poll/construction', async req => {
@@ -104,7 +116,13 @@ server.get<{}, string>('/poll/construction', async req => {
        const buildings = await cityRepo.buildingRepository.list();
 
        const buildQueues = await cityRepo.getBuildQueues(account.id);
-       return renderLandDevelopment(city, buildings, buildQueues);
+  const usage = {
+    foodUsagePerTick: await cityRepo.foodUsagePerTick(city),
+    foodProductionPerTick: await cityRepo.foodProductionPerTick(city),
+    energyUsagePerTick: 0,
+    energyProductionPerTick: 0
+  }
+       return renderLandDevelopment(city, buildings, buildQueues) + topbar({...city, ...usage});
 });
 
 server.get<{}, string>('/poll/unit-training', async req => {
@@ -113,8 +131,17 @@ server.get<{}, string>('/poll/unit-training', async req => {
 
        const unitTrainingQueues = await cityRepo.getUnitTrainingQueues(account.id);
        const units = await cityRepo.unitRepository.list();
+  const usage = {
+    foodUsagePerTick: await cityRepo.foodUsagePerTick(city),
+    foodProductionPerTick: await cityRepo.foodProductionPerTick(city),
+    energyUsagePerTick: 0,
+    energyProductionPerTick: 0
+  }
 
-       return renderUnitTraining(city, units, unitTrainingQueues);
+       return renderUnitTraining(city, units, unitTrainingQueues) + topbar({
+    ...city,
+    ...usage
+  });
 });
 
 server.post<{body: {sector: string}}, string>('/poll/map', async req => {
@@ -131,15 +158,34 @@ server.post<{body: {sector: string}}, string>('/poll/map', async req => {
     }
   }
 
-  console.log('Checking cities in sector', sector);
+  const usage = {
+    foodUsagePerTick: await cityRepo.foodUsagePerTick(city),
+    foodProductionPerTick: await cityRepo.foodProductionPerTick(city),
+    energyUsagePerTick: 0,
+    energyProductionPerTick: 0
+  }
 
-       return renderOverworldMap(await cityRepo.findAllInSector(sector), city, sector);
+       return renderOverworldMap(await cityRepo.findAllInSector(sector), city, sector) + topbar({
+    ...city,
+    ...usage
+  });
 });
 
 server.get<{}, string>('/poll/mailroom', async req => {
        const account = await accountRepo.validate(req.authInfo.accountId, req.authInfo.token);
+       const city = await cityRepo.getUsersCity(account.id);
 
-       return renderMailroom(await mailRepo.listReceivedMessages(account.id));
+  const usage = {
+    foodUsagePerTick: await cityRepo.foodUsagePerTick(city),
+    foodProductionPerTick: await cityRepo.foodProductionPerTick(city),
+    energyUsagePerTick: 0,
+    energyProductionPerTick: 0
+  }
+
+       return renderMailroom(await mailRepo.listReceivedMessages(account.id)) + topbar({
+    ...city,
+    ...usage
+  });
 });
 
 
@@ -150,7 +196,6 @@ server.post<{
        }
 }, string>('/cost/construction', async req => {
        const amount = parseInt(req.body.amount.trim(), 10);
-       console.log('checking amount', amount);
 
        if(isNaN(amount) || amount < 1) {
                return '';
@@ -161,13 +206,15 @@ server.post<{
                throw new NotFoundError(`Invalid building type ${req.body.building_type}`, ERROR_CODE.INVALID_BUILDING);
        }
 
-       return JSON.stringify({
-               gold: building.gold * amount,
-               ore: building.ore * amount,
-               logs: building.logs * amount,
+  const cost = {
+               credits: building.credits * amount,
+               alloys: building.alloys * amount,
+               energy: building.energy * amount,
                land: building.land * amount,
                time: building.time
-       });
+  };
+
+  return renderCost(cost);
 });
 
 server.post<{
@@ -177,19 +224,24 @@ server.post<{
        }
 }, string>('/cost/training', async req => {
        const amount = parseInt(req.body.amount, 10);
-       const unit = await cityRepo.unitRepository.findBySlug(req.body.type);
 
+       if(isNaN(amount) || amount < 1) {
+               return '';
+       }
+
+       const unit = await cityRepo.unitRepository.findBySlug(req.body.type);
        if(!unit) {
                throw new NotFoundError(`Invalid unit type ${req.body.type}`, ERROR_CODE.INVALID_UNIT);
        }
 
-       return JSON.stringify({
+       return renderCost({
                population: unit.population * amount,
                soldiers: unit.soldiers * amount,
                attackers: unit.attackers * amount,
                defenders: unit.defenders * amount,
-               gold: unit.gold * amount,
-               bushels: unit.bushels * amount
+               credits: unit.credits * amount,
+               food: unit.food * amount,
+    time: unit.time * amount
        });
 });
 
@@ -199,17 +251,17 @@ server.post<{
                building_type: string,
        }
 }, void>('/build', async req => {
-       const account = await accountRepo.validate(req.authInfo.accountId, req.authInfo.token);
-       const city = await cityRepo.getUsersCity(account.id);
+  const account = await accountRepo.validate(req.authInfo.accountId, req.authInfo.token);
+  const city = await cityRepo.getUsersCity(account.id);
 
-       const amount = parseInt(req.body.amount, 10);
-       const building = await cityRepo.buildingRepository.findBySlug(req.body.building_type);
+  const amount = parseInt(req.body.amount, 10);
+  const building = await cityRepo.buildingRepository.findBySlug(req.body.building_type);
 
-       if(!building) {
-               throw new NotFoundError(`Invalid building type ${req.body.building_type}`, ERROR_CODE.INVALID_BUILDING);
-       }
+  if(!building) {
+    throw new NotFoundError(`Invalid building type ${req.body.building_type}`, ERROR_CODE.INVALID_BUILDING);
+  }
 
-       const queueData = await cityRepo.buildBuilding(building, amount ,city);
+  const queueData = await cityRepo.buildBuilding(building, amount, city);
 
        construction.trigger(queueData, { delay: queueData.due });
 }, 'reload-construction-queue');
diff --git a/src/render/costs.ts b/src/render/costs.ts
new file mode 100644 (file)
index 0000000..03082a3
--- /dev/null
@@ -0,0 +1,56 @@
+type Cost = {
+  credits: number,
+  time: number,
+  alloys?: number,
+  energy?: number,
+  land?: number,
+  food?: number,
+  population?: number,
+  soldiers?: number
+  attackers?: number,
+  defenders?: number
+}
+
+function lineItem(display: string, value: number): string {
+  return `
+  <div>
+    <b>${display}:</b>
+    <span class="text">${value.toLocaleString()}</span>
+  </div>
+  `;
+}
+
+export function renderCost(cost: Cost): string {
+  const costAsArray = [];
+
+  costAsArray.push(lineItem('Credits', cost.credits));
+  costAsArray.push(lineItem('Time', cost.time));
+
+  if(cost.alloys) {
+    costAsArray.push(lineItem('Alloys', cost.alloys));
+  }
+  if(cost.food) {
+    costAsArray.push(lineItem('Food', cost.food));
+  }
+  if(cost.energy) {
+    costAsArray.push(lineItem('Energy', cost.energy));
+  }
+  if(cost.land) {
+    costAsArray.push(lineItem('Space', cost.land));
+  }
+  if(cost.population) {
+    costAsArray.push(lineItem('Pop', cost.population));
+  }
+  if(cost.soldiers) {
+    costAsArray.push(lineItem('Soldiers', cost.soldiers));
+  }
+  if(cost.attackers) {
+    costAsArray.push(lineItem('Attackers', cost.attackers));
+  }
+  if(cost.defenders) {
+    costAsArray.push(lineItem('Defenders', cost.defenders));
+  }
+
+
+  return `<div class="cost-display">${costAsArray.join("")}</div>`;
+}
index c6b5964c1d615ca4a57844b8ba3e2aafa2f21ae6..c035f7cbcec60921063e74f6d41c164402965f9d 100644 (file)
@@ -1,54 +1,62 @@
 import { Account } from "../repository/accounts";
 import { CityWithLocation } from "../repository/city";
 import * as _ from 'lodash';
-import { topbar } from "./topbar";
 
-export function renderKingomOverview(city: CityWithLocation, account: Account): string {
+type Usage = {
+  foodUsagePerTick: number;
+  foodProductionPerTick: number;
+  energyUsagePerTick: number;
+  energyProductionPerTick: number;
+}
+
+export function renderKingomOverview(city: CityWithLocation & Usage, account: Account): string {
+  const foodRateOfChange = city.foodProductionPerTick - city.foodUsagePerTick;
+  const energyRateOfChange = city.energyProductionPerTick - city.energyUsagePerTick;
     return `
        <div hx-trigger="every 600s" hx-get="/poll/overview">
-       <h2 data-augmented-ui="tl-clip bl-clip none">Kingdom Overview</h2>
+       <h2 data-augmented-ui="tl-clip bl-clip none">Overview</h2>
        <table>
        <tr>
-               <th>Lord</th>
+               <th>Captain</th>
                <td>${account.username}</td>
                <th>Population</th>
                <td>${city.population.toLocaleString()}/${_.max([city.farms * 70, city.population])}</td>
        </tr>
        <tr>
-               <th>Land</th>
+               <th>Space</th>
                <td>${city.totalSpace.toLocaleString()} (${Math.ceil(city.usedSpace/city.totalSpace * 100)}% used)</td>
                <th>Soldiers</th>
                <td>${city.soldiers.toLocaleString()}</td>
        </tr>
        <tr>
                <th>Location</th>
-               <td>${city.sector_id} - (${city.location_x},${city.location_y})</td>
+               <td>Sector ${city.sector_id} - (${city.location_x},${city.location_y})</td>
                <th>Attackers</th>
                <td>${city.attackers.toLocaleString()}</td>
        </tr>
        <tr>
-               <th>Gold</th>
-               <td>${city.gold.toLocaleString()}</td>
+               <th>Credits</th>
+               <td>${city.credits.toLocaleString()}</td>
                <th>Defenders</th>
                <td>${city.defenders.toLocaleString()}</td>
        </tr>
        <tr>
-               <th>Ore</th>
-               <td>${city.ore.toLocaleString()}</td>
+               <th>Alloys</th>
+               <td>${city.alloys.toLocaleString()}</td>
                <th>Special Attackers</th>
                <td>${city.sp_attackers.toLocaleString()}</td>
        </tr>
        <tr>
-               <th>Logs</th>
-               <td>${city.logs.toLocaleString()}</td>
+               <th>Energy</th>
+               <td>${city.energy.toLocaleString()} (<span class="rate-of-change ${energyRateOfChange < 0 ? 'danger-text' : 'success-text'}">${energyRateOfChange.toLocaleString()}</span>)</td>
                <th>Special Defenders</th>
                <td>${city.sp_defenders.toLocaleString()}</td>
        </tr>
        <tr>
-               <th>Bushels</th>
-               <td>${city.bushels.toLocaleString()}</td>
+               <th>Food</th>
+               <td>${city.food.toLocaleString()} (<span class="rate-of-change ${foodRateOfChange < 0 ? 'danger-text' : 'success-text'}">${foodRateOfChange.toLocaleString()}</span>)</td>
        </tr>
        </table>
        </div>
-       ${topbar(city)}`;
+       `;
 }
index d5cc4e34baa72615a3d5fa1e99506c7ac617ff84..0c1fad915890fe43330a3feb61683a9a6443a117 100644 (file)
@@ -2,7 +2,6 @@ import { BuildQueue } from "../repository/build-queue";
 import { CityWithLocation } from "../repository/city";
 import { Building } from '../repository/buildings';
 import _ from "lodash";
-import { topbar } from "./topbar";
 
 function progressBar(current, max): string {
     const percent = Math.ceil((current/max) * 100);
@@ -21,9 +20,10 @@ export function renderLandDevelopment(city: CityWithLocation, buildings: Buildin
     <h2 data-augmented-ui="tl-clip bl-clip none">Construction</h2>
     <table>
     <tr>
-        <th>Free Land</th>
+        <th>Type</th>
         <th>Current</th>
-        <td colspan="2">${(city.totalSpace - city.usedSpace).toLocaleString()} (${Math.ceil(freeSpace/city.totalSpace * 100)}% available)</td>
+        <th>Space Available: ${(city.totalSpace - city.usedSpace).toLocaleString()} (${Math.ceil(freeSpace/city.totalSpace * 100)}% available)</th>
+        <th width="200">Cost</th>
     </tr>
     ${
         buildings.map(building => {
@@ -37,8 +37,8 @@ export function renderLandDevelopment(city: CityWithLocation, buildings: Buildin
                         <input type="hidden" name="building_type" value="${building.slug}">
                         <button type="submit">Build</button>
                     </form>
-                    <span id="${building.slug}-cost"></span>
                 </td>
+                <td id="${building.slug}-cost"></td>
             </tr>
             `;
         }).join("\n")
@@ -74,5 +74,5 @@ export function renderLandDevelopment(city: CityWithLocation, buildings: Buildin
     </table>
     </div>
     `;
-    return html + queues + topbar(city);
-}
\ No newline at end of file
+    return html + queues;
+}
index 271eed9f70e136cf96baad6e964e9ac552886c49..a0b3b753c4e05b3bfa497660ff3a570e37134207 100644 (file)
@@ -1,6 +1,5 @@
 import { DateTime } from "luxon";
 import { MessageWithNames } from "../repository/mail";
-import { topbar } from "./topbar";
 
 export function renderMailroom(mail: MessageWithNames[]): string {
     return `
@@ -52,4 +51,4 @@ export function renderMessage(msg: MessageWithNames): string {
     </tr>
     </table>
     `;
-}
\ No newline at end of file
+}
index 219103d5cfb5f76b5051d7e3a0a51baaad503482..a9e83493b1a002f1bfe2da6d32a04630218e1c43 100644 (file)
@@ -2,10 +2,8 @@ import _ from "lodash";
 import { DateTime } from "luxon";
 import { Account } from "../repository/accounts";
 import { ArmyQueueWithAttackedOwner } from "../repository/army";
-import { City, CityRepository, CityWithLocation } from "../repository/city";
-import { topbar } from "./topbar";
+import { CityRepository, CityWithLocation } from "../repository/city";
 import { AVAILABLE_SECTORS } from '../config';
-import {initArray} from "../lib/util";
 
 const cityRepo = new CityRepository();
 
@@ -181,5 +179,5 @@ export async function launchOffensive(city: CityWithLocation, owner: Account, yo
     </form>
     `;
 
-    return html + topbar(yourCity);
+    return html;
 }
index e1261374385a3b707a422b4ca98d5457b6e9942f..94313c55f411b90cd4f5936de818491dc7bde61a 100644 (file)
@@ -1,13 +1,42 @@
 import { City } from "../repository/city";
 
-export function topbar(city: City): string {
+type Usage = {
+  foodUsagePerTick: number;
+  foodProductionPerTick: number;
+  energyUsagePerTick: number;
+  energyProductionPerTick: number;
+}
+
+
+export function topbar(city: City & Usage): string {
+  const foodRateOfChange = city.foodProductionPerTick - city.foodUsagePerTick;
+  const energyRateOfChange = city.energyProductionPerTick - city.energyUsagePerTick;
     const oob = `
     <div class="col" id="info-bar" hx-swap-oob="true">
-    <span><b>Gold:</b> ${city.gold.toLocaleString()}</span>
-    <span><b>Ore:</b> ${city.ore.toLocaleString()}</span>
-    <span><b>Logs:</b> ${city.logs.toLocaleString()}</span>
+    <span>
+      <b data-augmented-ui="all-hex border" title="Credits">&#8353;</b>
+      <span class="text">${city.credits.toLocaleString()}</span>
+    </span>
+    <span>
+      <b data-augmented-ui="all-hex border" title="Alloys">A</b>
+      <span class="text">${city.alloys.toLocaleString()}</span>
+    </span>
+    <span>
+      <b data-augmented-ui="all-hex border" title="Food">F</b>
+      <span class="text">
+      ${city.food.toLocaleString()}
+      <span class="rate-of-change ${foodRateOfChange < 0 ? 'danger-text': 'success-text'}">${foodRateOfChange.toLocaleString()}</span>
+      </span>
+    </span>
+    <span>
+      <b data-augmented-ui="all-hex border" title="Energy">E</b>
+      <span class="text">
+      ${city.energy.toLocaleString()}
+      <span class="rate-of-change ${energyRateOfChange < 0 ? 'danger-text': 'success-text'}">${energyRateOfChange.toLocaleString()}</span>
+      </span>
+    </span>
     </div>
     `;
 
     return oob;
-}
\ No newline at end of file
+}
index bfed36e2cd33cca3d346141b203327a92370b239..0214bfe301402ff31de4ad328a4a1c5cd9b5ac54 100644 (file)
@@ -2,7 +2,6 @@ import _ from "lodash";
 import { CityWithLocation } from "../repository/city";
 import { UnitTrainingQueue } from "../repository/training-queue";
 import { Unit } from "../repository/unit";
-import { topbar } from "./topbar";
 
 function progressBar(current, max): string {
     const percent = Math.ceil((current/max) * 100);
@@ -24,18 +23,19 @@ export function renderUnitTraining(city: CityWithLocation, units: Unit[], traini
         <th>Unit</th>
         <th>Avail.</td>
         <th></th>
+        <th width="200">Cost</th>
     </tr>
     <tr>
         <th>Soldiers</th>
         <td>${city.population}</td>
         <td>
             <form hx-post="/units">
-                <input type="number" name="amount" size="6" max="${city.population}" hx-trigger="change" hx-post="/cost/training" hx-target="#${unit.soldiers.slug}-cost">
+                <input type="number" name="amount" size="6" max="${city.population}" hx-trigger="keyup" hx-post="/cost/training" hx-target="#${unit.soldiers.slug}-cost">
                 <input type="hidden" name="type" value="${unit.soldiers.slug}">
                 <button type="submit" ${city.population ? '' : 'disabled'}>Train</button>
             </form>
-            <span id="${unit.soldiers.slug}-cost"></span>
         </td>
+        <td id="${unit.soldiers.slug}-cost"></span>
     </tr>
     <tr>
         <th>Attackers</th>
@@ -46,8 +46,8 @@ export function renderUnitTraining(city: CityWithLocation, units: Unit[], traini
                 <input type="hidden" name="type" value="${unit.attackers.slug}">
                 <button type="submit" ${city.soldiers ? '' : 'disabled'}>Train</button>
             </form>
-            <span id="${unit.attackers.slug}-cost"></span>
         </td>
+        <td id="${unit.attackers.slug}-cost"></span>
     </tr>
     <tr>
         <th>Defenders</th>
@@ -58,8 +58,8 @@ export function renderUnitTraining(city: CityWithLocation, units: Unit[], traini
                 <input type="hidden" name="type" value="${unit.defenders.slug}">
                 <button type="submit" ${city.soldiers ? '' : 'disabled'}>Train</button>
             </form>
-            <span id="${unit.defenders.slug}-cost"></span>
         </td>
+        <td id="${unit.defenders.slug}-cost"></td>
     </tr>
     <tr>
         <th>Special Attackers</th>
@@ -72,6 +72,7 @@ export function renderUnitTraining(city: CityWithLocation, units: Unit[], traini
             </form>
             <span id="${unit.sp_attackers.slug}-cost"></span>
         </td>
+        <td id="${unit.sp_attackers.slug}-cost"></td>
     </tr>
     <tr>
         <th>Special Defenders</th>
@@ -82,8 +83,8 @@ export function renderUnitTraining(city: CityWithLocation, units: Unit[], traini
                 <input type="hidden" name="type" value="${unit.sp_defenders.slug}">
                 <button type="submit" ${city.defenders ? '': 'disabled'}>Train</button>
             </form>
-            <span id="${unit.sp_defenders.slug}-cost"></span>
         </td>
+        <td id="${unit.sp_defenders.slug}-cost"></td>
         </tr>
     </table>
     `;
@@ -115,5 +116,5 @@ export function renderUnitTraining(city: CityWithLocation, units: Unit[], traini
     </div>
     `;
 
-    return html + queues + topbar(city);
-}
\ No newline at end of file
+    return html + queues;
+}
index 291abb107f181f430301af0e8e83514966555122..d478e5ea201621b947e10973bef009965e74f460 100644 (file)
@@ -3,9 +3,9 @@ import { Repository } from "./base";
 export type Building = {
     slug: string;
     display: string;
-    gold: number;
-    ore: number;
-    logs: number;
+    credits: number;
+    alloys: number;
+    energy: number;
     land: number;
     time: number;
 }
@@ -22,4 +22,4 @@ export class BuildingRepository extends Repository<Building> {
     async list(): Promise<Building[]> {
         return this.FindAll();
     }
-}
\ No newline at end of file
+}
index 7b8818510e9b45761473d6da7411c27735ce4299..43e1b7a4247e9e91a109f94b6774cdb96a740465 100644 (file)
@@ -16,10 +16,10 @@ export type City = {
     owner: string;
     totalSpace: number;
     usedSpace: number;
-    gold: number;
-    ore: number;
-    logs: number;
-    bushels: number;
+    credits: number;
+    alloys: number;
+    energy: number;
+    food: number;
     population: number;
     soldiers: number;
     attackers: number;
@@ -62,10 +62,10 @@ export class CityRepository extends Repository<City> {
             owner: accountId,
             totalSpace: 100,
             usedSpace: 0,
-            gold: 10000,
-            ore: 10000,
-            logs: 10000,
-            bushels: 10000,
+            credits: 10000,
+            alloys: 10000,
+            energy: 10000,
+            food: 10000,
             population: 1000,
             soldiers: 100,
             attackers: 0,
@@ -161,22 +161,22 @@ where l.sector_id = ?`, [sector_id]);
             throw new InsufficientResourceError('land', building.land, freeSpace);
         }
 
-        if(city.gold < building.gold) {
-            throw new InsufficientResourceError('gold', building.gold, city.gold);
+        if(city.credits < building.credits) {
+            throw new InsufficientResourceError('credits', building.credits, city.credits);
         }
 
-        if(city.ore < building.ore) {
-            throw new InsufficientResourceError('ore', building.ore, city.ore);
+        if(city.alloys < building.alloys) {
+            throw new InsufficientResourceError('alloys', building.alloys, city.alloys);
         }
 
-        if(city.logs < building.logs) {
-            throw new InsufficientResourceError('logs', building.logs, city.logs);
+        if(city.energy < building.energy) {
+            throw new InsufficientResourceError('energy', building.energy, city.energy);
         }
 
         city.usedSpace += (building.land * amount);
-        city.gold -= (building.gold * amount);
-        city.ore -= (building.ore * amount);
-        city.logs -= (building.logs * amount);
+        city.credits -= (building.credits * amount);
+        city.alloys -= (building.alloys * amount);
+        city.energy -= (building.energy * amount);
 
         await this.save(city);
 
@@ -215,12 +215,12 @@ where l.sector_id = ?`, [sector_id]);
     }
 
     async train(unit: Unit, amount: number, city: City): Promise<UnitTrainingQueue> {
-        if(city.gold < unit.gold) {
-            throw new InsufficientResourceError('gold', unit.gold, city.gold);
+        if(city.credits < unit.credits) {
+            throw new InsufficientResourceError('credits', unit.credits, city.credits);
         }
 
-        if(city.bushels < unit.bushels) {
-            throw new InsufficientResourceError('bushels', unit.bushels, city.bushels);
+        if(city.food < unit.food) {
+            throw new InsufficientResourceError('food', unit.food, city.food);
         }
 
         if(city.population < coalesce(unit.population, 0)) {
@@ -244,8 +244,8 @@ where l.sector_id = ?`, [sector_id]);
         // ok they have everything, lets update their city 
         // and create the entry in the training queue
 
-        city.gold -= unit.gold * amount;
-        city.bushels -= unit.bushels * amount;
+        city.credits -= unit.credits * amount;
+        city.food -= unit.food * amount;
         city.population -= coalesce(unit.population, 0) * amount;
         city.soldiers -= coalesce(unit.soldiers, 0) * amount;
         city.attackers -= coalesce(unit.attackers, 0) * amount;
@@ -279,6 +279,33 @@ where l.sector_id = ?`, [sector_id]);
         return power
     }
 
+    async foodProductionPerTick(city: City): Promise<number> {
+      // eventually we should supply the warehouse formula 
+      // to calculate the max amount of food created per tick
+      return _.max([
+        city.population + _.round(city.farms * 50)
+      ])
+    }
+
+    async foodUsagePerTick(city: City): Promise<number> {
+      return (
+        (city.soldiers * 0.5) + 
+        (city.population * 0.25) + 
+        (city.attackers * 0.75) + 
+        (city.attackers * 0.75) + 
+        (city.sp_attackers * 1.3) + 
+        (city.sp_defenders * 1.3)
+      )
+    }
+
+    async energyProductionPerTic(city: City): Promise<number> {
+      return 0;
+    }
+
+    async energyUsagePerTick(city: City): Promise<number> {
+      return 0;
+    }
+
     async attack(attacker: CityWithLocation, attacked: CityWithLocation, army: Army): Promise<ArmyQueue> {
         // validate the user has enough of a military! 
         if(attacker.soldiers < army.soldiers) {
index bfbe4c8b1334db85f0b330ebab00625eddd4768e..3d4ff7afbd1c21a2375e1fc6494d880c534f7adf 100644 (file)
@@ -3,8 +3,8 @@ import { Repository } from "./base";
 export type Unit = {
     slug: string;
     display: string;
-    gold: number;
-    bushels: number;
+    credits: number;
+    food: number;
     population: number;
     soldiers: number;
     attackers: number;
@@ -26,4 +26,4 @@ export class UnitRepository extends Repository<Unit> {
     async list(): Promise<Unit[]> {
         return this.FindAll();
     }
-}
\ No newline at end of file
+}
index 7be73a6031d50f9562f7230a363b2b542b3f5e8f..484c07c2e435ebdbc1512974c7e3e8d016d2066b 100644 (file)
@@ -54,16 +54,16 @@ export const fight = new Task<ArmyQueue>('fights', async (task, job) => {
             defenders: Math.floor(attacked.defenders * 0.05),
             sp_attackers: Math.floor(attacked.sp_attackers * 0.05),
             sp_defenders: Math.floor(attacked.sp_defenders * 0.05),
-            gold: Math.floor(attacked.gold * 0.2),
-            logs: Math.floor(attacked.logs * 0.2),
-            ore: Math.floor(attacked.ore * 0.2),
+            credits: Math.floor(attacked.credits * 0.2),
+            energy: Math.floor(attacked.energy * 0.2),
+            alloys: Math.floor(attacked.alloys * 0.2),
             land: Math.floor(attacked.totalSpace * 0.15),
         };
 
         // ok you have everything, lets return you home
-        attacker.gold += defenderLosses.gold;
-        attacker.logs += defenderLosses.gold;
-        attacker.ore += defenderLosses.ore;
+        attacker.credits += defenderLosses.credits;
+        attacker.energy += defenderLosses.credits;
+        attacker.alloys += defenderLosses.alloys;
         attacker.totalSpace += defenderLosses.land;
 
         attacker.soldiers += (army.soldiers - attackerLosses.soldiers);
@@ -77,9 +77,9 @@ export const fight = new Task<ArmyQueue>('fights', async (task, job) => {
         attacked.defenders -= defenderLosses.defenders;
         attacked.sp_attackers -= defenderLosses.sp_attackers;
         attacked.sp_defenders -= defenderLosses.sp_defenders;
-        attacked.gold -= defenderLosses.gold;
-        attacked.logs -= defenderLosses.logs;
-        attacked.ore -= defenderLosses.ore;
+        attacked.credits -= defenderLosses.credits;
+        attacked.energy -= defenderLosses.energy;
+        attacked.alloys -= defenderLosses.alloys;
         attacked.totalSpace -= defenderLosses.land;
 
         await Promise.all([
@@ -95,16 +95,16 @@ export const fight = new Task<ArmyQueue>('fights', async (task, job) => {
                 You pillaged:
                 <table>
                 <tr>
-                    <th>Gold</th><td>${defenderLosses.gold}</td>
+                    <th>Credits</th><td>${defenderLosses.credits}</td>
                 </tr>
                 <tr>
-                    <th>Logs</th><td>${defenderLosses.logs}</td>
+                    <th>Energy</th><td>${defenderLosses.energy}</td>
                 </tr>
                 <tr>
-                    <th>Ore</th><td>${defenderLosses.ore}</td>
+                    <th>Alloys</th><td>${defenderLosses.alloys}</td>
                 </tr>
                 <tr>
-                    <th>Land</th><td>${defenderLosses.land}</td>
+                    <th>Space</th><td>${defenderLosses.land}</td>
                 </tr>
                 </table?>
 
@@ -138,16 +138,16 @@ export const fight = new Task<ArmyQueue>('fights', async (task, job) => {
                 You Lost:
                 <table>
                 <tr>
-                    <th>Gold</th><td>${defenderLosses.gold}</td>
+                    <th>Credits</th><td>${defenderLosses.credits}</td>
                 </tr>
                 <tr>
-                    <th>Logs</th><td>${defenderLosses.logs}</td>
+                    <th>Energy</th><td>${defenderLosses.energy}</td>
                 </tr>
                 <tr>
-                    <th>Ore</th><td>${defenderLosses.ore}</td>
+                    <th>Alloys</th><td>${defenderLosses.alloys}</td>
                 </tr>
                 <tr>
-                    <th>Land</th><td>${defenderLosses.land}</td>
+                    <th>Space</th><td>${defenderLosses.land}</td>
                 </tr>
                 <tr>
                     <th>Soldiers</th><td>${attackerLosses.soldiers}</td>
@@ -259,4 +259,4 @@ export const fight = new Task<ArmyQueue>('fights', async (task, job) => {
         ]);
     }
 
-});
\ No newline at end of file
+});
index 8160e9ae03bf4446299e0726988db0d37acff826..e448713e53dca01231a85c26b3b757915e4d9b72 100644 (file)
@@ -12,10 +12,10 @@ export const tick = new Task<Tick>('tick', async (task, job) => {
 
        // +population*1.1 is where we take into account farms for bonus food production
        let sql = `update cities set 
-       gold = gold + population * 2, 
-       bushels = round(
+       credits = credits + population * 2, 
+       food = round(
                max(
-                       bushels - (
+                       food - (
                                (soldiers*0.5)+
                                (population*0.25)+
                                (attackers*0.75)+
@@ -29,7 +29,7 @@ export const tick = new Task<Tick>('tick', async (task, job) => {
        ),
        population = max(
                min(
-                       population + round(coalesce(bushels/bushels, 0) * population*0.08),
+                       population + round(coalesce(food/food, 0) * population*0.08),
                        farms * 70
                ),
                population
@@ -55,4 +55,4 @@ export const tick = new Task<Tick>('tick', async (task, job) => {
                }, { delay: 60000 * nextTickAt});
        }
 
-});
\ No newline at end of file
+});