fix monsters in town

master
Denis Ranneft 1 month ago
parent 39ed3382fc
commit c58bd80f58

@ -914,6 +914,19 @@ func (e *Engine) startCombatLocked(hero *model.Hero, enemy *model.Enemy) {
return
}
}
if e.roadGraph != nil {
var wx, wy float64
if hm, ok := e.movements[hero.ID]; ok && hm.Hero != nil {
ox, oy := hm.displayOffset(now)
wx, wy = hm.CurrentX+ox, hm.CurrentY+oy
} else if hero != nil {
wx, wy = hero.PositionX, hero.PositionY
}
if e.roadGraph.HeroInTownAt(wx, wy) {
e.logger.Debug("skip combat start: hero inside town radius", "hero_id", hero.ID)
return
}
}
cs := &model.CombatState{
HeroID: hero.ID,

@ -868,11 +868,14 @@ func WanderingMerchantCost(level int) int64 {
}
// rollRoadEncounter returns whether to trigger an encounter; if so, monster true means combat.
func (hm *HeroMovement) rollRoadEncounter(now time.Time) (monster bool, enemy model.Enemy, hit bool) {
func (hm *HeroMovement) rollRoadEncounter(now time.Time, graph *RoadGraph) (monster bool, enemy model.Enemy, hit bool) {
cfg := tuning.Get()
if hm.Road == nil || len(hm.Road.Waypoints) < 2 {
return false, model.Enemy{}, false
}
if graph != nil && graph.HeroInTownAt(hm.worldPositionAt(now)) {
return false, model.Enemy{}, false
}
if now.Sub(hm.LastEncounterAt) < time.Duration(cfg.EncounterCooldownBaseMs)*time.Millisecond {
return false, model.Enemy{}, false
}
@ -1030,13 +1033,22 @@ func (hm *HeroMovement) Die() {
hm.State = model.StateDead
}
// worldPositionAt returns hero world (x,y) matching SyncToHero / hero_move (spine + display offset).
func (hm *HeroMovement) worldPositionAt(now time.Time) (x, y float64) {
if hm == nil || hm.Hero == nil {
return 0, 0
}
ox, oy := hm.displayOffset(now)
return hm.CurrentX + ox, hm.CurrentY + oy
}
// SyncToHero writes movement state back to the hero model for persistence.
// Position uses the same world coordinates as hero_move / position_sync (road spine + display offset).
func (hm *HeroMovement) SyncToHero() {
now := time.Now()
ox, oy := hm.displayOffset(now)
hm.Hero.PositionX = hm.CurrentX + ox
hm.Hero.PositionY = hm.CurrentY + oy
x, y := hm.worldPositionAt(now)
hm.Hero.PositionX = x
hm.Hero.PositionY = y
hm.Hero.State = hm.State
if hm.CurrentTownID != 0 {
id := hm.CurrentTownID
@ -1683,8 +1695,11 @@ func (hm *HeroMovement) applyRestHealTick(dt float64) {
}
}
func (hm *HeroMovement) rollAdventureEncounter(now time.Time) (monster bool, enemy model.Enemy, hit bool) {
func (hm *HeroMovement) rollAdventureEncounter(now time.Time, graph *RoadGraph) (monster bool, enemy model.Enemy, hit bool) {
cfg := tuning.Get()
if graph != nil && graph.HeroInTownAt(hm.worldPositionAt(now)) {
return false, model.Enemy{}, false
}
cooldown := time.Duration(cfg.AdventureEncounterCooldownMs) * time.Millisecond
if now.Sub(hm.LastEncounterAt) < cooldown {
return false, model.Enemy{}, false
@ -2195,7 +2210,7 @@ func ProcessSingleHeroMovementTick(
canEncounter := hm.Excursion.Phase == model.ExcursionWild ||
(hm.Excursion.Phase == model.ExcursionReturn && cfg.AdventureReturnEncounterEnabled)
if canEncounter && (onEncounter != nil || onMerchantEncounter != nil) {
monster, enemy, hit := hm.rollAdventureEncounter(now)
monster, enemy, hit := hm.rollAdventureEncounter(now, graph)
if hit {
if monster && onEncounter != nil {
hm.LastEncounterAt = now
@ -2272,7 +2287,7 @@ func ProcessSingleHeroMovementTick(
canRollEncounter := hm.Road != nil && len(hm.Road.Waypoints) >= 2
if canRollEncounter && (onEncounter != nil || sender != nil || onMerchantEncounter != nil) {
monster, enemy, hit := hm.rollRoadEncounter(now)
monster, enemy, hit := hm.rollRoadEncounter(now, graph)
if hit {
if monster {
if onEncounter != nil {

Loading…
Cancel
Save