ability to cancel construction and have a portion of the funds returned
[browser-rts.git] / src / repository / city.ts
index 0ab8478a6d6ebed98d6c67e10b514a72d88c6bef..c9ecb91b0aa358d96c9de6d4487087b328cd2670 100644 (file)
@@ -4,7 +4,7 @@ import {Repository} from './base';
 import * as config from '../config';
 import { BuildQueue, BuildQueueRepository } from './build-queue';
 import { DateTime, Duration } from 'luxon';
-import { UnitTrainingQueue, UnitTrainingQueueRepository } from './training-queue';
+import { UnitTrainingQueue, UnitTrainingQueueRepository, UnitTrainingQueueWithName } from './training-queue';
 import { coalesce, pluck } from '../lib/util';
 import { Building, BuildingRepository } from './buildings';
 import { Unit, UnitRepository } from './unit';
@@ -32,10 +32,13 @@ export type City = {
     solar_panels: number;
     accumulators: number;
     mining_facilities: number;
+    ore_refinery: number;
     barracks: number;
     special_attacker_trainer: number;
     special_defender_trainer: number;
     icon: string;
+    max_construction_queue: number;
+    max_training_queue: number;
 }
 
 export type CityWithLocation = {
@@ -83,9 +86,12 @@ export class CityRepository extends Repository<City> {
             solar_panels: 5,
             accumulators: 5,
             mining_facilities: 5,
+            ore_refinery: 5,
             barracks: 0,
             special_attacker_trainer: 0,
             special_defender_trainer: 0,
+            max_construction_queue: 2,
+            max_training_queue: 2,
             icon
         };
 
@@ -128,7 +134,10 @@ export class CityRepository extends Repository<City> {
         return sample.sector_id;
     }
 
-    async save(city: City) {
+    async save(city: Partial<City>) {
+      if(!city.id) {
+        throw new Error('Unknown city to save');
+      }
       const fieldsToSave = [
         'totalSpace', 'usedSpace', 'credits', 'alloys', 'energy', 'food',
         'poulation', 'soldiers', 'attackers', 'defenders', 'sp_attackers', 'sp_defenders',
@@ -197,6 +206,12 @@ where l.sector_id = ?`, [sector_id]);
             throw new InsufficientResourceError('energy', building.energy, city.energy);
         }
 
+        // validate that they have enough empty construction queues
+        const concurrentConstruction = await this.buildQueue.list(city.owner);
+        if(concurrentConstruction.length >= city.max_construction_queue) {
+          throw new InsufficientResourceError('Construction queues', concurrentConstruction.length + 1, city.max_construction_queue);
+        }
+
         city.usedSpace += (building.land * amount);
         city.credits -= (building.credits * amount);
         city.alloys -= (building.alloys * amount);
@@ -263,17 +278,23 @@ where l.sector_id = ?`, [sector_id]);
             throw new InsufficientResourceError('defenders', unit.defenders, city.defenders);
         }
 
-        // validate that they have enough of the buildings to support this
+        // validate that they have enough empty training queues
+        const concurrentTraining = await this.unitTrainigQueue.list(city.owner);
+        if(concurrentTraining.length >= city.max_training_queue) {
+          throw new InsufficientResourceError('Training queues', concurrentTraining.length + 1, city.max_training_queue);
+        }
 
         // ok they have everything, lets update their city 
         // and create the entry in the training queue
 
         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;
-        city.defenders -= coalesce(unit.defenders, 0) * amount;
+        city.population -= unit.population * amount;
+        city.soldiers -= unit.soldiers * amount;
+        city.attackers -= unit.attackers * amount;
+        city.defenders -= unit.defenders * amount;
+
+        console.log(city);
 
         await this.save(city);
 
@@ -340,6 +361,10 @@ where l.sector_id = ?`, [sector_id]);
       return city.accumulators * 150;
     }
 
+    maxAlloy(city: City): number {
+      return city.ore_refinery * 75;
+    }
+
     async foodProductionPerTick(city: City): Promise<number> {
       // eventually we should supply the warehouse formula 
       // to calculate the max amount of food created per tick
@@ -364,15 +389,17 @@ where l.sector_id = ?`, [sector_id]);
     async energyUsagePerTick(city: City): Promise<number> {
       const buildings = await this.buildingRepository.list();
       const buildingsMap = pluck<Building>(buildings, 'slug');
-      const totalEnergy = _.sum([
-        city.farms * buildingsMap['farms'].energy,
-        city.barracks * buildingsMap['barracks'].energy,
-        city.special_defender_trainer * buildingsMap['special_defender_trainer'].energy,
-        city.special_attacker_trainer * buildingsMap['special_attacker_trainer'].energy,
-        city.homes * buildingsMap['homes'].energy,
-        city.warehouses * buildingsMap['warehouses'].energy,
-        city.solar_panels * buildingsMap['solar_panels'].energy
-      ]);
+      const totalEnergy = Math.ceil(_.sum([
+        city.farms * (buildingsMap['farms'].energy * 0.1),
+        city.barracks * (buildingsMap['barracks'].energy * 0.1),
+        city.special_defender_trainer * (buildingsMap['special_defender_trainer'].energy * 0.1),
+        city.special_attacker_trainer * (buildingsMap['special_attacker_trainer'].energy * 0.1),
+        city.homes * (buildingsMap['homes'].energy * 0.1),
+        city.warehouses * (buildingsMap['warehouses'].energy * 0.1),
+        city.solar_panels * (buildingsMap['solar_panels'].energy * 0.1),
+        city.mining_facilities * (buildingsMap['mining_facilities'].energy * 0.1),
+        city.ore_refinery * (buildingsMap['ore_refinery'].energy * 0.1)
+      ]));
       return totalEnergy;
     }
 
@@ -416,7 +443,7 @@ where l.sector_id = ?`, [sector_id]);
         return this.buildQueue.list(owner);
     }
 
-    async getUnitTrainingQueues(owner: string): Promise<UnitTrainingQueue[]> {
+    async getUnitTrainingQueues(owner: string): Promise<UnitTrainingQueueWithName[]> {
         return this.unitTrainigQueue.list(owner);
     }
 }