add action handlers, update action tracking, add monster images, fix form
This commit is contained in:
parent
de0381f668
commit
0d3afffb1e
@ -212,6 +212,11 @@ button.btn {
|
|||||||
background-color: #00c6ff;
|
background-color: #00c6ff;
|
||||||
background-image: url("/assets/images/overlay.png"), linear-gradient(to bottom, #00c6ff, #0072ff);
|
background-image: url("/assets/images/overlay.png"), linear-gradient(to bottom, #00c6ff, #0072ff);
|
||||||
border-color: #0072ff;
|
border-color: #0072ff;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #49d6fd;
|
||||||
|
background-image: url("/assets/images/overlay.png"), linear-gradient(to bottom, #49d6fd, #2987fa);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,7 +416,7 @@ img#move-compass-disabled {
|
|||||||
|
|
||||||
img#monster-image {
|
img#monster-image {
|
||||||
display: block;
|
display: block;
|
||||||
max-height: 360px;
|
max-width: 80%;
|
||||||
margin: 1rem auto;
|
margin: 1rem auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,7 +458,7 @@ select.styled-select {
|
|||||||
color: white;
|
color: white;
|
||||||
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2);
|
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.2);
|
||||||
text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.1);
|
text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.1);
|
||||||
height: 28px;
|
height: 29px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #909090;
|
background-color: #909090;
|
||||||
|
BIN
assets/images/monsters/Critter.png
Normal file
BIN
assets/images/monsters/Critter.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
BIN
assets/images/monsters/Drake.png
Normal file
BIN
assets/images/monsters/Drake.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 335 KiB |
@ -1,86 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"user_id": 1,
|
|
||||||
"monster_id": 10,
|
|
||||||
"monster_hp": 16,
|
|
||||||
"monster_max_hp": 16,
|
|
||||||
"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": 1755215734,
|
|
||||||
"updated": 1755215734
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 2,
|
|
||||||
"user_id": 1,
|
|
||||||
"monster_id": 7,
|
|
||||||
"monster_hp": 12,
|
|
||||||
"monster_max_hp": 12,
|
|
||||||
"monster_sleep": 0,
|
|
||||||
"monster_immune": 1,
|
|
||||||
"uber_damage": 0,
|
|
||||||
"uber_defense": 0,
|
|
||||||
"first_strike": true,
|
|
||||||
"turn": 1,
|
|
||||||
"ran_away": false,
|
|
||||||
"victory": false,
|
|
||||||
"won": false,
|
|
||||||
"reward_gold": 0,
|
|
||||||
"reward_exp": 0,
|
|
||||||
"actions": [],
|
|
||||||
"created": 1755215776,
|
|
||||||
"updated": 1755215776
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 3,
|
|
||||||
"user_id": 1,
|
|
||||||
"monster_id": 8,
|
|
||||||
"monster_hp": 14,
|
|
||||||
"monster_max_hp": 14,
|
|
||||||
"monster_sleep": 0,
|
|
||||||
"monster_immune": 0,
|
|
||||||
"uber_damage": 0,
|
|
||||||
"uber_defense": 0,
|
|
||||||
"first_strike": true,
|
|
||||||
"turn": 1,
|
|
||||||
"ran_away": false,
|
|
||||||
"victory": false,
|
|
||||||
"won": false,
|
|
||||||
"reward_gold": 0,
|
|
||||||
"reward_exp": 0,
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
]
|
|
83
internal/actions/fight.go
Normal file
83
internal/actions/fight.go
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package actions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"dk/internal/models/fights"
|
||||||
|
"dk/internal/models/spells"
|
||||||
|
"dk/internal/models/users"
|
||||||
|
"math/rand"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HandleAttack(fight *fights.Fight, user *users.User) {
|
||||||
|
// 20% chance to miss
|
||||||
|
if rand.Float32() < 0.2 {
|
||||||
|
fight.AddActionAttackMiss()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fight.DamageMonster(1)
|
||||||
|
fight.AddActionAttackHit(1)
|
||||||
|
|
||||||
|
if fight.MonsterHP <= 0 {
|
||||||
|
fight.WinFight(10, 5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleSpell(fight *fights.Fight, user *users.User, spellID int) {
|
||||||
|
spell, err := spells.Find(spellID)
|
||||||
|
if err != nil {
|
||||||
|
fight.AddAction("Spell not found!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if user has enough MP
|
||||||
|
if user.MP < spell.MP {
|
||||||
|
fight.AddAction("Not enough MP to cast " + spell.Name + "!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if user knows this spell
|
||||||
|
if !user.HasSpell(spellID) {
|
||||||
|
fight.AddAction("You don't know that spell!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deduct MP
|
||||||
|
user.MP -= spell.MP
|
||||||
|
|
||||||
|
switch spell.Type {
|
||||||
|
case spells.TypeHealing:
|
||||||
|
// Heal user
|
||||||
|
healAmount := spell.Attribute
|
||||||
|
user.HP += healAmount
|
||||||
|
if user.HP > user.MaxHP {
|
||||||
|
user.HP = user.MaxHP
|
||||||
|
}
|
||||||
|
fight.AddAction("You cast " + spell.Name + " and healed " + strconv.Itoa(healAmount) + " HP!")
|
||||||
|
|
||||||
|
case spells.TypeHurt:
|
||||||
|
// Damage monster
|
||||||
|
damage := spell.Attribute
|
||||||
|
fight.DamageMonster(damage)
|
||||||
|
fight.AddAction("You cast " + spell.Name + " and dealt " + strconv.Itoa(damage) + " damage!")
|
||||||
|
|
||||||
|
// Check if monster is defeated
|
||||||
|
if fight.MonsterHP <= 0 {
|
||||||
|
fight.WinFight(10, 5) // Basic rewards
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
fight.AddAction("You cast " + spell.Name + " but nothing happened!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleRun(fight *fights.Fight, user *users.User) {
|
||||||
|
// 20% chance to successfully run away
|
||||||
|
if rand.Float32() < 0.2 {
|
||||||
|
fight.RunAway()
|
||||||
|
user.FightID = 0
|
||||||
|
fight.AddAction("You successfully ran away!")
|
||||||
|
} else {
|
||||||
|
fight.AddAction("You failed to run away!")
|
||||||
|
}
|
||||||
|
}
|
@ -28,8 +28,6 @@ import (
|
|||||||
|
|
||||||
"dk/internal/router"
|
"dk/internal/router"
|
||||||
"dk/internal/session"
|
"dk/internal/session"
|
||||||
|
|
||||||
"github.com/valyala/fasthttp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -182,8 +180,10 @@ func Middleware() router.Middleware {
|
|||||||
// Only validate CSRF for state-changing methods
|
// Only validate CSRF for state-changing methods
|
||||||
if method == "POST" || method == "PUT" || method == "PATCH" || method == "DELETE" {
|
if method == "POST" || method == "PUT" || method == "PATCH" || method == "DELETE" {
|
||||||
if !ValidateFormToken(ctx) {
|
if !ValidateFormToken(ctx) {
|
||||||
ctx.SetStatusCode(fasthttp.StatusForbidden)
|
fmt.Println("Failed CSRF validation.")
|
||||||
ctx.WriteString("CSRF validation failed")
|
RotateToken(ctx)
|
||||||
|
currentPath := string(ctx.Path())
|
||||||
|
ctx.Redirect(currentPath, 302)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,27 +6,45 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ActionEntry represents a compact fight action
|
||||||
|
type ActionEntry struct {
|
||||||
|
Type int `json:"t"`
|
||||||
|
Data int `json:"d,omitempty"`
|
||||||
|
Name string `json:"n,omitempty"` // For spell names
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action type constants
|
||||||
|
const (
|
||||||
|
ActionAttackHit = 1
|
||||||
|
ActionAttackMiss = 2
|
||||||
|
ActionSpellHeal = 3
|
||||||
|
ActionSpellHurt = 4
|
||||||
|
ActionRunSuccess = 5
|
||||||
|
ActionRunFail = 6
|
||||||
|
ActionGeneric = 7
|
||||||
|
)
|
||||||
|
|
||||||
// Fight represents a fight, past or present
|
// Fight represents a fight, past or present
|
||||||
type Fight struct {
|
type Fight struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
UserID int `json:"user_id"`
|
UserID int `json:"user_id"`
|
||||||
MonsterID int `json:"monster_id"`
|
MonsterID int `json:"monster_id"`
|
||||||
MonsterHP int `json:"monster_hp"`
|
MonsterHP int `json:"monster_hp"`
|
||||||
MonsterMaxHP int `json:"monster_max_hp"`
|
MonsterMaxHP int `json:"monster_max_hp"`
|
||||||
MonsterSleep int `json:"monster_sleep"`
|
MonsterSleep int `json:"monster_sleep"`
|
||||||
MonsterImmune int `json:"monster_immune"`
|
MonsterImmune int `json:"monster_immune"`
|
||||||
UberDamage int `json:"uber_damage"`
|
UberDamage int `json:"uber_damage"`
|
||||||
UberDefense int `json:"uber_defense"`
|
UberDefense int `json:"uber_defense"`
|
||||||
FirstStrike bool `json:"first_strike"`
|
FirstStrike bool `json:"first_strike"`
|
||||||
Turn int `json:"turn"`
|
Turn int `json:"turn"`
|
||||||
RanAway bool `json:"ran_away"`
|
RanAway bool `json:"ran_away"`
|
||||||
Victory bool `json:"victory"`
|
Victory bool `json:"victory"`
|
||||||
Won bool `json:"won"`
|
Won bool `json:"won"`
|
||||||
RewardGold int `json:"reward_gold"`
|
RewardGold int `json:"reward_gold"`
|
||||||
RewardExp int `json:"reward_exp"`
|
RewardExp int `json:"reward_exp"`
|
||||||
Actions []string `json:"actions"`
|
Actions []ActionEntry `json:"actions"`
|
||||||
Created int64 `json:"created"`
|
Created int64 `json:"created"`
|
||||||
Updated int64 `json:"updated"`
|
Updated int64 `json:"updated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Fight) Save() error {
|
func (f *Fight) Save() error {
|
||||||
@ -57,7 +75,7 @@ func New(userID, monsterID int) *Fight {
|
|||||||
Won: false,
|
Won: false,
|
||||||
RewardGold: 0,
|
RewardGold: 0,
|
||||||
RewardExp: 0,
|
RewardExp: 0,
|
||||||
Actions: make([]string, 0),
|
Actions: make([]ActionEntry, 0),
|
||||||
Created: now,
|
Created: now,
|
||||||
Updated: now,
|
Updated: now,
|
||||||
}
|
}
|
||||||
@ -86,6 +104,84 @@ func (f *Fight) Validate() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Action methods for backward compatibility
|
||||||
|
func (f *Fight) AddAction(action string) {
|
||||||
|
f.Actions = append(f.Actions, ActionEntry{Type: ActionGeneric, Name: action})
|
||||||
|
f.Updated = time.Now().Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Fight) AddActionAttackHit(damage int) {
|
||||||
|
f.Actions = append(f.Actions, ActionEntry{Type: ActionAttackHit, Data: damage})
|
||||||
|
f.Updated = time.Now().Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Fight) AddActionAttackMiss() {
|
||||||
|
f.Actions = append(f.Actions, ActionEntry{Type: ActionAttackMiss})
|
||||||
|
f.Updated = time.Now().Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Fight) AddActionSpellHeal(spellName string, healAmount int) {
|
||||||
|
f.Actions = append(f.Actions, ActionEntry{Type: ActionSpellHeal, Data: healAmount, Name: spellName})
|
||||||
|
f.Updated = time.Now().Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Fight) AddActionSpellHurt(spellName string, damage int) {
|
||||||
|
f.Actions = append(f.Actions, ActionEntry{Type: ActionSpellHurt, Data: damage, Name: spellName})
|
||||||
|
f.Updated = time.Now().Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Fight) AddActionRunSuccess() {
|
||||||
|
f.Actions = append(f.Actions, ActionEntry{Type: ActionRunSuccess})
|
||||||
|
f.Updated = time.Now().Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Fight) AddActionRunFail() {
|
||||||
|
f.Actions = append(f.Actions, ActionEntry{Type: ActionRunFail})
|
||||||
|
f.Updated = time.Now().Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert actions to human-readable strings
|
||||||
|
func (f *Fight) GetActions() []string {
|
||||||
|
result := make([]string, len(f.Actions))
|
||||||
|
for i, action := range f.Actions {
|
||||||
|
result[i] = f.actionToString(action)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Fight) actionToString(action ActionEntry) string {
|
||||||
|
switch action.Type {
|
||||||
|
case ActionAttackHit:
|
||||||
|
return fmt.Sprintf("You attacked for %d damage!", action.Data)
|
||||||
|
case ActionAttackMiss:
|
||||||
|
return "You missed your attack!"
|
||||||
|
case ActionSpellHeal:
|
||||||
|
return fmt.Sprintf("You cast %s and healed %d HP!", action.Name, action.Data)
|
||||||
|
case ActionSpellHurt:
|
||||||
|
return fmt.Sprintf("You cast %s and dealt %d damage!", action.Name, action.Data)
|
||||||
|
case ActionRunSuccess:
|
||||||
|
return "You successfully ran away!"
|
||||||
|
case ActionRunFail:
|
||||||
|
return "You failed to run away!"
|
||||||
|
case ActionGeneric:
|
||||||
|
return action.Name
|
||||||
|
default:
|
||||||
|
return "Unknown action"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Fight) GetLastAction() string {
|
||||||
|
if len(f.Actions) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return f.actionToString(f.Actions[len(f.Actions)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Fight) ClearActions() {
|
||||||
|
f.Actions = make([]ActionEntry, 0)
|
||||||
|
f.Updated = time.Now().Unix()
|
||||||
|
}
|
||||||
|
|
||||||
// FightStore with enhanced BaseStore
|
// FightStore with enhanced BaseStore
|
||||||
type FightStore struct {
|
type FightStore struct {
|
||||||
*store.BaseStore[Fight]
|
*store.BaseStore[Fight]
|
||||||
@ -311,24 +407,3 @@ func (f *Fight) DamageMonster(damage int) {
|
|||||||
}
|
}
|
||||||
f.Updated = time.Now().Unix()
|
f.Updated = time.Now().Unix()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Fight) AddAction(action string) {
|
|
||||||
f.Actions = append(f.Actions, action)
|
|
||||||
f.Updated = time.Now().Unix()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Fight) GetActions() []string {
|
|
||||||
return f.Actions
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Fight) GetLastAction() string {
|
|
||||||
if len(f.Actions) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return f.Actions[len(f.Actions)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Fight) ClearActions() {
|
|
||||||
f.Actions = make([]string, 0)
|
|
||||||
f.Updated = time.Now().Unix()
|
|
||||||
}
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package routes
|
package routes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"dk/internal/actions"
|
||||||
"dk/internal/auth"
|
"dk/internal/auth"
|
||||||
"dk/internal/components"
|
"dk/internal/components"
|
||||||
"dk/internal/helpers"
|
"dk/internal/helpers"
|
||||||
@ -11,6 +12,7 @@ import (
|
|||||||
"dk/internal/models/users"
|
"dk/internal/models/users"
|
||||||
"dk/internal/router"
|
"dk/internal/router"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RegisterFightRoutes(r *router.Router) {
|
func RegisterFightRoutes(r *router.Router) {
|
||||||
@ -19,6 +21,7 @@ func RegisterFightRoutes(r *router.Router) {
|
|||||||
group.Use(middleware.RequireFighting())
|
group.Use(middleware.RequireFighting())
|
||||||
|
|
||||||
group.Get("/", showFight)
|
group.Get("/", showFight)
|
||||||
|
group.Post("/", handleFightAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
func showFight(ctx router.Ctx, _ []string) {
|
func showFight(ctx router.Ctx, _ []string) {
|
||||||
@ -46,13 +49,13 @@ func showFight(ctx router.Ctx, _ []string) {
|
|||||||
fight.Save()
|
fight.Save()
|
||||||
}
|
}
|
||||||
|
|
||||||
hpPct := helpers.ClampPct(float64(user.HP), float64(user.MaxHP), 0, 100)
|
monHpPct := helpers.ClampPct(float64(fight.MonsterHP), float64(fight.MonsterMaxHP), 0, 100)
|
||||||
|
|
||||||
hpColor := ""
|
monHpColor := ""
|
||||||
if hpPct < 35 {
|
if monHpPct < 35 {
|
||||||
hpColor = "danger"
|
monHpColor = "danger"
|
||||||
} else if hpPct < 75 {
|
} else if monHpPct < 75 {
|
||||||
hpColor = "warning"
|
monHpColor = "warning"
|
||||||
}
|
}
|
||||||
|
|
||||||
spellMap := helpers.NewOrderedMap[int, *spells.Spell]()
|
spellMap := helpers.NewOrderedMap[int, *spells.Spell]()
|
||||||
@ -68,8 +71,42 @@ func showFight(ctx router.Ctx, _ []string) {
|
|||||||
"fight": fight,
|
"fight": fight,
|
||||||
"user": user,
|
"user": user,
|
||||||
"monster": monster,
|
"monster": monster,
|
||||||
"mon_hppct": hpPct,
|
"mon_hppct": monHpPct,
|
||||||
"mon_hpcol": hpColor,
|
"mon_hpcol": monHpColor,
|
||||||
"spells": spellMap.ToSlice(),
|
"spells": spellMap.ToSlice(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleFightAction(ctx router.Ctx, _ []string) {
|
||||||
|
user := ctx.UserValue("user").(*users.User)
|
||||||
|
|
||||||
|
fight, err := fights.Find(user.FightID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SetContentType("text/plain")
|
||||||
|
ctx.SetBodyString("Fight not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
action := string(ctx.FormValue("action"))
|
||||||
|
|
||||||
|
switch action {
|
||||||
|
case "attack":
|
||||||
|
actions.HandleAttack(fight, user)
|
||||||
|
case "spell":
|
||||||
|
spellIDStr := string(ctx.FormValue("spell_id"))
|
||||||
|
if spellID, err := strconv.Atoi(spellIDStr); err == nil {
|
||||||
|
actions.HandleSpell(fight, user, spellID)
|
||||||
|
}
|
||||||
|
case "run":
|
||||||
|
actions.HandleRun(fight, user)
|
||||||
|
default:
|
||||||
|
fight.AddAction("Invalid action!")
|
||||||
|
}
|
||||||
|
|
||||||
|
fight.IncrementTurn()
|
||||||
|
fight.Save()
|
||||||
|
user.Save()
|
||||||
|
|
||||||
|
// Redirect back to fight page
|
||||||
|
ctx.Redirect("/fight", 302)
|
||||||
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
{block "content"}
|
{block "content"}
|
||||||
<div id="battle-window">
|
<div id="battle-window">
|
||||||
<h2>Fighting {monster.Name}</h2>
|
<h2>{monster.Name}</h2>
|
||||||
<h3>Level {monster.Level}</h3>
|
<h3>Level {monster.Level}</h3>
|
||||||
|
|
||||||
<img id="monster-image" src="/assets/images/monsters/{monster.Name}.png" alt="{monster.Name}" title="{monster.Name}">
|
<img id="monster-image" src="/assets/images/monsters/{monster.Name}.png" alt="{monster.Name}" title="{monster.Name}">
|
||||||
@ -14,17 +14,24 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form action="/fight" method="post">
|
<form action="/fight" method="post">
|
||||||
|
{csrf}
|
||||||
|
|
||||||
<div class="mb-05">
|
<div class="mb-05">
|
||||||
<button class="btn btn-primary">Attack</button>
|
<button type="submit" name="action" value="attack" class="btn btn-primary">Attack</button>
|
||||||
</div>
|
</div>
|
||||||
{if user.Spells != ""}
|
{if user.Spells != ""}
|
||||||
<select id="spell-select" class="styled-select">
|
<div class="mb-05">
|
||||||
{for spell in spells}
|
<select id="spell-select" class="styled-select" name="spell_id">
|
||||||
<option value="{spell.ID}">({spell.MP} MP) {spell.Name}</option>
|
{for spell in spells}
|
||||||
{/for}
|
<option value="{spell.ID}">({spell.MP} MP) {spell.Name}</option>
|
||||||
</select>
|
{/for}
|
||||||
|
</select>
|
||||||
|
|
||||||
<button class="btn btn-blue">Spell</button>
|
<button type="submit" name="action" value="spell" class="btn btn-blue">Spell</button>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
<div>
|
||||||
|
<button type="submit" name="action" value="run" class="btn">Run</button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{/block}
|
{/block}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user