All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+### [0.3.1](https://git.xangelo.ca/?p=risinglegends.git;a=commitdiff;h=v0.3.1;hp=v0.3.0;ds=sidebyside) (2023-08-31)
+
+
+### Bug Fixes
+
+* add button that goes back to town from any page 06c0e48
+* spells support durability 2dbb9b8
+* stop z-stacking alert messages 6e756e8
+* tooltip text centered due to media-query cbfebd1
+
## [0.3.0](https://git.xangelo.ca/?p=risinglegends.git;a=commitdiff;h=v0.3.0;hp=v0.2.17;ds=sidebyside) (2023-08-30)
{
"name": "rising-legends",
- "version": "0.3.0",
+ "version": "0.3.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "rising-legends",
- "version": "0.3.0",
+ "version": "0.3.1",
"dependencies": {
"@honeycombio/opentelemetry-node": "^0.4.0",
"@opentelemetry/auto-instrumentations-node": "^0.37.0",
{
"name": "rising-legends",
"private": true,
- "version": "0.3.0",
+ "version": "0.3.1",
"scripts": {
"up": "npx prisma migrate dev --name \"init\"",
"start": "pm2 start dist/server/api.js",
}
#alerts {
- position: relative;
+ position: absolute;
+ right: 0;
+ bottom: 0;
}
.alert {
padding: 0.3rem;
max-width: 17rem;
- position: absolute;
- bottom: 1rem;
- right: 0;
line-height: 1.2rem;
+ box-shadow: -3px -3px 4px 0px rgba(0, 0, 0, 0.5);
}
.alert.success, button.success {
border: solid 1px #0a0;
}
#main-nav {
margin-bottom: 1rem;
+ position: relative;
}
#main-nav section {
min-height: 344px;
/* tooltip styling */
@media(pointer: coarse), (hover: none) {
- [title] {
+ .tooltip[title] {
position: realtive;
display: flex;
justify-content: center;
}
- [title]:focus::after {
+ .tooltip[title]:focus::after {
content: attr(title);
background-color: #fff;
color: #222;
<p><button class="btn" id="logout">Logout</button></p>
</div>
</section>
+ <div id="alerts"></div>
</div>
- <div id="alerts"></div>
<section id="chat">
<div id="chat-messages" hx-trigger="load delay:1s" hx-get="/chat/history" hx-swap="afterbegin"></div>
import { sample } from 'lodash';
import { City, Location } from "../../../shared/map";
import { renderPlayerBar } from "../../views/player-bar";
+import { BackToTown } from "../../views/components/button";
export const router = Router();
<h3 class="location-name"><span>${service.name}</span></h3>
<div class="service-in-town">
${text.join("\n")}
+${BackToTown()}
</div>
</div>
`);
await updatePlayer(req.player);
text.push(`<p>${getText('heal_successful', service, city)}</p>`);
- text.push('<p><button hx-get="/player/explore" hx-target="#explore">Back to Town</button></p>');
}
res.send(`
<h3 class="location-name"><span>${service.name}</span></h3>
<div class="service-in-town">
${text.join("\n")}
+${BackToTown()}
</div>
</div>
${renderPlayerBar(req.player)}
import * as Alert from "../views/alert";
import { changeProfession } from "../player";
import { renderPlayerBar } from "../views/player-bar";
+import { BackToTown } from "../views/components/button";
function p(str: string) {
return `<p>${str}</p>`;
html.push(`<p>However, you should visit the ${place} in ${town} that can probably provide some guidance!</p>`);
}
+ html.push(BackToTown());
res.send(`
<div class="city-title-wrapper"><div class="city-title">${service.city_name}</div></div>
<div class="city-details">
return `<button ${attributes.join(" ")}>${value}</button>`;
}
+
+export function BackToTown(): string {
+ return Button({
+ 'id': 'back-to-town',
+ 'hx-get': '/player/explore',
+ 'hx-target': '#explore'
+ }, 'Back to Town');
+}
import { EquippedItemDetails } from "../../shared/equipped";
import { PlayerItem } from "../../shared/items";
import { capitalize } from "lodash";
+import { ProgressBar } from "./components/progress-bar";
function icon(icon_name?: string): string {
const placeholder = 'https://placehold.co/64x64/af936c/6d5f4d';
return `<span class="requirement-title">${name}</span>: <span class="requirement-value ${typeof val === 'number' ? (val > 0 ? "success": "error") : ""}">${valSign}${val}</span>`;
}
-function generateProgressBar(current: number, max: number, color: string, displayPercent: boolean = true): string {
- let percent = 0;
- if(max > 0) {
- percent = Math.floor((current / max) * 100);
- }
- const display = `${displayPercent? `${percent}% - `: ''}`;
- return `<div class="progress-bar" style="background: linear-gradient(to right, ${color}, ${color} ${percent}%, transparent ${percent}%, transparent)" title="${display}${current}/${max}">${display}${current}/${max}</div>`;
-}
-
function renderInventoryItem(item: EquippedItemDetails , action: (item: EquippedItemDetails) => string): string {
return `<div class="store-list">
<div class="inventory-icon" style="background-image: url('${icon(item.icon)}')">
${item.boosts.intelligence ? renderStatBoost('INT', item.boosts.intelligence) : ''}
${item.boosts.damage ? renderStatBoost('DMG', item.boosts.damage) : ''}
${item.boosts.damage_mitigation ? renderStatBoost('MIT', item.boosts.damage_mitigation.toString())+'%' : ''}
- ${['SPELL'].includes(item.type) ? '': generateProgressBar(item.currentAp, item.maxAp, '#7be67b')}
+ ${ProgressBar(item.currentAp, item.maxAp, `dur-${item.item_id}`, {
+ startingColor: '#7be67b',
+ endingColor: '#7be67b',
+ displayPercent: false,
+ title: item.type === 'SPELL' ? 'Uses' : 'Durability'
+ })}
</div>
${item.hasOwnProperty('id') ? `<div>${item.cost.toLocaleString()}G</div>` : ''}
</div>
import { max } from "lodash";
import { LocationWithCity } from "../../shared/map";
import { Monster, MonsterForFight } from "../../shared/monsters";
+import { BackToTown } from "./components/button";
export function renderOnlyMonsterSelector(monsters: Monster[] | MonsterForFight[], activeMonsterId: number = 0, location?: LocationWithCity): string {
let html = `
const range = [monster.level, monster.level + 3];
return `<option value="${monster.id}" ${monster.id === activeMonsterId ? 'selected': ''}>${monster.name} (${range[0]} - ${range[1]})</option>`;
}).join("\n")}
- </select> <button type="submit" class="red">Fight</button></form></div>
+ </select> <button type="submit" class="red">Fight</button></form>
+<br><br>
+${BackToTown()}
+
+</div>
`;
return html;
StatDef.forEach(stat => {
statBreakdown += `<tr>
- <th title="${stat.description}" tabindex="0">${stat.display}</th>
+ <th title="${stat.description}" tabindex="0" class="tooltip">${stat.display}</th>
<td class="${stat.id}">
${player[stat.id].toLocaleString()}
${player.stat_points ? statPointIncreaser(stat) : ''}
const html = `<div id="extra-inventory-info">
<table class="stat-breakdown">
<tr>
- <th title="The total amount of damage you can take before you pass out" tabindex="0">HP</th>
+ <th title="The total amount of damage you can take before you pass out" tabindex="0" class="tooltip">HP</th>
<td>${player.hp.toLocaleString()}/${maxHp(player.constitution, player.level).toLocaleString()}</td>
</tr>
<tr>
- <th title="Your energy level. Low vigor will cause your overall defence and damage to drop." tabindex="0">Vigor</th>
+ <th title="Your energy level. Low vigor will cause your overall defence and damage to drop." tabindex="0" class="tooltip">Vigor</th>
<td>${player.vigor.toLocaleString()}/${maxVigor(player.constitution, player.level).toLocaleString()}</td>
</tr>
<tr>
- <th title="How many experience points you need to get to your next level" tabindex="0">EXP</th>
+ <th title="How many experience points you need to get to your next level" tabindex="0" class="tooltip">EXP</th>
<td>${player.exp.toLocaleString()}/${expToLevel(player.level + 1).toLocaleString()}</td>
</tr>
<tr>
- <th title="The max defence you can have (and your true defence affected by your vigor)" tabindex="0">Defence</th>
+ <th title="The max defence you can have (and your true defence affected by your vigor)" tabindex="0" class="tooltip">Defence</th>
<td>${totalDefence(equipment, player, false).toLocaleString()} (${totalDefence(equipment, player).toLocaleString()})</td>
</tr>
<tr>
- <th title="You can use these to increase the base stats below" tabindex="0">Stat Points</th>
+ <th title="You can use these to increase the base stats below" tabindex="0" class="tooltip">Stat Points</th>
<td class="stat_points">${player.stat_points}</td>
</tr>
${statBreakdown}
import { EquippedItemDetails } from "../../shared/equipped";
import { ProgressBar } from "./components/progress-bar";
import * as City from './components/city';
+import { BackToTown } from "./components/button";
function renderStatBoost(name: string, val: number | string): string {
let valSign: string = '';
${item.boosts.intelligence ? renderStatBoost('INT', item.boosts.intelligence) : ''}
${item.boosts.damage ? renderStatBoost(item.affectedSkills.includes('restoration_magic') ? 'HP' : 'DMG', item.boosts.damage) : ''}
${item.boosts.damage_mitigation ? renderStatBoost('MIT', item.boosts.damage_mitigation.toString())+'%' : ''}
- ${['WEAPON','SPELL'].includes(item.type) ? '' : ProgressBar(item.currentAp, item.maxAp, `${item.item_id}-ap`, {
+ ${ProgressBar(item.currentAp, item.maxAp, `${item.item_id}-ap`, {
displayPercent: false,
-title: 'Durability',
+title: item.type === 'SPELL' ? 'Uses' : 'Durability',
startingColor: '#7be67b',
endingColor: '#7be67b'
})}
}
equipment.forEach(item => {
+ if(item.maxAp <= 0) {
+ return;
+ }
const filter = item.type === 'ARMOUR' ? item.equipment_slot : item.type;
listingTypes.add(filter);
${finalListing.join("\n")}
</div>
</div>
+ ${BackToTown()}
`)}`;
return html;
import { Player } from "../../shared/player";
import { LocationWithCity } from "shared/map";
import { ProgressBar } from "./components/progress-bar";
+import { BackToTown } from "./components/button";
type RenderStatOptions = {
unsigned: boolean
}
export function renderEquipmentDetails(item: ShopEquipment, player: Player): string {
+ const isSpell = item.type === 'SPELL';
+
return `
<div class="details">
<div class="name">${item.name}${item.equipment_slot === 'TWO_HANDED' ? ' (2H)': ''}</div>
${item.boosts.intelligence ? renderStatBoost('INT', item.boosts.intelligence) : ''}
${item.boosts.damage ? renderStatBoost(item.affectedSkills.includes('restoration_magic') ? 'HP' : 'DMG', item.boosts.damage) : ''}
${item.boosts.damage_mitigation ? renderStatBoost('MIT', item.boosts.damage_mitigation.toString())+'%' : ''}
- ${['SPELL'].includes(item.type) ? '' : renderStat('Durability', 'DUR', item.maxAp, { unsigned: true })}
+ ${renderStat(isSpell ? 'Uses': 'Durability', isSpell ? 'Uses': 'DUR', item.maxAp, { unsigned: true })}
</div>
${item.hasOwnProperty('id') ? `<div class="store-cost">${item.cost.toLocaleString()}G</div>` : ''}
</div>
${finalListing.join("\n")}
</div>
</div>
+${BackToTown()}
</div>`;
return html;
import {Profession} from "./profession";
import {SkillID} from "./skills";
+import { max } from 'lodash';
export type InventoryType = 'ARMOUR' | 'WEAPON' | 'SPELL';
const damageRatio = 1 - (item.currentAp / item.maxAp);
- return Math.floor(totalCost * damageRatio);
+ return max([Math.floor(totalCost * damageRatio), 1]);
}