matteoferla / DnD-battler

A 5e D&D encounter simulator written for my own amusement to test some hypotheses.
MIT License
80 stars 31 forks source link

.addmob reverses sides? #19

Closed bluetyson closed 2 years ago

bluetyson commented 2 years ago
billbybob4 = Creature.load('Plumber')
level1 = Creature.load('Amazing Martial Artist')
arena2 = Encounter(level1, billbybob4)
print("Encounter Martial Artist v Plumber")

arena3 = Encounter(Creature.load('Amazing Martial Artist')).addmobFASERIP(1)  #just a Plumber rather than Dnd Commoner
print("AddMob Martial Artist v Plumber")

assert dir(arena2) == dir(arena3)

for x in arena2.__dict__:
    print(x, arena2.__dict__[x])

tally {'rounds': 0, 'battles': 0, 'perfect': {'trade': 0, 'brucelee': 0}, 'close': {'trade': 0, 'brucelee': 0}, 'victories': {'trade': 0, 'brucelee': 0}}
active None
name Encounter
masterlog []
note
combattants [<DnD_battler.creature.Creature object at 0x000002EE06487FA0>, <DnD_battler.creature.Creature object at 0x000002EE06487C10>, <DnD_battler.creature.Creature object at 0x000002EE06487FA0>, <DnD_battler.creature.Creature object at 0x000002EE06487C10>]
sides {'trade', 'brucelee'}

for x in arena3.__dict__:
    print(x, arena3.__dict__[x])

sides {'trade', 'brucelee'}
tally {'rounds': 0, 'battles': 0, 'perfect': {'brucelee': 0, 'mob': 0}, 'close': {'brucelee': 0, 'mob': 0}, 'victories': {'brucelee': 0, 'mob': 0}}
active None
name Encounter
masterlog []
note
combattants [<DnD_battler.creature.Creature object at 0x000002EE064873A0>, <DnD_battler.creature.Creature object at 0x000002EE064873A0>, <DnD_battler.creature.Creature object at 0x000002EE06487820>]
sides {'brucelee', 'mob'}

The arena3 version has the Amazing Martial Artist lose, so sides different, note sure if I messed anything up. e.g. Shang Chi vs a Plumber if a straightout punchup can't lose.

Don't understand enough about append/load etc. to see why, but presumably something there might be flipping them - or is it just luck of the alpha draw if they are the right way or something?

bluetyson commented 2 years ago

Assuming I did everything ok [some assumption] - here's Arena2 example

================================================== Encounter ==================================================
Rough a priori predictions:
> trade= expected rounds to survive: 4.62; crudely normalised: 0%
> brucelee= expected rounds to survive: 39.22; crudely normalised: 0%
--------------------------------------------------------------------------------------------------------------
Battles: 1; Sum of rounds: 1; trade: 0.0 ± 0.0; brucelee: 1.0 ± 0.0;
> Team trade = winning battles: 0; perfect battles: 0; close-call battles: 0;
> Team brucelee = winning battles: 1; perfect battles: 0; close-call battles: 0;
------------------------------------------------- Combattants  ------------------------------------------------
Amazing Martial Artist: {team=brucelee; avg Health=120.0 (from 120); damage done (per battle average)= 14.0; hits/slams/stuns/kills/misses (PBA)= 0.5/0.5/0.0/0.0/0.0; rounds (PBA)=1.0;}
Amazing Martial Artist: {team=brucelee; avg Health=120.0 (from 120); damage done (per battle average)= 14.0; hits/slams/stuns/kills/misses (PBA)= 0.5/0.5/0.0/0.0/0.0; rounds (PBA)=1.0;}
Plumber: {team=trade; avg Health=-4.0 (from 24); damage done (per battle average)= 0.0; hits/slams/stuns/kills/misses (PBA)= 0.0/0.0/0.0/0.0/0.0; rounds (PBA)=0.0;}
Plumber: {team=trade; avg Health=-4.0 (from 24); damage done (per battle average)= 0.0; hits/slams/stuns/kills/misses (PBA)= 0.0/0.0/0.0/0.0/0.0; rounds (PBA)=0.0;}

mechanically, basically 50% chance for Martial Artist to put Plumber though a wall first round - and likely to win Initiative - and then Plumber is done.

the Arena3 version

================================================== Encounter ==================================================
Rough a priori predictions:
> mob= expected rounds to survive: 2.31; crudely normalised: 0%
> brucelee= expected rounds to survive: 78.43; crudely normalised: 0%
--------------------------------------------------------------------------------------------------------------
Battles: 1; Sum of rounds: 51; mob: 1.0 ± 0.0; brucelee: 0.0 ± 0.0;
> Team mob = winning battles: 1; perfect battles: 0; close-call battles: 0;
> Team brucelee = winning battles: 0; perfect battles: 0; close-call battles: 0;
------------------------------------------------- Combattants  ------------------------------------------------
Plumber: {team=mob; avg Health=24.0 (from 24); damage done (per battle average)= 120.0; hits/slams/stuns/kills/misses (PBA)= 20.0/0.0/0.0/0.0/30.0; rounds (PBA)=51.0;}
Amazing Martial Artist: {team=brucelee; avg Health=0.0 (from 120); damage done (per battle average)= 0.0; hits/slams/stuns/kills/misses (PBA)= 0.0/0.0/0.0/0.0/0.0; rounds (PBA)=49.0;}
Amazing Martial Artist: {team=brucelee; avg Health=0.0 (from 120); damage done (per battle average)= 0.0; hits/slams/stuns/kills/misses (PBA)= 0.0/0.0/0.0/0.0/0.0; rounds (PBA)=49.0;}

something odd going on there that I don't get yet.

bluetyson commented 2 years ago

I'll try your dragon example tomorrow, just have to fix the same things I changed to get this to work.

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_49812/3518064445.py in <module>
      1 bill = Creature.load("ancient blue dragon")
      2 bill.alt_attack['name'] = 'whackwithsheep'
----> 3 print(Encounter(Creature.load("ancient blue dragon")).addmob(85).go_to_war(10))  #An ancient blue dragon is nearly a match for 85 commoners (who crit evenutally)...

j:\clone\dnd-battler\DnD_battler\encounter\_action.py in go_to_war(self, rounds)
    157     def go_to_war(self, rounds=1000):
    158         for i in range(rounds):
--> 159             self.battle(1, 0)
    160         x = {y: self.tally['victories'][y] for y in self.sides}
    161         se = {}

j:\clone\dnd-battler\DnD_battler\encounter\_action.py in battle(self, reset, verbose)
    129                         self.active = character
    130                         character.tally['rounds'] += 1
--> 131                         character.act(self.masterlog)
    132                     else:
    133                         character.tally['dead'] += 1

j:\clone\dnd-battler\DnD_battler\creature\_action.py in act(self, verbose)
    157                 print(self.name + " is dodging")
    158             self.dodge = 1
--> 159         elif economy and self.alt_attack['name'] == 'net':
    160             opponent = self.arena.find('fiersomest enemy alive', self)[0]
    161             if opponent.condition != 'netted':

KeyError: 'name'
bluetyson commented 2 years ago

I installed your dev version, so will require a bit of site library hacking to get that to work. In the ancient blue dragon case, don't think nets will be what they need anyway. :)

bluetyson commented 2 years ago

These both seem fine though

billbybob15 = Creature.load('Plumber', alignment="mob")
level15 = Creature.load('Amazing Martial Artist')
arena4 = Encounter(billbybob15, level15)
print(arena4.go_to_war(1))
================================================== Encounter ==================================================
Rough a priori predictions:
> mob= expected rounds to survive: 4.62; crudely normalised: 0%
> brucelee= expected rounds to survive: 39.22; crudely normalised: 0%
--------------------------------------------------------------------------------------------------------------
Battles: 1; Sum of rounds: 3; mob: 0.0 ± 0.0; brucelee: 1.0 ± 0.0;
> Team mob = winning battles: 0; perfect battles: 0; close-call battles: 0;
> Team brucelee = winning battles: 1; perfect battles: 0; close-call battles: 0;
------------------------------------------------- Combattants  ------------------------------------------------
Amazing Martial Artist: {team=brucelee; avg Health=108.0 (from 120); damage done (per battle average)= 14.0; hits/slams/stuns/kills/misses (PBA)= 0.5/0.5/0.0/0.0/1.5; rounds (PBA)=2.5;}
Plumber: {team=mob; avg Health=-4.0 (from 24); damage done (per battle average)= 6.0; hits/slams/stuns/kills/misses (PBA)= 1.0/0.0/0.0/0.0/0.5; rounds (PBA)=1.5;}
Amazing Martial Artist: {team=brucelee; avg Health=108.0 (from 120); damage done (per battle average)= 14.0; hits/slams/stuns/kills/misses (PBA)= 0.5/0.5/0.0/0.0/1.5; rounds (PBA)=2.5;}
Plumber: {team=mob; avg Health=-4.0 (from 24); damage done (per battle average)= 6.0; hits/slams/stuns/kills/misses (PBA)= 1.0/0.0/0.0/0.0/0.5; rounds (PBA)=1.5;}

billbybob16 = Creature.load('Plumber', alignment="mob")
level16 = Creature.load('Amazing Martial Artist')
arena5 = Encounter(level16, billbybob16)
print(arena5.go_to_war(1))
================================================== Encounter ==================================================
Rough a priori predictions:
> mob= expected rounds to survive: 4.62; crudely normalised: 0%
> brucelee= expected rounds to survive: 39.22; crudely normalised: 0%
--------------------------------------------------------------------------------------------------------------
Battles: 1; Sum of rounds: 2; mob: 0.0 ± 0.0; brucelee: 1.0 ± 0.0;
> Team mob = winning battles: 0; perfect battles: 0; close-call battles: 0;
> Team brucelee = winning battles: 1; perfect battles: 0; close-call battles: 0;
------------------------------------------------- Combattants  ------------------------------------------------
Amazing Martial Artist: {team=brucelee; avg Health=120.0 (from 120); damage done (per battle average)= 24.0; hits/slams/stuns/kills/misses (PBA)= 1.0/0.5/0.0/0.0/0.0; rounds (PBA)=1.5;}
Plumber: {team=mob; avg Health=-24.0 (from 24); damage done (per battle average)= 0.0; hits/slams/stuns/kills/misses (PBA)= 0.0/0.0/0.0/0.0/0.5; rounds (PBA)=0.5;}
Amazing Martial Artist: {team=brucelee; avg Health=120.0 (from 120); damage done (per battle average)= 24.0; hits/slams/stuns/kills/misses (PBA)= 1.0/0.5/0.0/0.0/0.0; rounds (PBA)=1.5;}
Plumber: {team=mob; avg Health=-24.0 (from 24); damage done (per battle average)= 0.0; hits/slams/stuns/kills/misses (PBA)= 0.0/0.0/0.0/0.0/0.5; rounds (PBA)=0.5;}
bluetyson commented 2 years ago

Possibly it was the doubling problem that caused this?

Battles: 1; Sum of rounds: 4;
> Team martialarts = winning battles: 0; perfect battles: 0; close-call battles: 0;
> Team mob = winning battles: 1; perfect battles: 0; close-call battles: 1;
------------------------------------------------- Combatants  ------------------------------------------------
Plumber: {team=mob; avg Health=-16.0 (from 24); damage done (per battle average)= 0.0; hits/slams/stuns/kills/misses (PBA)= 0.0/0.0/0.0/0.0/0.0; rounds (PBA)=1.0;}
Plumber: {team=mob; avg Health=-16.0 (from 24); damage done (per battle average)= 0.0; hits/slams/stuns/kills/misses (PBA)= 0.0/0.0/0.0/0.0/2.0; rounds (PBA)=2.0;}
Plumber: {team=mob; avg Health=-4.0 (from 24); damage done (per battle average)= 0.0; hits/slams/stuns/kills/misses (PBA)= 0.0/0.0/0.0/0.0/2.0; rounds (PBA)=2.0;}
Amazing Martial Artist: {team=martialarts; avg Health=0.0 (from 120); damage done (per battle average)= 128.0; hits/slams/stuns/kills/misses (PBA)= 6.0/3.0/1.0/0.0/4.0; rounds (PBA)=4.0;}
Plumber: {team=mob; avg Health=4.0 (from 24); damage done (per battle average)= 18.0; hits/slams/stuns/kills/misses (PBA)= 3.0/0.0/0.0/0.0/1.0; rounds (PBA)=4.0;}
Plumber: {team=mob; avg Health=24.0 (from 24); damage done (per battle average)= 0.0; hits/slams/stuns/kills/misses (PBA)= 0.0/0.0/0.0/0.0/4.0; rounds (PBA)=4.0;}
Plumber: {team=mob; avg Health=24.0 (from 24); damage done (per battle average)= 12.0; hits/slams/stuns/kills/misses (PBA)= 2.0/0.0/0.0/0.0/2.0; rounds (PBA)=4.0;}
Plumber: {team=mob; avg Health=24.0 (from 24); damage done (per battle average)= 12.0; hits/slams/stuns/kills/misses (PBA)= 2.0/0.0/0.0/0.0/2.0; rounds (PBA)=4.0;}
Plumber: {team=mob; avg Health=24.0 (from 24); damage done (per battle average)= 6.0; hits/slams/stuns/kills/misses (PBA)= 1.0/0.0/0.0/0.0/3.0; rounds (PBA)=4.0;}
Plumber: {team=mob; avg Health=24.0 (from 24); damage done (per battle average)= 12.0; hits/slams/stuns/kills/misses (PBA)= 2.0/0.0/0.0/0.0/2.0; rounds (PBA)=4.0;}
Plumber: {team=mob; avg Health=24.0 (from 24); damage done (per battle average)= 24.0; hits/slams/stuns/kills/misses (PBA)= 4.0/0.0/0.0/0.0/0.0; rounds (PBA)=4.0;}
Plumber: {team=mob; avg Health=24.0 (from 24); damage done (per battle average)= 6.0; hits/slams/stuns/kills/misses (PBA)= 1.0/0.0/0.0/0.0/2.0; rounds (PBA)=4.0;}
Plumber: {team=mob; avg Health=24.0 (from 24); damage done (per battle average)= 12.0; hits/slams/stuns/kills/misses (PBA)= 2.0/0.0/0.0/0.0/1.0; rounds (PBA)=3.0;}
Plumber: {team=mob; avg Health=24.0 (from 24); damage done (per battle average)= 6.0; hits/slams/stuns/kills/misses (PBA)= 1.0/0.0/0.0/0.0/2.0; rounds (PBA)=3.0;}
Plumber: {team=mob; avg Health=24.0 (from 24); damage done (per battle average)= 12.0; hits/slams/stuns/kills/misses (PBA)= 2.0/0.0/0.0/0.0/1.0; rounds (PBA)=3.0;}

This seems ok.

bluetyson commented 2 years ago

Looks like it was the duplicate proble, seems ok in my version now.