Skip to content

Commit

Permalink
Ouija: reduce active cost to 1, when destroyed increase opponent's ma…
Browse files Browse the repository at this point in the history
…xhp by 1

Jet Stream: revert attack buff back to 3
Martyr: heal for effective heal, not source heal amount
Corpse Explosion: exclude target from aoe
Legacy: print games to replay tab
Fix AI to act less crazy when hand full
  • Loading branch information
Philip Dubé committed Aug 26, 2023
1 parent 6d78103 commit 7db18e4
Show file tree
Hide file tree
Showing 11 changed files with 89 additions and 73 deletions.
2 changes: 1 addition & 1 deletion src/Cards.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
[["Mark of Entropy",5011,0,-1,"pillar","pillar+stackable+additive+charges=1"],["Mark of Entropy",7011,0,-1,"pillar+ownplay=pillar1","pillar+stackable+additive+charges=1"],["Amethyst Pillar",5100,0,0,"pillar","pillar+stackable+additive+charges=1"],["Amethyst Tower",7100,0,0,"pillar+ownplay=pillar1","pillar+stackable+additive+charges=1"],["Entropy Pendulum",5150,0,0,"pend","pillar+stackable+additive+charges=1"],["Entropy Pendulum",7150,0,0,"pend+ownplay=pillar1","pillar+stackable+additive+charges=1"],
["Ricochet",5117,3,2,"spell=ricochet",""],["Ricochet",7117,2,2,"spell=ricochet",""]],
[["Mark of Death",5012,0,-1,"pillar","pillar+stackable+additive+charges=1"],["Mark of Death",7012,0,-1,"pillar+ownplay=pillar1","pillar+stackable+additive+charges=1"],["Bone Pillar",5200,0,0,"pillar","pillar+stackable+additive+charges=1"],["Bone Tower",7200,0,0,"pillar+ownplay=pillar1","pillar+stackable+additive+charges=1"],["Death Pendulum",5250,0,0,"pend","pillar+stackable+additive+charges=1"],["Death Pendulum",7250,0,0,"pend+ownplay=pillar1","pillar+stackable+additive+charges=1"],
["Boneyard",5207,3,1,"death=boneyard",""],["Graveyard",7207,4,1,"death=boneyard",""],["Soul Catcher",5215,"1:0",1,"death=soulcatch",""],["Soul Catcher",7215,0,1,"death=soulcatch",""],["Ouija Essence",5216,3,2,"death=ouija+upkeep+owndiscard=hasten+2:5=ouijagrowth",""],["Ouija Source",7216,2,2,"death=ouija+upkeep+owndiscard=hasten+2:5=ouijagrowth",""],["Epidemic",5219,5,1,"death=epidemic",""],["Epidemic",7219,4,1,"death=epidemic",""]],
["Boneyard",5207,3,1,"death=boneyard",""],["Graveyard",7207,4,1,"death=boneyard",""],["Soul Catcher",5215,"1:0",1,"death=soulcatch",""],["Soul Catcher",7215,0,1,"death=soulcatch",""],["Ouija Essence",5216,3,2,"death=ouija+owndiscard=hasten+upkeep+owndestroy=ouijadestroy+1:5=ouijagrowth",""],["Ouija Source",7216,2,2,"death=ouija+owndiscard=hasten+upkeep+owndestroy=ouijadestroy+1:5=ouijagrowth",""],["Epidemic",5219,5,1,"death=epidemic",""],["Epidemic",7219,4,1,"death=epidemic",""]],
[["Mark of Gravity",5013,0,-1,"pillar","pillar+stackable+additive+charges=1"],["Mark of Gravity",7013,0,-1,"pillar+ownplay=pillar1","pillar+stackable+additive+charges=1"],["Gravity Pillar",5300,0,0,"pillar","pillar+stackable+additive+charges=1"],["Gravity Tower",7300,0,0,"pillar+ownplay=pillar1","pillar+stackable+additive+charges=1"],["Gravity Pendulum",5350,0,0,"pend","pillar+stackable+additive+charges=1"],["Gravity Pendulum",7350,0,0,"pend+ownplay=pillar1","pillar+stackable+additive+charges=1"],
["Catapult",5313,3,2,"2=catapult",""],["Catapult",7313,3,2,"1=catapult",""],["Inertia",5322,1,1,"spell=inertia",""],["Inertia",7322,"1:0",1,"spell=inertia",""]],
[["Mark of Earth",5014,0,-1,"pillar","pillar+stackable+additive+charges=1"],["Mark of Earth",7014,0,-1,"pillar+ownplay=pillar1","pillar+stackable+additive+charges=1"],["Stone Pillar",5400,0,0,"pillar","pillar+stackable+additive+charges=1"],["Stone Tower",7400,0,0,"pillar+ownplay=pillar1","pillar+stackable+additive+charges=1"],["Earth Pendulum",5450,0,0,"pend","pillar+stackable+additive+charges=1"],["Earth Pendulum",7450,0,0,"pend+ownplay=pillar1","pillar+stackable+additive+charges=1"],
Expand Down
12 changes: 12 additions & 0 deletions src/Game.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,18 @@ export default class Game {
canTarget(c, t) {
return this.game.can_target(c, t);
}
replayJson() {
return (
this.replay &&
JSON.stringify({
date: this.time,
seed: this.data.seed,
set: this.data.set,
players: this.data.players,
moves: this.replay,
})
);
}
}

function defineProp(key) {
Expand Down
37 changes: 18 additions & 19 deletions src/rs/src/aieval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@ fn eval_skill(
const SparkUp: u16 = card::Upped(card::Spark) as u16;
const Phantom: u16 = card::Phantom as u16;
const PhantomUp: u16 = card::Upped(card::Phantom) as u16;
const FireflyV: u16 = card::v_Firefly as u16;
const FireflyUpV: u16 = card::Upped(card::v_Firefly) as u16;
const ScarabV: u16 = card::v_Scarab as u16;
const ScarabUpV: u16 = card::Upped(card::v_Scarab) as u16;
skills
.iter()
.map(|&sk| match sk {
Expand Down Expand Up @@ -369,7 +373,7 @@ fn eval_skill(
Skill::freeze(x) | Skill::v_freeze(x) => x as f32,
Skill::freezeperm => 4.0,
Skill::fungusrebirth => 1.0,
Skill::gas | Skill::v_gas => 5.0,
Skill::gas => 5.0,
Skill::give => 1.0,
Skill::golemhit => {
let mut dmg = 0.0;
Expand Down Expand Up @@ -581,7 +585,7 @@ fn eval_skill(
Skill::siphonactive => 3.0,
Skill::siphonstrength => 4.0,
Skill::skyblitz => 10.0,
Skill::snipe => 7.0,
Skill::snipe => 3.0,
Skill::sosa | Skill::v_sosa => 6.0,
Skill::soulcatch => 2.0,
Skill::spores => 4.0,
Expand All @@ -593,10 +597,10 @@ fn eval_skill(
Skill::storm(x) | Skill::v_storm(x) | Skill::firestorm(x) => (x * 4) as f32,
Skill::summon(FateEgg) => 3.0,
Skill::summon(FateEggUp) => 4.0,
Skill::summon(Firefly) => 4.0,
Skill::summon(FireflyUp) => 5.0,
Skill::summon(Scarab) => 4.0,
Skill::summon(ScarabUp) => 4.5,
Skill::summon(Firefly) | Skill::summon(FireflyV) => 4.0,
Skill::summon(FireflyUp) | Skill::summon(FireflyUpV) => 5.0,
Skill::summon(Scarab) | Skill::summon(ScarabV) => 4.0,
Skill::summon(ScarabUp) | Skill::summon(ScarabUpV) => 4.5,
Skill::summon(Shadow) => 3.0,
Skill::summon(ShadowUp) => 4.0,
Skill::summon(Spark) => 2.0,
Expand Down Expand Up @@ -967,7 +971,7 @@ fn evalthing(
let mut poison = ctx.get(id, Stat::poison);
for &sk in ctx.getSkill(id, Event::OwnAttack).iter() {
match sk {
Skill::growth(gatk, ghp) => poison = poison.saturating_sub(ghp as i32),
Skill::growth(_, ghp) => poison = poison.saturating_sub(ghp as i32),
_ => (),
}
}
Expand Down Expand Up @@ -1080,7 +1084,7 @@ fn evalthing(
}
}
let flag = ctx.get_thing(id).flag;
if flag.get(Flag::airborne | Flag::ranged) {
if flag.get(Flag::airborne | Flag::ranged | Flag::whetstone) {
score += 0.2;
} else if flag.get(Flag::nightfall) {
score += 0.5;
Expand All @@ -1090,12 +1094,12 @@ fn evalthing(
score += 1.0;
}
if iscrea {
let hpf32 = hp as f32;
let voodoo = ctx.get(id, Flag::voodoo);
if voodoo && ctx.material(id, None) {
score += hp as f32 / 10.0;
score += hpf32 / 10.0;
}
if hp != 0 && ctx.get(owner, Stat::gpull) == id {
let hpf32 = hp as f32;
if voodoo {
score += hpf32;
}
Expand All @@ -1113,9 +1117,9 @@ fn evalthing(
} else {
score *= if hp != 0 {
if ctx.material(id, None) {
1.0 + (cmp::min(hp, 33) as f32).ln() / 7.0
1.0 + hpf32.sqrt() / (hpf32.sqrt() * 2.0 + 4.0)
} else {
1.3
1.5
}
} else if inhand {
0.9
Expand All @@ -1124,11 +1128,7 @@ fn evalthing(
}
}
} else {
score *= if ctx.get(id, Flag::immaterial) {
1.4
} else {
1.25
};
score *= if ctx.material(id, None) { 1.25 } else { 1.4 };
}
if inhand {
score * 0.9
Expand Down Expand Up @@ -1315,8 +1315,7 @@ pub fn eval(ctx: &Game) -> f32 {
if patience {
pscore += (ctx.count_creatures(pl) * 3) as f32;
}
pscore += (quantamap.get(pl, etg::Chroma) as f32) / 1188.0;
pscore += (player.quanta.iter().map(|q| *q as u32).sum::<u32>() as f32) / 1188.0;
pscore += (quantamap.get(pl, etg::Chroma) as u32 + player.quanta.iter().map(|q| *q as u32).sum::<u32>()) as f32 / 14256.0;
pscore += evalthing(
ctx,
&damage,
Expand Down
32 changes: 14 additions & 18 deletions src/rs/src/aisearch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,30 +27,21 @@ struct Candidate {
pub score: f32,
}

fn get_worst_card(ctx: &Game) -> Candidate {
fn get_worst_card(ctx: &Game) -> (i32, f32) {
if ctx.full_hand(ctx.turn) {
ctx.get_player(ctx.turn)
.hand
.iter()
.filter(|&&card| card != 0)
.map(|&card| {
let card = ctx.get_player(ctx.turn).hand[0];
let mut clone = ctx.clonegame();
clone.die(card);
let score = eval(&clone);
Candidate {
cmd: GameMove::End(card),
depth: 0,
score,
}
(card, eval(&clone))
})
.max_by(|a, b| a.score.partial_cmp(&b.score).unwrap_or(Ordering::Equal))
.max_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(Ordering::Equal))
.unwrap()
} else {
Candidate {
cmd: GameMove::End(0),
depth: 0,
score: eval(ctx),
}
(0, eval(ctx))
}
}

Expand Down Expand Up @@ -226,6 +217,7 @@ fn scancore(ctx: &Game, depth: i32, candy: &mut Candidate, limit: &mut u32, cmd:
| &[Skill::cseed2]
| &[Skill::mutation]
| &[Skill::improve]
| &[Skill::hatch]
) || ctx.hasskill(id, Event::Shield, Skill::randomdr)
|| ctx.hasskill(id, Event::OwnPlay, Skill::mutant)
{
Expand All @@ -242,7 +234,7 @@ fn scancore(ctx: &Game, depth: i32, candy: &mut Candidate, limit: &mut u32, cmd:
}) {
gclone.r#move(cmd);
}
let score = eval(&gclone);
let score = get_worst_card(&gclone).1;
if score > candy.score || (score == candy.score && depth < candy.depth) {
if depth == 0 {
*candy = Candidate { cmd, depth, score };
Expand Down Expand Up @@ -320,9 +312,13 @@ pub fn search(ctx: &Game) -> GameMove {
};
}
lethal(ctx).unwrap_or_else(|| {
let mut candy = get_worst_card(ctx);
let mut limit = 864;
scan(ctx, 0, &mut candy, &mut limit);
let (discard, score) = get_worst_card(ctx);
let mut candy = Candidate {
cmd: GameMove::End(discard),
depth: 0,
score,
};
scan(ctx, 0, &mut candy, &mut 1260);
candy.cmd
})
}
1 change: 1 addition & 0 deletions src/rs/src/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1761,6 +1761,7 @@ impl Game {
}
let mut dmgdata = ProcData::default();
dmgdata.dmg = dmg;
dmgdata.amt = capdmg;
self.proc_data(Event::Dmg, id, &mut dmgdata);
if realdmg > 0 {
if (!dontdie || kind == Kind::Player) && self.truehp(id) <= 0 {
Expand Down
47 changes: 28 additions & 19 deletions src/rs/src/skill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ pub enum Skill {
nymph,
obsession,
ouija,
ouijadestroy,
ouijagrowth,
pacify,
pairproduce,
Expand Down Expand Up @@ -578,7 +579,6 @@ pub enum Skill {
v_freeevade,
v_freeze(u8),
v_gaincharge2,
v_gas,
v_gpullspell,
v_gratitude,
v_guard,
Expand Down Expand Up @@ -1079,7 +1079,11 @@ impl Skill {
| Skill::v_storm(x) => x as i32,
Skill::summon(x) => x as i32,
Skill::quanta(x) => x as i32,
Skill::freeze(x) | Skill::v_drainlife(x) | Skill::v_firebolt(x) | Skill::v_freeze(x) | Skill::v_icebolt(x) => x as i32,
Skill::freeze(x)
| Skill::v_drainlife(x)
| Skill::v_firebolt(x)
| Skill::v_freeze(x)
| Skill::v_icebolt(x) => x as i32,
Skill::growth(x, _) | Skill::icegrowth(x, _) => x as i32,
_ => 0,
}
Expand Down Expand Up @@ -1512,8 +1516,10 @@ impl Skill {
owner
},
|ctx, cr| {
ctx.spelldmg(cr, dmg);
ctx.poison(cr, poison);
if cr != t {
ctx.spelldmg(cr, dmg);
ctx.poison(cr, poison);
}
},
);
ctx.spelldmg(foe, dmg);
Expand Down Expand Up @@ -2191,7 +2197,12 @@ impl Skill {
}
Self::gas => {
let owner = ctx.get_owner(c);
let gas = ctx.new_thing(card::As(ctx.get(c, Stat::card), card::UnstableGas), owner);
let gas = if ctx.cardset() == CardSet::Open {
card::UnstableGas
} else {
card::v_UnstableGas
};
let gas = ctx.new_thing(card::As(ctx.get(c, Stat::card), gas), owner);
ctx.addPerm(owner, gas);
}
Self::give => {
Expand Down Expand Up @@ -2698,7 +2709,7 @@ impl Skill {
Self::jetstream => {
if ctx.get(t, Flag::airborne) {
ctx.dmg(t, 1);
ctx.incrAtk(t, 4);
ctx.incrAtk(t, 3);
} else {
ctx.set(t, Flag::airborne, true);
}
Expand Down Expand Up @@ -2809,12 +2820,11 @@ impl Skill {
}
}
Self::martyr => {
let dmg = data.dmg;
if dmg > 0 {
ctx.incrAtk(c, dmg);
if data.dmg > 0 {
ctx.incrAtk(c, data.dmg);
} else {
let owner = ctx.get_owner(c);
ctx.dmg(owner, dmg);
ctx.dmg(owner, data.amt);
}
}
Self::mend => {
Expand Down Expand Up @@ -3057,6 +3067,11 @@ impl Skill {
ctx.addCard(foe, inst);
}
}
Self::ouijadestroy => {
let foe = ctx.get_foe(ctx.get_owner(c));
let maxhp = ctx.get_mut(foe, Stat::maxhp);
*maxhp = cmp::min(*maxhp + 1, 500);
}
Self::ouijagrowth => {
let foe = ctx.get_foe(ctx.get_owner(c));
let inst = ctx.new_thing(card::OuijaEssence, foe);
Expand Down Expand Up @@ -4374,12 +4389,6 @@ impl Skill {
data.evade = true;
}
}
Self::v_gas => {
let owner = ctx.get_owner(c);
let gas =
ctx.new_thing(card::As(ctx.get(c, Stat::card), card::v_UnstableGas), owner);
ctx.addPerm(owner, gas);
}
Self::v_gratitude => {
let owner = ctx.get_owner(c);
ctx.dmg(
Expand Down Expand Up @@ -4524,8 +4533,8 @@ impl Skill {
Skill::summon(1908),
Skill::snipe,
Skill::dive,
Skill::v_gas,
Skill::v_gas,
Skill::gas,
Skill::gas,
],
[
Skill::summon(2010),
Expand Down Expand Up @@ -4635,7 +4644,7 @@ impl Skill {
Skill::summon(_) => 2,
Skill::snipe => 2,
Skill::dive => 2,
Skill::v_gas => 2,
Skill::gas => 2,
Skill::deja => 4,
Skill::v_neuro => -2,
Skill::precognition => 2,
Expand Down
8 changes: 4 additions & 4 deletions src/skillText.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ const data = {
'Remove statuses (positive & negative) from target creature or permanent, & heal target creature 1.',
cold: '30% chance to freeze non-ranged attackers for 3 turns.',
corpseexplosion: [
'Sacrifice one of your creatures to deal 1 spell damage to all creatures. Increase damage by 1 for every 8 HP of the sacrifice. Poisonous sacrifices poison. Also affect opponent.',
'Sacrifice one of your creatures to deal 1 spell damage to all other creatures. Increase damage by 1 for every 8 HP of the sacrifice. Poisonous sacrifices poison. Also affect opponent.',
'Sacrifice one of your creatures to deal 1 spell damage to all enemy creatures. Increase damage by 1 for every 8 HP of the sacrifice. Poisonous sacrifices poison. Also affect opponent.',
],
counter:
Expand Down Expand Up @@ -389,6 +389,7 @@ const data = {
obsession: c =>
`When discarded, its owner receives ${c.upped ? 13 : 10} spell damage.`,
ouija: "Whenever a creature dies, add an Ouija Essence to opponent's hand.",
ouijadestroy: "When destroyed, add 1 to opponent's maximum health.",
ouijagrowth: "Summon an Ouija Essence on opponent's side of the field.",
pacify: "Set target creature or weapon's strength to 0.",
pairproduce: 'Your pillars, pendulums, and towers trigger as if end of turn.',
Expand Down Expand Up @@ -618,15 +619,15 @@ const data = {
"When this creature attacks, if any damage is blocked by opponent's shield, your maximum HP is increased by the amount of this creature's damage that was blocked.",
virusdeath: 'When this creature dies, give opponent 1 poison counter.',
virusinfect:
'Sacrifice this creature. Give target creature or player 1 poison counter.',
'Sacrifice this creature. Give target creature 1 poison counter. Give opponent 1 poison counter.',
virusplague:
"Sacrifice this creature. Give target player's creatures 1 poison counter.",
void: "Reduce opponent's maximum HP by 3.",
voidshell:
'Block all damage from attackers. Reduce your maximum HP equal to the damage blocked by this card.',
web: 'Target creature loses airborne status.',
weight: 'Evade all attackers that have more than 5 HP.',
wind: 'Restore any strentgh lost by halving after attacking.',
wind: 'Restore any strength lost by halving after attacking. Increase HP by amount restored.',
wings: 'Evade all non-airborne, non-ranged attackers.',
wisdom:
'Target creature or weapon gains 3|0. May target immaterial cards. If it targets an immaterial card, that card gains psionic. Psionic cards deal spell damage and typically bypass shields.',
Expand Down Expand Up @@ -672,7 +673,6 @@ const data = {
v_freeze: x => c =>
`Freeze target for ${x} turns. Being frozen disables attacking & per turn skills`,
v_gaincharge2: 'Gain 2 stacks per death.',
v_gas: 'Summon an Unstable Gas.',
v_gpullspell: 'Target creature intercepts attacks directed to its owner.',
v_gratitude: 'Heal owner 3, 5 if 1:5.',
v_guard: 'Delay target creature & attack target if grounded. Delay self.',
Expand Down
Loading

0 comments on commit 7db18e4

Please sign in to comment.