work on fight system, pass 2

This commit is contained in:
Sky Johnson 2025-08-14 22:33:51 -05:00
parent 674cfce506
commit de0381f668
9 changed files with 180 additions and 3 deletions

View File

@ -207,6 +207,12 @@ button.btn {
background-image: url("/assets/images/overlay.png"), linear-gradient(to bottom, #ffd965, #ffb574);
}
}
&.btn-blue {
background-color: #00c6ff;
background-image: url("/assets/images/overlay.png"), linear-gradient(to bottom, #00c6ff, #0072ff);
border-color: #0072ff;
}
}
form.standard {
@ -402,3 +408,64 @@ img#move-compass-disabled {
filter: grayscale();
margin-top: 0.5rem;
}
img#monster-image {
display: block;
max-height: 360px;
margin: 1rem auto;
}
div#monster-health {
display: flex;
background-color: rgba(0, 0, 0, 0.6);
height: 16px;
width: 100%;
border: 1px solid rgba(0, 0, 0, 0.6);
& > div.bar {
width: 100%;
height: 100%;
background: #56ab2f;
background: linear-gradient(to bottom, #a8e063, #56ab2f);
&.warning {
background: #F2994A;
background: linear-gradient(to bottom, #F2C94C, #F2994A);
}
&.danger {
background: #cb2d3e;
background: linear-gradient(to bottom, #ef473a, #cb2d3e);
}
}
}
select.styled-select {
font-family: inherit;
font-size: 1rem;
appearance: none;
outline: none;
background-color: #808080;
background-image: url("/assets/images/overlay.png");
border: 1px solid #808080;
padding: 0.25rem 0.5rem;
cursor: pointer;
color: white;
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2);
text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.1);
height: 28px;
&:hover {
background-color: #909090;
}
}
div#battle-window {
background: url("/assets/images/backgrounds/forest1.jpg");
background-size: cover;
padding: 0.5rem;
h2, h3 {
color: white;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 922 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

View File

@ -0,0 +1,27 @@
function addSelectArrows() {
const selects = document.querySelectorAll('select.styled-select')
selects.forEach(select => {
if (select.parentElement.classList.contains('select-wrapper')) return
select.style.paddingRight = '1.5rem'
const wrapper = document.createElement('div')
wrapper.className = 'select-wrapper'
wrapper.style.position = 'relative'
wrapper.style.display = 'inline-block'
select.parentNode.insertBefore(wrapper, select)
wrapper.appendChild(select)
const arrow = document.createElement('div')
arrow.innerHTML = `<svg width="16px" height="16px" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M19 13.5L15.5 17L12 13.5" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M15.5 17V11C15.5 8.79086 13.7091 7 11.5 7H4.5" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>`
arrow.style.position = 'absolute'
arrow.style.right = '5px'
arrow.style.top = '56%'
arrow.style.transform = 'translateY(-50%)'
arrow.style.pointerEvents = 'none'
wrapper.appendChild(arrow)
})
}

View File

@ -61,5 +61,26 @@
"actions": [],
"created": 1755215777,
"updated": 1755215777
},
{
"id": 4,
"user_id": 1,
"monster_id": 4,
"monster_hp": 10,
"monster_max_hp": 10,
"monster_sleep": 0,
"monster_immune": 0,
"uber_damage": 0,
"uber_defense": 0,
"first_strike": false,
"turn": 1,
"ran_away": false,
"victory": false,
"won": false,
"reward_gold": 0,
"reward_exp": 0,
"actions": [],
"created": 1755222893,
"updated": 1755222893
}
]

View File

@ -3,8 +3,11 @@ package routes
import (
"dk/internal/auth"
"dk/internal/components"
"dk/internal/helpers"
"dk/internal/middleware"
"dk/internal/models/fights"
"dk/internal/models/monsters"
"dk/internal/models/spells"
"dk/internal/models/users"
"dk/internal/router"
"math/rand"
@ -28,6 +31,13 @@ func showFight(ctx router.Ctx, _ []string) {
return
}
monster, err := monsters.Find(fight.MonsterID)
if err != nil {
ctx.SetContentType("text/plain")
ctx.SetBodyString("Monster not found for fight")
return
}
// If turn 0, determine first strike and advance to turn 1
if fight.Turn == 0 {
// 50% chance user goes first
@ -36,8 +46,30 @@ func showFight(ctx router.Ctx, _ []string) {
fight.Save()
}
hpPct := helpers.ClampPct(float64(user.HP), float64(user.MaxHP), 0, 100)
hpColor := ""
if hpPct < 35 {
hpColor = "danger"
} else if hpPct < 75 {
hpColor = "warning"
}
spellMap := helpers.NewOrderedMap[int, *spells.Spell]()
if user.Spells != "" {
for _, id := range user.GetSpellIDs() {
if spell, err := spells.Find(id); err == nil {
spellMap.Set(id, spell)
}
}
}
components.RenderPage(ctx, "Fighting", "fight/fight.html", map[string]any{
"fight": fight,
"user": user,
"fight": fight,
"user": user,
"monster": monster,
"mon_hppct": hpPct,
"mon_hpcol": hpColor,
"spells": spellMap.ToSlice(),
})
}

View File

@ -1,5 +1,30 @@
{include "layout.html"}
{block "content"}
ITS A FIGHT!
<div id="battle-window">
<h2>Fighting {monster.Name}</h2>
<h3>Level {monster.Level}</h3>
<img id="monster-image" src="/assets/images/monsters/{monster.Name}.png" alt="{monster.Name}" title="{monster.Name}">
</div>
<span>{fight.MonsterHP}/{fight.MonsterMaxHP}</span>
<div id="monster-health" class="mb-1">
<div class="bar {mon_hpcol}" style="width: {mon_hppct}%;"></div>
</div>
<form action="/fight" method="post">
<div class="mb-05">
<button class="btn btn-primary">Attack</button>
</div>
{if user.Spells != ""}
<select id="spell-select" class="styled-select">
{for spell in spells}
<option value="{spell.ID}">({spell.MP} MP) {spell.Name}</option>
{/for}
</select>
<button class="btn btn-blue">Spell</button>
{/if}
</form>
{/block}

View File

@ -9,6 +9,7 @@
<link rel="stylesheet" href="/assets/dk.css">
<script src="/assets/scripts/confirm_modal.js"></script>
<script src="/assets/scripts/select_arrows.js"></script>
<script>
function open_char_popup()
@ -65,5 +66,9 @@
</div>
{yield "scripts"}
<script>
document.addEventListener('DOMContentLoaded', addSelectArrows)
</script>
</body>
</html>