You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
169 lines
4.3 KiB
Go
169 lines
4.3 KiB
Go
package game
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/denisovdennis/autohero/internal/model"
|
|
)
|
|
|
|
func TestSimulateOneFight_HeroSurvives(t *testing.T) {
|
|
hero := &model.Hero{
|
|
Level: 1, XP: 0,
|
|
MaxHP: 10000, HP: 10000,
|
|
Attack: 100, Defense: 60, Speed: 1.0,
|
|
Strength: 10, Constitution: 10, Agility: 10, Luck: 5,
|
|
State: model.StateWalking,
|
|
}
|
|
|
|
now := time.Now()
|
|
survived, enemy, xpGained, goldGained := SimulateOneFight(hero, now, nil, nil, 100*time.Millisecond, VictoryRewardDeps{})
|
|
|
|
if !survived {
|
|
t.Fatalf("overpowered hero should survive, enemy was %s", enemy.Name)
|
|
}
|
|
if xpGained <= 0 {
|
|
t.Fatal("expected positive XP gain")
|
|
}
|
|
if goldGained <= 0 {
|
|
t.Fatal("expected positive gold gain")
|
|
}
|
|
if enemy.Name == "" {
|
|
t.Fatal("expected enemy with a name")
|
|
}
|
|
}
|
|
|
|
func TestSimulateOneFight_HeroDies(t *testing.T) {
|
|
hero := &model.Hero{
|
|
Level: 1, XP: 0,
|
|
MaxHP: 1, HP: 1,
|
|
Attack: 1, Defense: 0, Speed: 1.0,
|
|
State: model.StateWalking,
|
|
}
|
|
|
|
now := time.Now()
|
|
survived, _, _, _ := SimulateOneFight(hero, now, nil, nil, 100*time.Millisecond, VictoryRewardDeps{})
|
|
|
|
if survived {
|
|
t.Fatal("1 HP hero should die to any enemy")
|
|
}
|
|
if hero.HP != 0 {
|
|
t.Fatalf("expected HP 0 after death, got %d", hero.HP)
|
|
}
|
|
if hero.State != model.StateDead {
|
|
t.Fatalf("expected state dead, got %s", hero.State)
|
|
}
|
|
}
|
|
|
|
func TestSimulateOneFight_LevelUp(t *testing.T) {
|
|
// Seed XP just below L1->L2 threshold (100 XP with default tuning).
|
|
hero := &model.Hero{
|
|
Level: 1, XP: 99,
|
|
MaxHP: 10000, HP: 10000,
|
|
Attack: 100, Defense: 60, Speed: 1.0,
|
|
Strength: 10, Constitution: 10, Agility: 10, Luck: 5,
|
|
State: model.StateWalking,
|
|
}
|
|
|
|
now := time.Now()
|
|
survived, _, xpGained, _ := SimulateOneFight(hero, now, nil, nil, 100*time.Millisecond, VictoryRewardDeps{})
|
|
|
|
if !survived {
|
|
t.Fatal("overpowered hero should survive")
|
|
}
|
|
if xpGained <= 0 {
|
|
t.Fatal("expected XP gain")
|
|
}
|
|
if hero.Level < 2 {
|
|
t.Fatalf("expected level 2+ after gaining %d XP from 99 base, got level %d", xpGained, hero.Level)
|
|
}
|
|
}
|
|
|
|
func TestBuildEnemyInstanceForLevel_XPPerLevelRampsFrom10(t *testing.T) {
|
|
tmpl := model.Enemy{
|
|
BaseLevel: 1,
|
|
XPReward: 1,
|
|
XPPerLevel: 4,
|
|
IsElite: false,
|
|
}
|
|
early := BuildEnemyInstanceForLevel(tmpl, 6)
|
|
if early.XPReward != 1 {
|
|
t.Fatalf("normal mob instance L6: want base XP only (no per-level ramp), got %d", early.XPReward)
|
|
}
|
|
mid := BuildEnemyInstanceForLevel(tmpl, 12)
|
|
if mid.XPReward <= 1 {
|
|
t.Fatalf("normal mob instance L12: want xp_per_level applied, got %d", mid.XPReward)
|
|
}
|
|
elite := tmpl
|
|
elite.IsElite = true
|
|
el := BuildEnemyInstanceForLevel(elite, 5)
|
|
if el.XPReward <= 1 {
|
|
t.Fatalf("elite instance L5: want xp_per_level even before 10, got %d", el.XPReward)
|
|
}
|
|
}
|
|
|
|
func TestOfflineAutoPotionHook_DoesNotTriggerWhenHealthy(t *testing.T) {
|
|
hero := &model.Hero{
|
|
MaxHP: 100,
|
|
HP: 100,
|
|
Potions: 3,
|
|
}
|
|
if used := OfflineAutoPotionHook(hero, time.Now()); used {
|
|
t.Fatal("expected no potion usage when hero is above threshold")
|
|
}
|
|
if hero.Potions != 3 {
|
|
t.Fatalf("expected potions unchanged, got %d", hero.Potions)
|
|
}
|
|
}
|
|
|
|
func TestPickEnemyForLevel(t *testing.T) {
|
|
tests := []struct {
|
|
level int
|
|
}{
|
|
{1}, {5}, {10}, {20}, {50},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
enemy := PickEnemyForLevel(tt.level)
|
|
if enemy.Name == "" {
|
|
t.Errorf("PickEnemyForLevel(%d) returned enemy with empty name", tt.level)
|
|
}
|
|
if enemy.MaxHP <= 0 {
|
|
t.Errorf("PickEnemyForLevel(%d) returned enemy with MaxHP=%d", tt.level, enemy.MaxHP)
|
|
}
|
|
if enemy.HP != enemy.MaxHP {
|
|
t.Errorf("PickEnemyForLevel(%d) returned enemy with HP=%d != MaxHP=%d", tt.level, enemy.HP, enemy.MaxHP)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestScaleEnemyTemplate(t *testing.T) {
|
|
tmpl, ok := model.EnemyBySlug("wolf")
|
|
if !ok {
|
|
tmpl = model.Enemy{
|
|
Slug: "wolf",
|
|
Archetype: "wolf",
|
|
Name: "Forest Wolf",
|
|
MaxHP: 40,
|
|
HP: 40,
|
|
Attack: 8,
|
|
Defense: 2,
|
|
Speed: 1.2,
|
|
BaseLevel: 1,
|
|
LevelVariance: 0.3,
|
|
MaxHeroLevelDiff: 5,
|
|
HPPerLevel: 5,
|
|
AttackPerLevel: 1.5,
|
|
DefensePerLevel: 1.0,
|
|
}
|
|
}
|
|
scaled := ScaleEnemyTemplate(tmpl, 5)
|
|
|
|
if scaled.MaxHP <= tmpl.MaxHP {
|
|
t.Errorf("scaled MaxHP %d should exceed base %d at level 5", scaled.MaxHP, tmpl.MaxHP)
|
|
}
|
|
if scaled.HP != scaled.MaxHP {
|
|
t.Errorf("scaled HP %d should equal MaxHP %d", scaled.HP, scaled.MaxHP)
|
|
}
|
|
}
|