a1bd4b8756bef6a275f1c07b9609229bf510ce90
[browser-rts.git] / src / render / unit-training.ts
1 import _ from "lodash";
2 import { CityWithLocation } from "../repository/city";
3 import { UnitTrainingQueueWithName } from "../repository/training-queue";
4 import { Unit } from "../repository/unit";
5 import { DateTime } from "luxon";
6
7 const emptyQueue: UnitTrainingQueueWithName = {
8   display: '',
9   id: '',
10   owner: '',
11   amount: 0,
12   created: 0,
13   due: 0,
14   unit_type: 'empty'
15 }
16
17 function progressBar(current: number, max: number): string {
18     const percent = Math.ceil((current/max) * 100);
19     return `
20     <div class="progress-bar unit-training" style="background: background: var(--green-bg);
21     background: linear-gradient(90deg, var(--green-bg) 0%, var(--green-bg) ${percent}%, #000 ${percent}%); border-color: var(--green-border);">
22     ${percent}%
23     </div>
24     `;
25 }
26
27 export function renderUnitTraining(city: CityWithLocation, units: Unit[], trainingQueues: UnitTrainingQueueWithName[]): string {
28     const unit = _.keyBy(units, 'slug');
29     const sortedTrainingQueue = trainingQueues.sort((a, b) => {
30         return a.due - b.due;
31     });
32     let html = `
33     <div hx-trigger="reload-unit-training, every 600s" hx-get="/poll/unit-training">
34     <h2 data-augmented-ui="tl-clip bl-clip none">Unit Training</h2>
35     <table>
36     <tr>
37         <th>Unit</th>
38         <th>Avail.</td>
39         <th></th>
40         <th width="200">Cost</th>
41     </tr>
42     <tr>
43         <th>Soldiers</th>
44         <td>${city.soldiers}</td>
45         <td>
46             <form hx-post="/units" hx-swap="innerHTML" hx-target="#notifications">
47                 <input type="number" name="amount" size="6" max="${city.population}" hx-trigger="keyup" hx-post="/cost/training" hx-target="#${unit.soldiers.slug}-cost" hx-swap="innerHTML">
48                 <input type="hidden" name="type" value="${unit.soldiers.slug}">
49                 <button type="submit" ${city.population ? '' : 'disabled'}>Train</button>
50             </form>
51         </td>
52         <td id="${unit.soldiers.slug}-cost"></span>
53     </tr>
54     <tr>
55         <th>Attackers</th>
56         <td>${city.attackers}</td>
57         <td>
58             <form hx-post="/units" hx-swap="innerHTML" hx-target="#notifications">
59                 <input type="number" name="amount" size="6" max="${city.soldiers}" hx-trigger="keyup" hx-post="/cost/training" hx-target="#${unit.attackers.slug}-cost" hx-swap="innerHTML">
60                 <input type="hidden" name="type" value="${unit.attackers.slug}">
61                 <button type="submit" ${city.soldiers ? '' : 'disabled'}>Train</button>
62             </form>
63         </td>
64         <td id="${unit.attackers.slug}-cost"></span>
65     </tr>
66     <tr>
67         <th>Defenders</th>
68         <td>${city.defenders}</td>
69         <td>
70             <form hx-post="/units" hx-swap="innerHTML" hx-target="#notifications">
71                 <input type="number" name="amount" size="6" max="${city.soldiers}" hx-trigger="keyup" hx-post="/cost/training" hx-target="#${unit.defenders.slug}-cost" hx-swap="innerHTML">
72                 <input type="hidden" name="type" value="${unit.defenders.slug}">
73                 <button type="submit" ${city.soldiers ? '' : 'disabled'}>Train</button>
74             </form>
75         </td>
76         <td id="${unit.defenders.slug}-cost"></td>
77     </tr>
78     <tr>
79         <th>Special Attackers</th>
80         <td>${city.sp_attackers}</td>
81         <td>
82             <form hx-post="/units" hx-swap="innerHTML" hx-target="#notifications">
83                 <input type="number" name="amount" size="6" max="${city.attackers}" hx-trigger="keyup" hx-post="/cost/training" hx-target="#${unit.sp_attackers.slug}-cost" hx-swap="innerHTML">
84                 <input type="hidden" name="type" value="${unit.sp_attackers.slug}">
85                 <button type="submit" ${city.attackers ? '': 'disabled'}>Train</button>
86             </form>
87             <span id="${unit.sp_attackers.slug}-cost"></span>
88         </td>
89         <td id="${unit.sp_attackers.slug}-cost"></td>
90     </tr>
91     <tr>
92         <th>Special Defenders</th>
93         <td>${city.sp_defenders}</td>
94         <td>
95             <form hx-post="/units" hx-swap="innerHTML" hx-target="#notifications">
96                 <input type="number" name="amount" size="6" max="${city.defenders}" hx-trigger="keyup" hx-post="/cost/training" hx-target="#${unit.sp_defenders.slug}-cost" hx-swap="innerHTML">
97                 <input type="hidden" name="type" value="${unit.sp_defenders.slug}">
98                 <button type="submit" ${city.defenders ? '': 'disabled'}>Train</button>
99             </form>
100         </td>
101         <td id="${unit.sp_defenders.slug}-cost"></td>
102         </tr>
103     </table>
104     `;
105
106     const finalTrainingQueue = sortedTrainingQueue;
107     if(finalTrainingQueue.length < city.max_training_queue) {
108       while(finalTrainingQueue.length < city.max_construction_queue) {
109         finalTrainingQueue.push(emptyQueue);
110       }
111     }
112
113     const queues = `
114     <hr>
115     <h2 data-augmented-ui="tl-clip bl-clip none">Training Queues</h2>
116     <table>
117     <tr>
118     <th align="left">Unit Type</th>
119     <th align="left">Amount Expected</th>
120     <th>Progress</th>
121     </tr>
122     ${sortedTrainingQueue.map(queue => {
123       if(queue.unit_type === 'empty') {
124         return `<tr>
125         <td colspan="4">You have sufficient queue capacity to train more units.</td>
126         </tr>`;
127       }
128       else {
129         const created = DateTime.fromMillis(queue.created);
130         const due = DateTime.fromMillis(queue.due);
131         const now = Date.now() - queue.created;
132         const duration = queue.due - queue.created;
133
134         return `
135         <tr>
136         <td>${queue.display}</td>
137         <td>${queue.amount}</td>
138         <td>
139         <span title="${Math.ceil(due.diff(created).as('minutes')).toLocaleString()} minutes remaining">
140         ${progressBar(now, duration)}<br>
141         </span>
142         </td>
143         </tr>
144         `;
145       }
146     }).join("\n")}
147     </table>
148     </div>
149     `;
150
151     return html + queues;
152 }