Improve rock attribution.
This commit is contained in:
+27
-10
@@ -172,7 +172,7 @@ type battleSide struct {
|
||||
petBonus int // Mammoth aura: +power for later friendly pets
|
||||
|
||||
oneShotRocks []setAsideRocks // Badger/Blowfish: on next own pet play
|
||||
recurringRocks []int // Snake: on every own pet play
|
||||
recurringRocks []setAsideRocks // Snake: on every own pet play
|
||||
lastPetRocks []lastPetVolley // Crocodile: when the enemy plays their last pet
|
||||
shieldCards []Card // Turtle set-aside cards, parallel to shields
|
||||
}
|
||||
@@ -194,6 +194,7 @@ type queuedPlay struct {
|
||||
effect Effect
|
||||
everyone bool // rock volley hits every active pet (Badger)
|
||||
release *Card // set-aside card to release once this play resolves (Blowfish/Badger/Croc)
|
||||
source *Card // set-aside pet credited as the effect's source (Blowfish/Badger/Croc/Snake)
|
||||
}
|
||||
|
||||
// effectCount resolves an effect's final count: base × Per statistic,
|
||||
@@ -389,7 +390,8 @@ func (g *Game) resolveBattle() {
|
||||
setAsideRocks{dice: e.count(), everyone: e.Target == "all", src: u.Card})
|
||||
setAside()
|
||||
case ActionRecurringRocks:
|
||||
s.recurringRocks = append(s.recurringRocks, e.count())
|
||||
s.recurringRocks = append(s.recurringRocks,
|
||||
setAsideRocks{dice: e.count(), src: u.Card})
|
||||
setAside()
|
||||
case ActionEnemyLastPetRocks:
|
||||
s.lastPetRocks = append(s.lastPetRocks, lastPetVolley{dice: e.count(), src: u.Card})
|
||||
@@ -457,7 +459,7 @@ func (g *Game) resolveBattle() {
|
||||
|
||||
// throwRocks rolls `dice` rock dice against one seat's pet. Rocks are
|
||||
// not "attacks with" the pet, so no knockout applies. Reports a kill.
|
||||
throwRocks := func(from, target, dice int) (killed bool) {
|
||||
throwRocks := func(from, target, dice int, source *Card) (killed bool) {
|
||||
tu := sides[target].unit
|
||||
if tu == nil {
|
||||
return false
|
||||
@@ -470,11 +472,24 @@ func (g *Game) resolveBattle() {
|
||||
}
|
||||
dealt, block := hitUnit(target, roll)
|
||||
died := !tu.Alive()
|
||||
// A set-aside pet (Snake/Blowfish/Badger/Croc) throws its rocks after a
|
||||
// different pet has been played, so credit `source` explicitly; only
|
||||
// fall back to the pet in play for direct throwers (Hedgehog/Rhino).
|
||||
var rockTxt string
|
||||
if source != nil {
|
||||
switch {
|
||||
case roll == 0:
|
||||
rockTxt = fmt.Sprintf("%s's set-aside rocks miss %s.", source.Name, tu.Card.Name)
|
||||
case died:
|
||||
rockTxt = fmt.Sprintf("%s's set-aside rocks pelt %s for %d — it faints.", source.Name, tu.Card.Name, roll)
|
||||
default:
|
||||
rockTxt = fmt.Sprintf("%s's set-aside rocks pelt %s for %d.", source.Name, tu.Card.Name, roll)
|
||||
}
|
||||
} else {
|
||||
thrower := pname(from)
|
||||
if su := sides[from].unit; su != nil {
|
||||
thrower = su.Card.Name
|
||||
}
|
||||
var rockTxt string
|
||||
switch {
|
||||
case roll == 0:
|
||||
rockTxt = fmt.Sprintf("%s's rocks miss %s.", thrower, tu.Card.Name)
|
||||
@@ -483,6 +498,7 @@ func (g *Game) resolveBattle() {
|
||||
default:
|
||||
rockTxt = fmt.Sprintf("%s pelts %s for %d.", thrower, tu.Card.Name, roll)
|
||||
}
|
||||
}
|
||||
emit(BattleEvent{
|
||||
Type: "rock", Seat: from, Target: target, Roll: roll, Dice: faces,
|
||||
DamageAfter: tu.Damage, TargetDied: died, Text: rockTxt,
|
||||
@@ -561,12 +577,13 @@ func (g *Game) resolveBattle() {
|
||||
for _, r := range s.oneShotRocks {
|
||||
src := r.src
|
||||
plays = append(plays, queuedPlay{seat: seat, everyone: r.everyone,
|
||||
effect: Effect{Action: ActionThrowRock, Count: r.dice}, release: &src})
|
||||
effect: Effect{Action: ActionThrowRock, Count: r.dice}, release: &src, source: &src})
|
||||
}
|
||||
s.oneShotRocks = nil
|
||||
for _, dice := range s.recurringRocks {
|
||||
for _, r := range s.recurringRocks {
|
||||
src := r.src
|
||||
plays = append(plays, queuedPlay{seat: seat,
|
||||
effect: Effect{Action: ActionThrowRock, Count: dice}})
|
||||
effect: Effect{Action: ActionThrowRock, Count: r.dice}, source: &src})
|
||||
}
|
||||
// Walk the pet's own play effects, then its active perk's, so a
|
||||
// play-time shield knows its source (an innate pet block vs a
|
||||
@@ -622,7 +639,7 @@ func (g *Game) resolveBattle() {
|
||||
for _, v := range os.lastPetRocks {
|
||||
src := v.src
|
||||
plays = append(plays, queuedPlay{seat: other,
|
||||
effect: Effect{Action: ActionThrowRock, Count: v.dice}, release: &src})
|
||||
effect: Effect{Action: ActionThrowRock, Count: v.dice}, release: &src, source: &src})
|
||||
}
|
||||
os.lastPetRocks = nil
|
||||
}
|
||||
@@ -669,12 +686,12 @@ func (g *Game) resolveBattle() {
|
||||
}
|
||||
if q.everyone {
|
||||
for seat := range sides {
|
||||
if throwRocks(q.seat, seat, dice) {
|
||||
if throwRocks(q.seat, seat, dice, q.source) {
|
||||
anyDeath = true
|
||||
}
|
||||
}
|
||||
} else if t := nextTarget(q.seat); t >= 0 {
|
||||
if throwRocks(q.seat, t, dice) {
|
||||
if throwRocks(q.seat, t, dice, q.source) {
|
||||
anyDeath = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,6 +588,12 @@ func TestSnakeRecurringRocks(t *testing.T) {
|
||||
if len(rocks) != 2 {
|
||||
t.Fatalf("snake should volley on each friendly play: %+v", rocks)
|
||||
}
|
||||
// The set-aside Snake threw the rocks, not the pet (A/B) in play.
|
||||
for _, r := range rocks {
|
||||
if !strings.Contains(r.Text, "Snake") {
|
||||
t.Fatalf("rock event should credit Snake as the source, got %q", r.Text)
|
||||
}
|
||||
}
|
||||
if res.WinnerSeat != -1 {
|
||||
t.Fatalf("expected draw, got %d", res.WinnerSeat)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user