allow cancelling of training queues
authorxangelo <git@xangelo.ca>
Mon, 6 Jun 2022 20:29:08 +0000 (16:29 -0400)
committerxangelo <git@xangelo.ca>
Mon, 6 Jun 2022 20:29:08 +0000 (16:29 -0400)
When cancelling a training queue you end up with a minimum of 20% loss
on resources (credits/food/alloy/energy), 0% loss of people. The 20%
loss is based on the percentage completion.. after 20% completion, you
get the inverse of resources back.

IE: 40% completion means you get 60% of your resources back.
IE: 99% completion means you get 1% of your resources back

src/api.ts
src/render/unit-training.ts

index 4509bec431ad8d616bc0946d2fa2c0933268b2da..66381943a40e55598146862be56975ebd26dbbad 100644 (file)
@@ -423,6 +423,49 @@ server.post<{params: {queueId: string}}, void>('/construction/:queueId/cancel',
 
 }, 'reload-construction-queue');
 
+server.post<{params: {queueId: string}}, void>('/training/:queueId/cancel', async req => {
+       const acct = await accountRepo.validate(req.authInfo.accountId, req.authInfo.token);
+       const city = await cityRepo.getUsersCity(acct.id);
+
+  if(!validator.isUUID(req.params.queueId)) {
+    throw new BadInputError('Invalid queue ID', ERROR_CODE.INVALID_BUILD_QUEUE);
+  }
+  
+  const queue = await cityRepo.unitTrainigQueue.FindOne({owner: city.owner, id: req.params.queueId});
+  if(!queue) {
+    throw new NotFoundError('That queue does not exist', ERROR_CODE.INVALID_BUILD_QUEUE);
+  }
+
+  const [, unit] = await Promise.all([
+    cityRepo.unitTrainigQueue.Delete({
+      owner: city.owner,
+      id: req.params.queueId
+    }),
+    cityRepo.unitRepository.FindOne({slug: queue.unit_type})
+  ]);
+
+  // now that it's deleted we can give the player back some percentage 
+  // of resources based on how close they are to completion.
+  const diff = (queue.due - Date.now()) / (queue.due - queue.created);
+  // force a 20% loss minimum
+  const finalDiff = diff < 0.2 ? 0.2 : diff;
+
+  const costReturn: Partial<City> = {
+    id: city.id,
+    credits: city.credits + Math.floor(unit.credits * queue.amount * diff),
+    food: city.food + Math.floor(unit.food * queue.amount * diff),
+    population: city.population + Math.floor(unit.population * queue.amount),
+    soldiers: city.soldiers + Math.floor(unit.soldiers * queue.amount),
+    attackers: city.attackers + Math.floor(unit.attackers * queue.amount),
+    defenders: city.defenders + Math.floor(unit.attackers * queue.amount)
+  };
+
+  console.log('update', costReturn)
+
+  await cityRepo.save(costReturn);
+
+}, 'reload-unit-training');
+
 server.get<void, string>('/server-stats', async req => {
   const date = new Date();
   return `
index a1bd4b8756bef6a275f1c07b9609229bf510ce90..9e64c9c454337b1823c4b4794bd961a8399fd200 100644 (file)
@@ -117,7 +117,7 @@ export function renderUnitTraining(city: CityWithLocation, units: Unit[], traini
     <tr>
     <th align="left">Unit Type</th>
     <th align="left">Amount Expected</th>
-    <th>Progress</th>
+    <th colspan="2">Progress</th>
     </tr>
     ${sortedTrainingQueue.map(queue => {
       if(queue.unit_type === 'empty') {
@@ -135,10 +135,9 @@ export function renderUnitTraining(city: CityWithLocation, units: Unit[], traini
         <tr>
         <td>${queue.display}</td>
         <td>${queue.amount}</td>
-        <td>
-        <span title="${Math.ceil(due.diff(created).as('minutes')).toLocaleString()} minutes remaining">
-        ${progressBar(now, duration)}<br>
-        </span>
+        <td>${progressBar(now, duration)}</td>
+        <td width="50">
+        <a href="#" hx-post="/training/${queue.id}/cancel" hx-trigger="click" class="danger-text close" title="Cancel Unit Training">&times;</a>
         </td>
         </tr>
         `;