94d97917b96c386be3426df41b11d215b2bdbf2b
[browser-rts.git] / src / render / fight.ts
1 import _ from "lodash";
2 import { DateTime } from "luxon";
3 import { Account } from "../repository/accounts";
4 import { ArmyQueueWithAttackedOwner } from "../repository/army";
5 import { City, CityRepository } from "../repository/city";
6
7 const cityRepo = new CityRepository();
8
9 export function renderOverworldMap(cities: City[], yourCity: City): string {
10     let map: City[][] = new Array(100);
11     for(let i = 0; i < cities.length; ++i) {
12         if(!map[cities[i].location_y]) {
13             map[cities[i].location_y] = new Array(100);
14         }
15
16         map[cities[i].location_y][cities[i].location_x] = cities[i];
17     }
18
19     let rows: string[] = [];
20     for(let y = 0; y < 100; ++y) {
21         rows[y] = '<tr>';
22         for(let x = 0; x < 100; ++x) {
23             if(!map[y] || !map[y][x]) {
24                 rows[y] += '<td><div class="empty"></div></td>' ;
25             }
26             else if(map[y][x]) {
27                 if(map[y][x].id === yourCity.id)
28                     rows[y] += '<td><div class="city yours"></div></td>';
29                 else
30                     rows[y] += `<td><div class="city others" hx-trigger="click" hx-get="/city/${map[y][x].id}" hx-target="#city-offence"></div></td>`;
31             }
32             else {
33                 rows[y] += '<td><div class="empty"></div></td>';
34             }
35         }
36         rows[y] += '</tr>';
37     }
38     let html = `
39     <div id="city-offence"></div>
40     <div id="outgoing-attacks" hx-trigger="reload-outgoing-attacks, every 600s, load" hx-get="/attacks/outgoing"></div>
41     <table id="overworld-map">
42     ${rows.join("\n")}
43     </table>
44     
45     `;
46
47     return html;
48
49 }
50
51 export function listOperations(outgoingOps: ArmyQueueWithAttackedOwner[]): string {
52     let html = `
53     <h4>Outgoing Attacks</h4>
54     <table>
55     <tr>
56         <th>Destination</th>
57         <th>Sol.</th>
58         <th>Atk.</th>
59         <th>Def.</th>
60         <th>Sp. Atk.</th>
61         <th>Sp. Def.</th>
62         <th>Est. Arrival</th>
63     </tr>
64
65     ${outgoingOps.map(op => {
66         return `
67         <tr>
68             <td>${op.attacked_account} - (${op.location_x},${op.location_y})</td>
69             <td>${op.soldiers.toLocaleString()}</td>
70             <td>${op.attackers.toLocaleString()}</td>
71             <td>${op.defenders.toLocaleString()}</td>
72             <td>${op.sp_attackers.toLocaleString()}</td>
73             <td>${op.sp_defenders.toLocaleString()}</td>
74             <td>${ _.round(DateTime.fromMillis(op.due).diffNow().as('hours'), 2)} hours</td>
75         </tr>
76         `;
77     }).join("\n")}
78     </table>
79     `;
80
81     return html;
82 }
83
84 export async function launchOffensive(city: City, owner: Account, yourCity: City, you: Account): Promise<string> {
85     const distance = cityRepo.distanceInHours(city, yourCity);
86     const power = await cityRepo.power({
87         soldiers: yourCity.soldiers,
88         attackers: yourCity.attackers,
89         defenders: yourCity.defenders,
90         sp_attackers: yourCity.sp_attackers,
91         sp_defenders: yourCity.sp_defenders
92     })
93     let html = `
94     <h3>Viewing (${city.location_x},${city.location_y}) owned by ${owner.username}</h3>
95     <h4>Report</h4>
96     <p>This city is ${distance} hours away.</p>
97     <form hx-post="/attack">
98     <input type="hidden" name="city" value="${city.id}">
99     <table>
100     <tr>
101         <th>Soldiers</th>
102         <td>
103         <input type="number" class="potential-attack" name="soldiers" max="${yourCity.soldiers}" value="${yourCity.soldiers}" hx-target="#total-attack-power" hx-post="/attack-power" hx-include=".potential-attack">
104         (${yourCity.soldiers})
105         </td>
106     </tr>
107     <tr>
108         <th>Attackers</th>
109         <td>
110         <input type="number" class="potential-attack" name="attackers" max="${yourCity.attackers}" value="${yourCity.attackers}" hx-target="#total-attack-power" hx-post="/attack-power" hx-include=".potential-attack">
111         (${yourCity.attackers})
112         </td>
113     </tr>
114     <tr>
115         <th>Defenders</th>
116         <td>
117         <input type="number" class="potential-attack" name="defenders" max="${yourCity.defenders}" value="${yourCity.defenders}" hx-target="#total-attack-power" hx-post="/attack-power" hx-include=".potential-attack">
118         (${yourCity.defenders})
119         </td>
120     </tr>
121     <tr>
122         <th>Sp. Attack</th>
123         <td>
124         <input type="number" class="potential-attack" name="sp_attackers" max="${yourCity.sp_attackers}" value="${yourCity.sp_attackers}" hx-target="#total-attack-power" hx-post="/attack-power" hx-include=".potential-attack">
125         (${yourCity.sp_attackers})
126         </td>
127     </tr>
128     <tr>
129         <th>Sp. Defenders</th>
130         <td>
131         <input type="number" class="potential-attack" name="sp_defenders" max="${yourCity.sp_defenders}" value="${yourCity.sp_defenders}" hx-target="#total-attack-power" hx-post="/attack-power" hx-include=".potential-attack">
132         (${yourCity.sp_defenders})
133         </td>
134     </tr>
135     <tr>
136         <th>Total Power</th>
137         <td id="total-attack-power">${power}</td>
138     </tr>
139     <tr>
140         <td colspan="2" style="text-align: right">
141             <button type="submit">Attack (${city.location_x},${city.location_y})</button>
142         </td>
143     </tr>
144     </table>
145     </form>
146     `;
147
148     return html;
149 }