Menu
News
All News
Dungeons & Dragons
Level Up: Advanced 5th Edition
Pathfinder
Starfinder
Warhammer
2d20 System
Year Zero Engine
Industry News
Reviews
Dragon Reflections
White Dwarf Reflections
Columns
Weekly Digests
Weekly News Digest
Freebies, Sales & Bundles
RPG Print News
RPG Crowdfunding News
Game Content
ENterplanetary DimENsions
Mythological Figures
Opinion
Worlds of Design
Peregrine's Nest
RPG Evolution
Other Columns
From the Freelancing Frontline
Monster ENcyclopedia
WotC/TSR Alumni Look Back
4 Hours w/RSD (Ryan Dancey)
The Road to 3E (Jonathan Tweet)
Greenwood's Realms (Ed Greenwood)
Drawmij's TSR (Jim Ward)
Community
Forums & Topics
Forum List
Latest Posts
Forum list
*Dungeons & Dragons
Level Up: Advanced 5th Edition
D&D Older Editions, OSR, & D&D Variants
*TTRPGs General
*Pathfinder & Starfinder
EN Publishing
*Geek Talk & Media
Search forums
Chat/Discord
Resources
Wiki
Pages
Latest activity
Media
New media
New comments
Search media
Downloads
Latest reviews
Search resources
EN Publishing
Store
EN5ider
Adventures in ZEITGEIST
Awfully Cheerful Engine
What's OLD is NEW
Judge Dredd & The Worlds Of 2000AD
War of the Burning Sky
Level Up: Advanced 5E
Events & Releases
Upcoming Events
Private Events
Featured Events
Socials!
EN Publishing
Twitter
BlueSky
Facebook
Instagram
EN World
BlueSky
YouTube
Facebook
Twitter
Twitch
Podcast
Features
Top 5 RPGs Compiled Charts 2004-Present
Adventure Game Industry Market Research Summary (RPGs) V1.0
Ryan Dancey: Acquiring TSR
Q&A With Gary Gygax
D&D Rules FAQs
TSR, WotC, & Paizo: A Comparative History
D&D Pronunciation Guide
Million Dollar TTRPG Kickstarters
Tabletop RPG Podcast Hall of Fame
Eric Noah's Unofficial D&D 3rd Edition News
D&D in the Mainstream
D&D & RPG History
About Morrus
Log in
Register
What's new
Search
Search
Search titles only
By:
Forums & Topics
Forum List
Latest Posts
Forum list
*Dungeons & Dragons
Level Up: Advanced 5th Edition
D&D Older Editions, OSR, & D&D Variants
*TTRPGs General
*Pathfinder & Starfinder
EN Publishing
*Geek Talk & Media
Search forums
Chat/Discord
Menu
Log in
Register
Install the app
Install
NOW LIVE! Today's the day you meet your new best friend. You don’t have to leave Wolfy behind... In 'Pets & Sidekicks' your companions level up with you!
Community
General Tabletop Discussion
*Pathfinder & Starfinder
Monte Carlo versus "The Math"
JavaScript is disabled. For a better experience, please enable JavaScript in your browser before proceeding.
You are using an out of date browser. It may not display this or other websites correctly.
You should upgrade or use an
alternative browser
.
Reply to thread
Message
<blockquote data-quote="sfedi" data-source="post: 4999386" data-attributes="member: 15746"><p>What would the party's tactic be?</p><p>(we must first add more conditions to make this work: the marked condition and to-hit bonuses or something like that from the Cleric, oh, and Healing Word)</p><p></p><p></p><p>Isn't the default to not attack downed foes?</p><p>Why would we want to see that scenario?</p><p></p><p></p><p>Mmm, that makes sense.</p><p>Maybe in a group that may be different.</p><p></p><p>Perhaps we should stick to: downed creature is out of the combat. period.</p><p></p><p></p><p>Oh, I didn't meant a test case, only a run experiment and posted here, something like that.</p><p></p><p>Some thing I got thinking today and what we should have next is a good idea/specification on:</p><p> - how the simulation is ran</p><p> - the steps taken in the combat</p><p></p><p>So we are sure we are doing the same, and avoid subtle bugs.</p><p></p><p>After that, define/know what are we measuring, when and how.</p><p></p><p>So we can be sure what the numbers mean.</p><p></p><p>For now, it seems that posting the code is the best way to go for having this.</p><p></p><p>Having said that...</p><p></p><p>[sblock=Script that runs the simulation][code]</p><p>"Run a combat simulation"</p><p>| cr |</p><p>cr := SimulationRunner new.</p><p>cr simulatorBuilder: [CombatSimulator new].</p><p>cr addPCsBlock: [ :cs |</p><p> (cs addPlayer: (Player with: (Fighter level: 1))); group: 'PCs'].</p><p>cr addMonstersBlock: [ :cs |</p><p> (cs addPlayer: (Player with: (Soldier level: 1))); group: 'Monsters'].</p><p>cr numberOfRuns: 1000.</p><p></p><p>cr addMeasuring: TotalRuns new.</p><p>cr addMeasuring: (Average of: DailiesUsed).</p><p>cr addMeasuring: (Average of: CombatDurations).</p><p>cr addMeasuring: (Histogram of: CombatDurations).</p><p></p><p>cr addMeasuring: (AverageFromTotal </p><p> of: (HitPointsRemaining) </p><p> fromTotal: [:creature | creature maxHitpoints]).</p><p>cr addMeasuring: (Histogram of: (HitPointsRemaining)).</p><p></p><p>cr addMeasuring: (AverageFromTotal </p><p> of: (HitPointsRemainingAfterDay) </p><p> fromTotal: [:creature | creature maxHitpoints]).</p><p>cr addMeasuring: (Histogram of: (HitPointsRemainingAfterDay)).</p><p></p><p>cr addMeasuring: (AverageFromTotal </p><p> of: (HealingSurgesRemaining) </p><p> fromTotal: [:creature | creature maxHealingSurges]).</p><p>cr addMeasuring: (Histogram of: (HealingSurgesRemaining)).</p><p></p><p>cr addMeasuring: (Average of: CombatsPerDay).</p><p>cr addMeasuring: (Histogram of: (CombatsPerDay)).</p><p></p><p>cr run.</p><p></p><p>(CombatReport on: cr) displayString.</p><p>[/code][/sblock]</p><p></p><p>[sblock=Running a simulation and getting the data][code]</p><p>run</p><p> self initializeMeasurings.</p><p> self numberOfRuns timesRepeat: [| simulation currentCombat maxCombats arePCsAlive |</p><p> simulation := self newSimulation.</p><p> self addPCsTo: simulation.</p><p> maxCombats := 50.</p><p> currentCombat := 1.</p><p> arePCsAlive := simulation arePCsAlive.</p><p> [currentCombat <= maxCombats and: [arePCsAlive]] whileTrue: [</p><p> simulation removeMonsters.</p><p> self addMonstersTo: simulation.</p><p> simulation context at: 'currentCombat' put: currentCombat.</p><p> simulation run.</p><p> self measureAfterCombat: simulation.</p><p> arePCsAlive := simulation arePCsAlive.</p><p> arePCsAlive ifTrue: [</p><p> simulation runAfterCombat.</p><p> self measureAfterShortRest: simulation].</p><p> currentCombat := currentCombat + 1.</p><p> ].</p><p> self measureAfterDay: simulation.</p><p> ].</p><p>[/code][/sblock]</p><p></p><p>[sblock=Running the combat][code]</p><p>run</p><p></p><p> self players do: [:each | each combat: self].</p><p> self rollInitiative.</p><p> self runCombat.</p><p></p><p>rollInitiative</p><p> | initiativesAndPlayers |</p><p> initiativesAndPlayers := self players </p><p> collect: [:player | Association key: player initiativeRoll value: player].</p><p> initiativesAndPlayers := initiativesAndPlayers asSortedCollection.</p><p> orderedCombatants := initiativesAndPlayers collect: [:each | each value]</p><p></p><p>runCombat</p><p> | anyoneActed |</p><p> anyoneActed := true.</p><p> self currentRound: 0.</p><p> [anyoneActed] whileTrue: </p><p> [anyoneActed := false.</p><p> orderedCombatants do: </p><p> [:player | </p><p> (player wantsToAct) </p><p> ifTrue: </p><p> [anyoneActed := true.</p><p> player act]].</p><p> self currentRound: self currentRound + 1.</p><p> (anyoneActed not and: [self currentRound = 1]) ifTrue: [self halt]].</p><p>[/code][/sblock]</p><p></p><p>[sblock=How the player acts][code]</p><p>[b]When Second Wind is a minor, I put this code[/b]</p><p>act</p><p> ^self shouldHealInCombat ifTrue: [self doSecondWind. self doAttack] ifFalse: [self doAttack]</p><p></p><p>[b]When Second Wind is a standard, I put this code[/b]</p><p>act</p><p> ^self shouldHealInCombat ifTrue: [self doSecondWind] ifFalse: [self doAttack]</p><p></p><p>shouldHealInCombat</p><p> ^self areHitpointLowEnough and: [self isSecondWindAvailble]</p><p></p><p>areHitpointLowEnough</p><p> ^self character currentHitpoints + self character healingSurgeValue <= self character maxHitpoints</p><p></p><p>doSecondWind</p><p> self getSecondWindAction actOn: self character.</p><p></p><p>doAttack</p><p> | enemies |</p><p> enemies := self activeEnemiesIn: self combat.</p><p> enemies isEmpty ifTrue: [^nil].</p><p> self combat resolve: self chooseAttack against: enemies first character</p><p></p><p>chooseAttack</p><p> | minimumUsageAllowed |</p><p> minimumUsageAllowed := EncounterUsage.</p><p> self isSituationDesperate ifTrue: [minimumUsageAllowed := DailyUsage].</p><p> ^(self character powers select: </p><p> [:each | </p><p> (each isAttack and: [each isAvailable]) </p><p> and: [each usage isAsFrequentOrMoreThan: minimumUsageAllowed]]) </p><p> maxUsing: [:each | each averageDamage]</p><p></p><p>isSituationDesperate</p><p> ^self character isBloodied.</p><p></p><p>[/code][/sblock]</p><p></p><p>[sblock=What happens after/between a combat(s)][code]</p><p>runAfterCombat</p><p> ^self players do: [:each | each takeShortRest].</p><p></p><p>Player>>takeShortRest</p><p> [character healingSurges > 0 and: [self shouldHealInShortRest]] </p><p> whileTrue: [self spendHealingSurgeWhileInShortRest].</p><p> self character powers do: [:each | each takeShortRest]</p><p></p><p>shouldHealInShortRest</p><p> ^self isDamageTakenMoreThan: (3/4) of: self character healingSurgeValue.</p><p></p><p>spendHealingSurgeWhileInShortRest</p><p> ^self character spendHealingSurge.</p><p></p><p>spendHealingSurge</p><p> (self healingSurges > 0) ifTrue: [</p><p> self healingSurges: self healingSurges - 1.</p><p> self regainHitpoints: self healingSurgeValue.</p><p> ].</p><p></p><p>regainHitpoints: anInteger</p><p> (self currentHitpoints <= 0) ifTrue: [self currentHitpoints: 0].</p><p> self currentHitpoints: self currentHitpoints + anInteger.</p><p> self currentHitpoints > self maxHitpoints ifTrue: [self currentHitpoints: self maxHitpoints]</p><p></p><p>[/code][/sblock]</p><p></p><p>Oh, BTW, this is Smalltalk code. Run on Dolphin Smalltalk 6.</p><p>I can mail or upload the packages for all the code if someone wants.</p></blockquote><p></p>
[QUOTE="sfedi, post: 4999386, member: 15746"] What would the party's tactic be? (we must first add more conditions to make this work: the marked condition and to-hit bonuses or something like that from the Cleric, oh, and Healing Word) Isn't the default to not attack downed foes? Why would we want to see that scenario? Mmm, that makes sense. Maybe in a group that may be different. Perhaps we should stick to: downed creature is out of the combat. period. Oh, I didn't meant a test case, only a run experiment and posted here, something like that. Some thing I got thinking today and what we should have next is a good idea/specification on: - how the simulation is ran - the steps taken in the combat So we are sure we are doing the same, and avoid subtle bugs. After that, define/know what are we measuring, when and how. So we can be sure what the numbers mean. For now, it seems that posting the code is the best way to go for having this. Having said that... [sblock=Script that runs the simulation][code] "Run a combat simulation" | cr | cr := SimulationRunner new. cr simulatorBuilder: [CombatSimulator new]. cr addPCsBlock: [ :cs | (cs addPlayer: (Player with: (Fighter level: 1))); group: 'PCs']. cr addMonstersBlock: [ :cs | (cs addPlayer: (Player with: (Soldier level: 1))); group: 'Monsters']. cr numberOfRuns: 1000. cr addMeasuring: TotalRuns new. cr addMeasuring: (Average of: DailiesUsed). cr addMeasuring: (Average of: CombatDurations). cr addMeasuring: (Histogram of: CombatDurations). cr addMeasuring: (AverageFromTotal of: (HitPointsRemaining) fromTotal: [:creature | creature maxHitpoints]). cr addMeasuring: (Histogram of: (HitPointsRemaining)). cr addMeasuring: (AverageFromTotal of: (HitPointsRemainingAfterDay) fromTotal: [:creature | creature maxHitpoints]). cr addMeasuring: (Histogram of: (HitPointsRemainingAfterDay)). cr addMeasuring: (AverageFromTotal of: (HealingSurgesRemaining) fromTotal: [:creature | creature maxHealingSurges]). cr addMeasuring: (Histogram of: (HealingSurgesRemaining)). cr addMeasuring: (Average of: CombatsPerDay). cr addMeasuring: (Histogram of: (CombatsPerDay)). cr run. (CombatReport on: cr) displayString. [/code][/sblock] [sblock=Running a simulation and getting the data][code] run self initializeMeasurings. self numberOfRuns timesRepeat: [| simulation currentCombat maxCombats arePCsAlive | simulation := self newSimulation. self addPCsTo: simulation. maxCombats := 50. currentCombat := 1. arePCsAlive := simulation arePCsAlive. [currentCombat <= maxCombats and: [arePCsAlive]] whileTrue: [ simulation removeMonsters. self addMonstersTo: simulation. simulation context at: 'currentCombat' put: currentCombat. simulation run. self measureAfterCombat: simulation. arePCsAlive := simulation arePCsAlive. arePCsAlive ifTrue: [ simulation runAfterCombat. self measureAfterShortRest: simulation]. currentCombat := currentCombat + 1. ]. self measureAfterDay: simulation. ]. [/code][/sblock] [sblock=Running the combat][code] run self players do: [:each | each combat: self]. self rollInitiative. self runCombat. rollInitiative | initiativesAndPlayers | initiativesAndPlayers := self players collect: [:player | Association key: player initiativeRoll value: player]. initiativesAndPlayers := initiativesAndPlayers asSortedCollection. orderedCombatants := initiativesAndPlayers collect: [:each | each value] runCombat | anyoneActed | anyoneActed := true. self currentRound: 0. [anyoneActed] whileTrue: [anyoneActed := false. orderedCombatants do: [:player | (player wantsToAct) ifTrue: [anyoneActed := true. player act]]. self currentRound: self currentRound + 1. (anyoneActed not and: [self currentRound = 1]) ifTrue: [self halt]]. [/code][/sblock] [sblock=How the player acts][code] [b]When Second Wind is a minor, I put this code[/b] act ^self shouldHealInCombat ifTrue: [self doSecondWind. self doAttack] ifFalse: [self doAttack] [b]When Second Wind is a standard, I put this code[/b] act ^self shouldHealInCombat ifTrue: [self doSecondWind] ifFalse: [self doAttack] shouldHealInCombat ^self areHitpointLowEnough and: [self isSecondWindAvailble] areHitpointLowEnough ^self character currentHitpoints + self character healingSurgeValue <= self character maxHitpoints doSecondWind self getSecondWindAction actOn: self character. doAttack | enemies | enemies := self activeEnemiesIn: self combat. enemies isEmpty ifTrue: [^nil]. self combat resolve: self chooseAttack against: enemies first character chooseAttack | minimumUsageAllowed | minimumUsageAllowed := EncounterUsage. self isSituationDesperate ifTrue: [minimumUsageAllowed := DailyUsage]. ^(self character powers select: [:each | (each isAttack and: [each isAvailable]) and: [each usage isAsFrequentOrMoreThan: minimumUsageAllowed]]) maxUsing: [:each | each averageDamage] isSituationDesperate ^self character isBloodied. [/code][/sblock] [sblock=What happens after/between a combat(s)][code] runAfterCombat ^self players do: [:each | each takeShortRest]. Player>>takeShortRest [character healingSurges > 0 and: [self shouldHealInShortRest]] whileTrue: [self spendHealingSurgeWhileInShortRest]. self character powers do: [:each | each takeShortRest] shouldHealInShortRest ^self isDamageTakenMoreThan: (3/4) of: self character healingSurgeValue. spendHealingSurgeWhileInShortRest ^self character spendHealingSurge. spendHealingSurge (self healingSurges > 0) ifTrue: [ self healingSurges: self healingSurges - 1. self regainHitpoints: self healingSurgeValue. ]. regainHitpoints: anInteger (self currentHitpoints <= 0) ifTrue: [self currentHitpoints: 0]. self currentHitpoints: self currentHitpoints + anInteger. self currentHitpoints > self maxHitpoints ifTrue: [self currentHitpoints: self maxHitpoints] [/code][/sblock] Oh, BTW, this is Smalltalk code. Run on Dolphin Smalltalk 6. I can mail or upload the packages for all the code if someone wants. [/QUOTE]
Insert quotes…
Verification
Post reply
Community
General Tabletop Discussion
*Pathfinder & Starfinder
Monte Carlo versus "The Math"
Top