chore(release): 0.3.3
[risinglegends.git] / src / server / views / fight.ts
1 import { FightRound } from "shared/fight";
2 import { LocationWithCity } from "shared/map";
3 import { Fight, MonsterForFight } from "../../shared/monsters";
4 import { Button, ButtonWithBlock } from "./components/button";
5
6 export function renderRoundDetails(roundData: FightRound): string {
7   let html: string[] = roundData.roundDetails.map(d => `<div>${d}</div>`);
8
9   switch(roundData.winner) {
10     case 'player':
11       html.push(`<div>You defeated the ${roundData.monster.name}!</div>`);
12       if(roundData.rewards.gold) {
13         html.push(`<div>You gained ${roundData.rewards.gold} gold</div>`);
14       }
15       if(roundData.rewards.exp) {
16         html.push(`<div>You gained ${roundData.rewards.exp} exp</div>`);
17       }
18       if(roundData.rewards.levelIncrease) {
19         html.push(`<div>You gained a level! ${roundData.player.level}</div>`);
20       }
21     break;
22     case 'monster':
23       if(roundData.player.hp === 0) {
24         html.push(`<p>You were killed...</p>`);
25       }
26       html.push('<p><button hx-get="/player/explore" hx-target="#explore">Back to Town</button></p>');
27     break;
28     case 'in-progress':
29       // fight still in progress, so we don't send any final actions back
30     break;
31   }
32
33
34   return html.join("\n");
35 }
36
37 function CastButton(blockTime?: number): string {
38   const attrs = {
39       id: 'cast-button',
40       type: 'submit', 
41       class: ['fight-action', 'red'],
42       name: 'action',
43       value: 'cast'
44   };
45
46   if(blockTime) {
47     return ButtonWithBlock(attrs, 'Cast', blockTime);
48   }
49   else {
50     return Button(attrs, 'Cast');
51   }
52
53 }
54
55 function AttackButton(blockTime?: number): string {
56   const attrs = {
57       id: 'attack-button',
58       type: 'submit', 
59       class: ['fight-action', 'red'],
60       name: 'action',
61       value: 'attack'
62   };
63
64   if(blockTime) {
65     return ButtonWithBlock(attrs, 'Attack', blockTime);
66   }
67   else {
68     return Button(attrs, 'Attack');
69   }
70 }
71
72 export function renderFight(monster: Fight, results: string = '', displayFightActions: boolean = true, blockTime: number = 0) {
73   const hpPercent = Math.floor((monster.hp / monster.maxHp) * 100);
74
75   let html = `
76   <div id="fight-container">
77     <div id="defender-info">
78       <div class="avatar-container">
79         <img id="avatar" src="https://via.placeholder.com/64x64">
80       </div>
81       <div id="defender-stat-bars">
82         <div class="monster-identifier ${monster.variant}"><span id="defender-name">${monster.name}</span>, level ${monster.level}</div>
83         <div class="progress-bar" id="defender-hp-bar" style="background: linear-gradient(to right, red, red ${hpPercent}%, transparent ${hpPercent}%, transparent)" title="${hpPercent}% - ${monster.hp}/${monster.maxHp}">${hpPercent}% - ${monster.hp} / ${monster.maxHp}</div>
84       </div>
85     </div>
86     <div id="fight-actions">
87       ${displayFightActions ? `
88       <form hx-post="/fight/turn" hx-target="#fight-container">
89         ${AttackButton(blockTime)}
90         ${CastButton(blockTime)}
91         <button type="submit" class="fight-action" name="action" value="flee">Flee</button>
92       </form>
93       `: ''}
94       </div>
95     <div id="fight-results">${results}</div>
96   </div>
97 </div>`;
98
99   return html;
100 }
101
102 export function renderFightPreRound(monster: Fight,  displayFightActions: boolean = true, location: LocationWithCity, closestTown: number) {
103   let html = `
104 <section id="explore" class="tab active" style="background-image: url('/assets/img/map/${closestTown}.jpeg')" hx-swap-oob="true">
105   <div class="city-title-wrapper">
106     <div class="city-title">${location.city_name}</div>
107   </div>
108   <div class="city-details">
109     <h3 class="location-name"><span>${location.name}</span></h3>
110
111     ${renderFight(monster, '', displayFightActions)}
112   </div>
113 </section>
114 `;
115
116   return html;
117 }