new spell system
This commit is contained in:
parent
63dabb9e54
commit
2e3a977530
BIN
data/dk.db
BIN
data/dk.db
Binary file not shown.
2
go.mod
2
go.mod
@ -3,7 +3,7 @@ module dk
|
||||
go 1.25.0
|
||||
|
||||
require (
|
||||
git.sharkk.net/Sharkk/Sashimi v1.1.3
|
||||
git.sharkk.net/Sharkk/Sashimi v1.1.4
|
||||
git.sharkk.net/Sharkk/Sushi v1.2.0
|
||||
github.com/valyala/fasthttp v1.65.0
|
||||
)
|
||||
|
4
go.sum
4
go.sum
@ -1,5 +1,5 @@
|
||||
git.sharkk.net/Sharkk/Sashimi v1.1.3 h1:fY63Zn//A1EffFkoKjCQseRmLFNRibNDZYPUur5SF1s=
|
||||
git.sharkk.net/Sharkk/Sashimi v1.1.3/go.mod h1:wTMnO6jo34LIjpDJ0qToq14RbwP6Uf4HtdWDmqxrdAM=
|
||||
git.sharkk.net/Sharkk/Sashimi v1.1.4 h1:aULzzz4Qqpl69Vtpbi7zYYvay4J/HzButYXLwPzB/xw=
|
||||
git.sharkk.net/Sharkk/Sashimi v1.1.4/go.mod h1:wTMnO6jo34LIjpDJ0qToq14RbwP6Uf4HtdWDmqxrdAM=
|
||||
git.sharkk.net/Sharkk/Sushi v1.2.0 h1:RwOCZmgaOqtkmuK2Z7/esdLbhSXJZphsOsWEHni4Sss=
|
||||
git.sharkk.net/Sharkk/Sushi v1.2.0/go.mod h1:S84ACGkuZ+BKzBO4lb5WQnm5aw9+l7VSO2T1bjzxL3o=
|
||||
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
|
||||
|
@ -2,7 +2,6 @@ package actions
|
||||
|
||||
import (
|
||||
"dk/internal/database"
|
||||
"dk/internal/helpers/exp"
|
||||
"dk/internal/models/fightlogs"
|
||||
"dk/internal/models/fights"
|
||||
"dk/internal/models/monsters"
|
||||
@ -147,22 +146,24 @@ func HandleSpell(fight *fights.Fight, user *users.User, spellID int) *FightResul
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("new MP is %d\n", user.MP-spell.MP)
|
||||
|
||||
result := &FightResult{
|
||||
UserUpdates: map[string]any{"mp": user.MP - spell.MP},
|
||||
}
|
||||
|
||||
switch spell.Type {
|
||||
case spells.TypeHealing:
|
||||
newHP := min(user.HP+spell.Attribute, user.MaxHP)
|
||||
case spells.TypeHeal:
|
||||
newHP := min(user.HP+spell.Power, user.MaxHP)
|
||||
result.UserUpdates["hp"] = newHP
|
||||
result.ActionText = fmt.Sprintf("You cast %s and healed %d HP!", spell.Name, spell.Attribute)
|
||||
result.LogAction = func() error { return fightlogs.AddSpellHeal(fight.ID, spell.Name, spell.Attribute) }
|
||||
result.ActionText = fmt.Sprintf("You cast %s and healed %d HP!", spell.Name, spell.Power)
|
||||
result.LogAction = func() error { return fightlogs.AddSpellHeal(fight.ID, spell.Name, spell.Power) }
|
||||
|
||||
case spells.TypeHurt:
|
||||
newMonsterHP := max(fight.MonsterHP-spell.Attribute, 0)
|
||||
case spells.TypeDamage:
|
||||
newMonsterHP := max(fight.MonsterHP-spell.Power, 0)
|
||||
result.FightUpdates = map[string]any{"monster_hp": newMonsterHP}
|
||||
result.ActionText = fmt.Sprintf("You cast %s and dealt %d damage!", spell.Name, spell.Attribute)
|
||||
result.LogAction = func() error { return fightlogs.AddSpellHurt(fight.ID, spell.Name, spell.Attribute) }
|
||||
result.ActionText = fmt.Sprintf("You cast %s and dealt %d damage!", spell.Name, spell.Power)
|
||||
result.LogAction = func() error { return fightlogs.AddSpellHurt(fight.ID, spell.Name, spell.Power) }
|
||||
|
||||
if newMonsterHP <= 0 {
|
||||
monster, err := monsters.Find(fight.MonsterID)
|
||||
@ -172,6 +173,33 @@ func HandleSpell(fight *fights.Fight, user *users.User, spellID int) *FightResul
|
||||
}
|
||||
}
|
||||
|
||||
case spells.TypeSleep:
|
||||
// For now, sleep spells do damage like the old system
|
||||
newMonsterHP := max(fight.MonsterHP-spell.Power, 0)
|
||||
result.FightUpdates = map[string]any{"monster_hp": newMonsterHP}
|
||||
result.ActionText = fmt.Sprintf("You cast %s and dealt %d damage!", spell.Name, spell.Power)
|
||||
result.LogAction = func() error { return fightlogs.AddSpellHurt(fight.ID, spell.Name, spell.Power) }
|
||||
|
||||
if newMonsterHP <= 0 {
|
||||
monster, err := monsters.Find(fight.MonsterID)
|
||||
if err == nil {
|
||||
result.EndFightWithVictory(monster, user)
|
||||
result.ActionText += " " + fmt.Sprintf("%s has been defeated!", monster.Name)
|
||||
}
|
||||
}
|
||||
|
||||
case spells.TypeUberAttack:
|
||||
// Apply attack buff for next attack
|
||||
result.FightUpdates = map[string]any{"uber_damage": spell.Power}
|
||||
result.ActionText = fmt.Sprintf("You cast %s! Your next attack will be %d%% stronger!", spell.Name, spell.Power)
|
||||
result.LogAction = func() error { return fightlogs.AddAction(fight.ID, result.ActionText) }
|
||||
|
||||
case spells.TypeUberDefense:
|
||||
// Apply defense buff
|
||||
result.FightUpdates = map[string]any{"uber_defense": spell.Power}
|
||||
result.ActionText = fmt.Sprintf("You cast %s! You will take %d%% less damage!", spell.Name, spell.Power)
|
||||
result.LogAction = func() error { return fightlogs.AddAction(fight.ID, result.ActionText) }
|
||||
|
||||
default:
|
||||
result.ActionText = "You cast " + spell.Name + " but nothing happened!"
|
||||
result.LogAction = func() error { return fightlogs.AddAction(fight.ID, result.ActionText) }
|
||||
@ -266,31 +294,6 @@ func HandleMonsterAttack(fight *fights.Fight, user *users.User) *FightResult {
|
||||
return result
|
||||
}
|
||||
|
||||
type LevelStats struct {
|
||||
Strength int
|
||||
Dexterity int
|
||||
}
|
||||
|
||||
func calculateLevelUp(currentLevel, newExp, currentStr, currentDex int) (int, LevelStats) {
|
||||
level := currentLevel
|
||||
str := currentStr
|
||||
dex := currentDex
|
||||
nexp := newExp
|
||||
|
||||
for {
|
||||
expNeeded := exp.Calc(level + 1)
|
||||
if nexp < expNeeded {
|
||||
break
|
||||
}
|
||||
level++
|
||||
str++
|
||||
dex++
|
||||
nexp -= expNeeded
|
||||
}
|
||||
|
||||
return level, LevelStats{Strength: str, Dexterity: dex}
|
||||
}
|
||||
|
||||
func findClosestTown(x, y int) *towns.Town {
|
||||
allTowns, err := towns.All()
|
||||
if err != nil || len(allTowns) == 0 {
|
||||
|
@ -2,7 +2,6 @@ package components
|
||||
|
||||
import (
|
||||
"dk/internal/helpers"
|
||||
"dk/internal/models/spells"
|
||||
"dk/internal/models/towns"
|
||||
"dk/internal/models/users"
|
||||
"fmt"
|
||||
@ -66,11 +65,12 @@ func RightAside(ctx sushi.Ctx) map[string]any {
|
||||
}
|
||||
|
||||
// Build known healing spells list
|
||||
if user.Spells != "" {
|
||||
userSpells, err := user.GetSpells()
|
||||
if err == nil {
|
||||
spellMap := helpers.NewOrderedMap[int, string]()
|
||||
for _, id := range user.GetSpellIDs() {
|
||||
if spell, err := spells.Find(id); err == nil {
|
||||
spellMap.Set(id, spell.Name)
|
||||
for _, spell := range userSpells {
|
||||
if spell.IsHeal() {
|
||||
spellMap.Set(spell.ID, spell.Name)
|
||||
}
|
||||
}
|
||||
data["_spells"] = spellMap.ToSlice()
|
||||
|
@ -8,29 +8,33 @@ import (
|
||||
|
||||
// Spell represents a spell in the game
|
||||
type Spell struct {
|
||||
ID int
|
||||
Name string
|
||||
MP int
|
||||
Attribute int
|
||||
Type int
|
||||
ID int
|
||||
Type int
|
||||
Name string
|
||||
Lore string
|
||||
Icon string
|
||||
MP int
|
||||
Power int
|
||||
}
|
||||
|
||||
// SpellType constants for spell types
|
||||
const (
|
||||
TypeHealing = 1
|
||||
TypeHurt = 2
|
||||
TypeSleep = 3
|
||||
TypeAttackBoost = 4
|
||||
TypeDefenseBoost = 5
|
||||
TypeHeal = 0
|
||||
TypeDamage = 1
|
||||
TypeSleep = 2
|
||||
TypeUberAttack = 3
|
||||
TypeUberDefense = 4
|
||||
)
|
||||
|
||||
// New creates a new Spell with sensible defaults
|
||||
func New() *Spell {
|
||||
return &Spell{
|
||||
Name: "",
|
||||
MP: 5,
|
||||
Attribute: 10,
|
||||
Type: TypeHealing,
|
||||
Type: TypeHeal,
|
||||
Name: "",
|
||||
Lore: "",
|
||||
Icon: "",
|
||||
MP: 5,
|
||||
Power: 10,
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,10 +46,10 @@ func (s *Spell) Validate() error {
|
||||
if s.MP < 0 {
|
||||
return fmt.Errorf("spell MP cannot be negative")
|
||||
}
|
||||
if s.Attribute < 0 {
|
||||
return fmt.Errorf("spell Attribute cannot be negative")
|
||||
if s.Power < 0 {
|
||||
return fmt.Errorf("spell Power cannot be negative")
|
||||
}
|
||||
if s.Type < TypeHealing || s.Type > TypeDefenseBoost {
|
||||
if s.Type < TypeHeal || s.Type > TypeUberDefense {
|
||||
return fmt.Errorf("invalid spell type: %d", s.Type)
|
||||
}
|
||||
return nil
|
||||
@ -108,39 +112,83 @@ func ByName(name string) (*Spell, error) {
|
||||
return &spell, nil
|
||||
}
|
||||
|
||||
// Helper methods
|
||||
func (s *Spell) IsHealing() bool {
|
||||
return s.Type == TypeHealing
|
||||
// Spell unlock functions
|
||||
func UnlocksForClassAtLevel(classID, level int) ([]*Spell, error) {
|
||||
var spells []*Spell
|
||||
query := `
|
||||
SELECT s.* FROM spells s
|
||||
JOIN spell_unlocks u ON s.id = u.spell_id
|
||||
WHERE u.class_id = %d AND u.level = %d
|
||||
ORDER BY s.type ASC, s.mp ASC, s.id ASC`
|
||||
err := database.Select(&spells, query, classID, level)
|
||||
return spells, err
|
||||
}
|
||||
|
||||
func (s *Spell) IsHurt() bool {
|
||||
return s.Type == TypeHurt
|
||||
func UserSpells(userID int) ([]*Spell, error) {
|
||||
var spells []*Spell
|
||||
query := `
|
||||
SELECT s.* FROM spells s
|
||||
JOIN user_spells us ON s.id = us.spell_id
|
||||
WHERE us.user_id = %d
|
||||
ORDER BY s.type ASC, s.mp ASC, s.id ASC`
|
||||
err := database.Select(&spells, query, userID)
|
||||
return spells, err
|
||||
}
|
||||
|
||||
func GrantSpell(userID, spellID int) error {
|
||||
return database.Exec("INSERT OR IGNORE INTO user_spells (user_id, spell_id) VALUES (%d, %d)", userID, spellID)
|
||||
}
|
||||
|
||||
func GrantSpells(userID int, spellIDs []int) error {
|
||||
return database.Transaction(func() error {
|
||||
for _, spellID := range spellIDs {
|
||||
if err := GrantSpell(userID, spellID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func HasSpell(userID, spellID int) bool {
|
||||
var count int
|
||||
err := database.Get(&count, "SELECT COUNT(*) FROM user_spells WHERE user_id = %d AND spell_id = %d", userID, spellID)
|
||||
return err == nil && count > 0
|
||||
}
|
||||
|
||||
// Helper methods
|
||||
func (s *Spell) IsHeal() bool {
|
||||
return s.Type == TypeHeal
|
||||
}
|
||||
|
||||
func (s *Spell) IsDamage() bool {
|
||||
return s.Type == TypeDamage
|
||||
}
|
||||
|
||||
func (s *Spell) IsSleep() bool {
|
||||
return s.Type == TypeSleep
|
||||
}
|
||||
|
||||
func (s *Spell) IsAttackBoost() bool {
|
||||
return s.Type == TypeAttackBoost
|
||||
func (s *Spell) IsUberAttack() bool {
|
||||
return s.Type == TypeUberAttack
|
||||
}
|
||||
|
||||
func (s *Spell) IsDefenseBoost() bool {
|
||||
return s.Type == TypeDefenseBoost
|
||||
func (s *Spell) IsUberDefense() bool {
|
||||
return s.Type == TypeUberDefense
|
||||
}
|
||||
|
||||
func (s *Spell) TypeName() string {
|
||||
switch s.Type {
|
||||
case TypeHealing:
|
||||
return "Healing"
|
||||
case TypeHurt:
|
||||
return "Hurt"
|
||||
case TypeHeal:
|
||||
return "Heal"
|
||||
case TypeDamage:
|
||||
return "Damage"
|
||||
case TypeSleep:
|
||||
return "Sleep"
|
||||
case TypeAttackBoost:
|
||||
return "Attack Boost"
|
||||
case TypeDefenseBoost:
|
||||
return "Defense Boost"
|
||||
case TypeUberAttack:
|
||||
return "Uber Attack"
|
||||
case TypeUberDefense:
|
||||
return "Uber Defense"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
@ -154,13 +202,13 @@ func (s *Spell) Efficiency() float64 {
|
||||
if s.MP == 0 {
|
||||
return 0
|
||||
}
|
||||
return float64(s.Attribute) / float64(s.MP)
|
||||
return float64(s.Power) / float64(s.MP)
|
||||
}
|
||||
|
||||
func (s *Spell) IsOffensive() bool {
|
||||
return s.Type == TypeHurt || s.Type == TypeSleep
|
||||
return s.Type == TypeDamage || s.Type == TypeSleep
|
||||
}
|
||||
|
||||
func (s *Spell) IsSupport() bool {
|
||||
return s.Type == TypeHealing || s.Type == TypeAttackBoost || s.Type == TypeDefenseBoost
|
||||
return s.Type == TypeHeal || s.Type == TypeUberAttack || s.Type == TypeUberDefense
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"dk/internal/helpers"
|
||||
"dk/internal/helpers/exp"
|
||||
"dk/internal/models/classes"
|
||||
"dk/internal/models/spells"
|
||||
)
|
||||
|
||||
// User represents a user in the game
|
||||
@ -208,16 +209,34 @@ func (u *User) IsAlive() bool {
|
||||
return u.HP > 0
|
||||
}
|
||||
|
||||
func (u *User) GetSpellIDs() []int {
|
||||
return helpers.StringToInts(u.Spells)
|
||||
}
|
||||
|
||||
func (u *User) SetSpellIDs(spells []int) {
|
||||
u.Spells = helpers.IntsToString(spells)
|
||||
func (u *User) GetSpells() ([]*spells.Spell, error) {
|
||||
return spells.UserSpells(u.ID)
|
||||
}
|
||||
|
||||
func (u *User) HasSpell(spellID int) bool {
|
||||
return slices.Contains(u.GetSpellIDs(), spellID)
|
||||
return spells.HasSpell(u.ID, spellID)
|
||||
}
|
||||
|
||||
func (u *User) GrantSpell(spellID int) error {
|
||||
return spells.GrantSpell(u.ID, spellID)
|
||||
}
|
||||
|
||||
func (u *User) GrantSpells(spellIDs []int) error {
|
||||
return spells.GrantSpells(u.ID, spellIDs)
|
||||
}
|
||||
|
||||
func (u *User) LearnNewSpells() error {
|
||||
newSpells, err := spells.UnlocksForClassAtLevel(u.ClassID, u.Level)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var spellIDs []int
|
||||
for _, spell := range newSpells {
|
||||
spellIDs = append(spellIDs, spell.ID)
|
||||
}
|
||||
|
||||
return u.GrantSpells(spellIDs)
|
||||
}
|
||||
|
||||
func (u *User) GetTownIDs() []int {
|
||||
@ -273,6 +292,7 @@ func (u *User) ExpNeededForNextLevel() int {
|
||||
}
|
||||
|
||||
func (u *User) GrantExp(expAmount int) map[string]any {
|
||||
oldLevel := u.Level
|
||||
newLevel, newStr, newDex, newExp := u.CalculateLevelUp(expAmount)
|
||||
|
||||
updates := map[string]any{
|
||||
@ -280,10 +300,18 @@ func (u *User) GrantExp(expAmount int) map[string]any {
|
||||
}
|
||||
|
||||
// Only include level/stats if they actually changed
|
||||
if newLevel > u.Level {
|
||||
if newLevel > oldLevel {
|
||||
updates["level"] = newLevel
|
||||
updates["strength"] = newStr
|
||||
updates["dexterity"] = newDex
|
||||
|
||||
// Learn new spells for each level gained
|
||||
for level := oldLevel + 1; level <= newLevel; level++ {
|
||||
if err := u.learnSpellsForLevel(level); err != nil {
|
||||
// Don't fail the level up if spells fail
|
||||
fmt.Printf("Failed to grant spells for level %d to user %d: %v\n", level, u.ID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return updates
|
||||
@ -333,3 +361,17 @@ func (u *User) Class() *classes.Class {
|
||||
}
|
||||
return class
|
||||
}
|
||||
|
||||
func (u *User) learnSpellsForLevel(level int) error {
|
||||
newSpells, err := spells.UnlocksForClassAtLevel(u.ClassID, level)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var spellIDs []int
|
||||
for _, spell := range newSpells {
|
||||
spellIDs = append(spellIDs, spell.ID)
|
||||
}
|
||||
|
||||
return u.GrantSpells(spellIDs)
|
||||
}
|
||||
|
@ -165,6 +165,12 @@ func processRegister(ctx sushi.Ctx) {
|
||||
return
|
||||
}
|
||||
|
||||
// Grant level 1 spells for their class
|
||||
if err := user.LearnNewSpells(); err != nil {
|
||||
// Don't fail registration if spells fail, just log it
|
||||
fmt.Printf("Failed to grant initial spells to user %d: %v\n", user.ID, err)
|
||||
}
|
||||
|
||||
// Auto-login after registration
|
||||
ctx.Login(user.ID, user)
|
||||
|
||||
|
@ -89,13 +89,10 @@ func showFight(ctx sushi.Ctx) {
|
||||
monHpColor = "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)
|
||||
}
|
||||
}
|
||||
var userSpells []*spells.Spell
|
||||
spellList, err := user.GetSpells()
|
||||
if err == nil {
|
||||
userSpells = spellList
|
||||
}
|
||||
|
||||
// Get recent fight actions
|
||||
@ -107,7 +104,7 @@ func showFight(ctx sushi.Ctx) {
|
||||
"monster": monster,
|
||||
"mon_hppct": monHpPct,
|
||||
"mon_hpcol": monHpColor,
|
||||
"spells": spellMap.ToSlice(),
|
||||
"spells": userSpells,
|
||||
"action": sess.GetFlashMessage("action"),
|
||||
"mon_action": sess.GetFlashMessage("mon_action"),
|
||||
"last_action": lastAction,
|
||||
|
57
sql/3_new_spell_system.sql
Normal file
57
sql/3_new_spell_system.sql
Normal file
@ -0,0 +1,57 @@
|
||||
-- Migration 3: new spell system
|
||||
-- Created: 2025-08-25 22:13:03
|
||||
|
||||
DROP TABLE IF EXISTS spells;
|
||||
|
||||
CREATE TABLE spells (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`type` INTEGER NOT NULL DEFAULT 0,
|
||||
`name` TEXT NOT NULL,
|
||||
`lore` TEXT DEFAULT '',
|
||||
`icon` TEXT DEFAULT '',
|
||||
`mp` INTEGER NOT NULL DEFAULT 0,
|
||||
`power` INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
-- Types: 0 (Heal), 1 (Damage), 2 (Sleep), 3 (Uber Attack), 4 (Uber Defense)
|
||||
INSERT INTO spells VALUES
|
||||
(1, 0, 'Heal', '', '', 5, 10),
|
||||
(2, 0, 'Revive', '', '', 10, 25),
|
||||
(3, 0, 'Life', '', '', 25, 50),
|
||||
(4, 0, 'Breath', '', '', 50, 100),
|
||||
(5, 0, 'Gaia', '', '', 75, 150),
|
||||
(6, 1, 'Hurt', '', '', 5, 15),
|
||||
(7, 1, 'Pain', '', '', 12, 35),
|
||||
(8, 1, 'Maim', '', '', 25, 70),
|
||||
(9, 1, 'Rend', '', '', 40, 100),
|
||||
(10, 1, 'Chaos', '', '', 50, 130),
|
||||
(11, 2, 'Sleep', '', '', 10, 5),
|
||||
(12, 2, 'Dream', '', '', 30, 9),
|
||||
(13, 2, 'Nightmare', '', '', 60, 13),
|
||||
(14, 3, 'Craze', '', '', 10, 10),
|
||||
(15, 3, 'Rage', '', '', 20, 25),
|
||||
(16, 3, 'Fury', '', '', 30, 50),
|
||||
(17, 4, 'Ward', '', '', 10, 10),
|
||||
(18, 4, 'Fend', '', '', 20, 25),
|
||||
(19, 4, 'Barrier', '', '', 30, 50),
|
||||
(20, 2, 'Spark', 'Small jolt of electric energy.', '', 5, 10),
|
||||
(21, 2, 'Firebolt', 'Blast of concentrated fire.', '', 10, 30),
|
||||
(22, 2, 'Geyser', 'Explosion of high-pressure water.', '', 15, 60),
|
||||
(23, 2, 'Magic Missile', 'Fast, tracking bolt of arcane force.', '', 20, 85);
|
||||
|
||||
CREATE TABLE spell_unlocks (
|
||||
`spell_id` INTEGER NOT NULL,
|
||||
`class_id` INTEGER NOT NULL,
|
||||
`level` INTEGER NOT NULL
|
||||
);
|
||||
|
||||
-- Classes: 1 (Adventurer), 2 (Mage), 3 (Warrior), 4 (Paladin)
|
||||
INSERT INTO spell_unlocks VALUES
|
||||
(1, 1, 3), (6, 1, 3), (11, 1, 7), (14, 1, 7), (17, 1, 7),
|
||||
(20, 2, 1), (21, 2, 5), (22, 2, 12), (23, 2, 22), (11, 2, 7), (17, 2, 10), (19, 2, 24),
|
||||
(1, 4, 1), (2, 4, 5), (3, 4, 10), (4, 4, 20);
|
||||
|
||||
CREATE TABLE user_spells (
|
||||
`user_id` INTEGER NOT NULL,
|
||||
`spell_id` INTEGER NOT NULL
|
||||
);
|
@ -22,7 +22,7 @@
|
||||
<div class="mb-05">
|
||||
<button type="submit" name="action" value="attack" class="btn btn-primary">Attack</button>
|
||||
</div>
|
||||
{if user.Spells != ""}
|
||||
{if spells}
|
||||
<div class="mb-05">
|
||||
<select id="spell-select" class="styled-select" name="spell_id">
|
||||
{for spell in spells}
|
||||
@ -37,4 +37,4 @@
|
||||
<button type="submit" name="action" value="run" class="btn">Run</button>
|
||||
</div>
|
||||
</form>
|
||||
{/block}
|
||||
{/block}
|
5
templates/fight/victory.html
Normal file
5
templates/fight/victory.html
Normal file
@ -0,0 +1,5 @@
|
||||
{include "layout.html"}
|
||||
|
||||
{block "content"}
|
||||
<h1>Victory!</h1>
|
||||
{/block}
|
Loading…
x
Reference in New Issue
Block a user