833341e17db62654aa698fc68257c9fad1b1ca6e
[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     <h2>Map</h2>
40     <div id="city-offence"></div>
41     <div id="outgoing-attacks" hx-trigger="reload-outgoing-attacks, every 600s, load" hx-get="/attacks/outgoing"></div>
42     <table id="overworld-map">
43     ${rows.join("\n")}
44     </table>
45     
46     `;
47
48     return html;
49
50 }
51
52 export function listOperations(outgoingOps: ArmyQueueWithAttackedOwner[]): string {
53     let html = `
54     <h4>Outgoing Attacks</h4>
55     <table>
56     <tr>
57         <th>Destination</th>
58         <th>Sol.</th>
59         <th>Atk.</th>
60         <th>Def.</th>
61         <th>Sp. Atk.</th>
62         <th>Sp. Def.</th>
63         <th>Est. Arrival</th>
64     </tr>
65
66     ${outgoingOps.map(op => {
67         return `
68         <tr>
69             <td>${op.attacked_account} - (${op.location_x},${op.location_y})</td>
70             <td>${op.soldiers.toLocaleString()}</td>
71             <td>${op.attackers.toLocaleString()}</td>
72             <td>${op.defenders.toLocaleString()}</td>
73             <td>${op.sp_attackers.toLocaleString()}</td>
74             <td>${op.sp_defenders.toLocaleString()}</td>
75             <td>${ _.round(DateTime.fromMillis(op.due).diffNow().as('hours'), 2)} hours</td>
76         </tr>
77         `;
78     }).join("\n")}
79     </table>
80     `;
81
82     return html;
83 }
84
85 export async function launchOffensive(city: City, owner: Account, yourCity: City, you: Account): Promise<string> {
86     const distance = cityRepo.distanceInHours(city, yourCity);
87     const power = await cityRepo.power({
88         soldiers: yourCity.soldiers,
89         attackers: yourCity.attackers,
90         defenders: yourCity.defenders,
91         sp_attackers: yourCity.sp_attackers,
92         sp_defenders: yourCity.sp_defenders
93     })
94     let html = `
95     <h3>Viewing (${city.location_x},${city.location_y}) owned by ${owner.username}</h3>
96     <h4>Report</h4>
97     <p>This city is ${distance} hours away.</p>
98     <form hx-post="/attack">
99     <input type="hidden" name="city" value="${city.id}">
100     <table>
101     <tr>
102         <th>Soldiers</th>
103         <td>
104         <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">
105         (${yourCity.soldiers})
106         </td>
107     </tr>
108     <tr>
109         <th>Attackers</th>
110         <td>
111         <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">
112         (${yourCity.attackers})
113         </td>
114     </tr>
115     <tr>
116         <th>Defenders</th>
117         <td>
118         <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">
119         (${yourCity.defenders})
120         </td>
121     </tr>
122     <tr>
123         <th>Sp. Attack</th>
124         <td>
125         <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">
126         (${yourCity.sp_attackers})
127         </td>
128     </tr>
129     <tr>
130         <th>Sp. Defenders</th>
131         <td>
132         <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">
133         (${yourCity.sp_defenders})
134         </td>
135     </tr>
136     <tr>
137         <th>Total Power</th>
138         <td id="total-attack-power">${power}</td>
139     </tr>
140     <tr>
141         <td colspan="2" style="text-align: right">
142             <button type="submit">Attack (${city.location_x},${city.location_y})</button>
143         </td>
144     </tr>
145     </table>
146     </form>
147     `;
148
149     return html;
150 }