include diehammer plan docs
This commit is contained in:
@@ -0,0 +1,294 @@
|
||||
//
|
||||
// Dice.swift
|
||||
// Bunch O' Dice
|
||||
//
|
||||
// Created by Rory Hinnen on 22/2/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct Dice {
|
||||
// MARK: Private
|
||||
private var d6: Int {
|
||||
get {
|
||||
return Int.random(in: 1...6)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Enums
|
||||
enum DiceType: Int, CaseIterable{
|
||||
case one = 1
|
||||
case two = 2
|
||||
case three = 3
|
||||
case four = 4
|
||||
case five = 5
|
||||
case six = 6
|
||||
}
|
||||
|
||||
enum RollModifiers: Int {
|
||||
case negative = -1
|
||||
case none = 0
|
||||
case positive = 1
|
||||
|
||||
func add() -> RollModifiers {
|
||||
switch self {
|
||||
case .negative:
|
||||
return RollModifiers.none
|
||||
case .none:
|
||||
return RollModifiers.positive
|
||||
case .positive:
|
||||
return RollModifiers.positive
|
||||
}
|
||||
}
|
||||
|
||||
func remove() -> RollModifiers {
|
||||
switch self {
|
||||
case .negative:
|
||||
return RollModifiers.negative
|
||||
case .none:
|
||||
return RollModifiers.negative
|
||||
case .positive:
|
||||
return RollModifiers.none
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Variables
|
||||
var one = 0
|
||||
var two = 0
|
||||
var three = 0
|
||||
var four = 0
|
||||
var five = 0
|
||||
var six = 0
|
||||
|
||||
// MARK: Roll controllers
|
||||
// clear and roll the die
|
||||
mutating func roll(howMany: Int) {
|
||||
clear()
|
||||
var y = howMany
|
||||
while y > 0 {
|
||||
switch d6 {
|
||||
case 1:
|
||||
one += 1
|
||||
case 2:
|
||||
two += 1
|
||||
case 3:
|
||||
three += 1
|
||||
case 4:
|
||||
four += 1
|
||||
case 5:
|
||||
five += 1
|
||||
default:
|
||||
six += 1
|
||||
}
|
||||
y -= 1
|
||||
}
|
||||
}
|
||||
|
||||
// calculate basic roll
|
||||
func total(cutoff: Int, modifier: Dice.RollModifiers) -> Int {
|
||||
var total = six
|
||||
|
||||
switch modifier {
|
||||
case .none:
|
||||
switch cutoff {
|
||||
case 5:
|
||||
total += five
|
||||
case 4:
|
||||
total += four + five
|
||||
case 3:
|
||||
total += three + four + five
|
||||
case 2:
|
||||
total += two + three + four + five
|
||||
default:
|
||||
break
|
||||
}
|
||||
case .negative:
|
||||
switch cutoff {
|
||||
case 4:
|
||||
total += five
|
||||
case 3:
|
||||
total += four + five
|
||||
case 2:
|
||||
total += three + four + five
|
||||
case 1:
|
||||
total += two + three + four + five
|
||||
default:
|
||||
break
|
||||
}
|
||||
case .positive:
|
||||
switch cutoff {
|
||||
case 6:
|
||||
total += five
|
||||
case 5:
|
||||
total += four + five
|
||||
case 4:
|
||||
total += three + four + five
|
||||
case 3, 2:
|
||||
total += two + three + four + five
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
// Calculate different rolls
|
||||
func hit(die: Int, cutoff: Int, modifier: Int) -> Int {
|
||||
return total(cutoff: cutoff, modifier: Dice.RollModifiers(rawValue: modifier) ?? .none)
|
||||
}
|
||||
|
||||
func wound(die: Int, mortal: Bool, cutoff: Int, modifier: Int) -> Int {
|
||||
if mortal {
|
||||
return total(cutoff: 2, modifier: Dice.RollModifiers(rawValue: modifier) ?? .none)
|
||||
} else {
|
||||
return total(cutoff: cutoff, modifier: Dice.RollModifiers(rawValue: modifier) ?? .none)
|
||||
}
|
||||
}
|
||||
|
||||
func armour(die: Int, invulnerable: Bool, save: Int, armourPenetration: Int) -> Int {
|
||||
var total = 0
|
||||
switch invulnerable ? save : (save - armourPenetration) {
|
||||
case 7...:
|
||||
total = six + five + four + three + two + one
|
||||
case 6:
|
||||
total = five + four + three + two + one
|
||||
case 5:
|
||||
total = four + three + two + one
|
||||
case 4:
|
||||
total = three + two + one
|
||||
case 3:
|
||||
total = two + one
|
||||
default:
|
||||
total = one
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
// MARK: roll utilities
|
||||
// Utility functions
|
||||
mutating func clear() {
|
||||
one = 0
|
||||
two = 0
|
||||
three = 0
|
||||
four = 0
|
||||
five = 0
|
||||
six = 0
|
||||
}
|
||||
|
||||
mutating func add(pool: Dice) {
|
||||
one += pool.one
|
||||
two += pool.two
|
||||
three += pool.three
|
||||
four += pool.four
|
||||
five += pool.five
|
||||
six += pool.six
|
||||
}
|
||||
|
||||
func value(which: DiceType) -> Int {
|
||||
switch which {
|
||||
case .one:
|
||||
return one
|
||||
case .two:
|
||||
return two
|
||||
case .three:
|
||||
return three
|
||||
case .four:
|
||||
return four
|
||||
case .five:
|
||||
return five
|
||||
case .six:
|
||||
return six
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Extra
|
||||
mutating func increment(die: DiceType) {
|
||||
switch die {
|
||||
case .one:
|
||||
one += 1
|
||||
case .two:
|
||||
two += 1
|
||||
case .three:
|
||||
three += 1
|
||||
case .four:
|
||||
four += 1
|
||||
case .five:
|
||||
five += 1
|
||||
case .six:
|
||||
six += 1
|
||||
}
|
||||
}
|
||||
|
||||
mutating func decrement(die: DiceType) {
|
||||
switch die {
|
||||
case .one:
|
||||
if one > 0 {
|
||||
one -= 1
|
||||
}
|
||||
case .two:
|
||||
if two > 0 {
|
||||
two -= 1
|
||||
}
|
||||
case .three:
|
||||
if three > 0 {
|
||||
three -= 1
|
||||
}
|
||||
case .four:
|
||||
if four > 0 {
|
||||
four -= 1
|
||||
}
|
||||
case .five:
|
||||
if five > 0 {
|
||||
five -= 1
|
||||
}
|
||||
case .six:
|
||||
if six > 0 {
|
||||
six -= 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutating func reroll(dice: DiceType) {
|
||||
var rerolls = Dice()
|
||||
switch dice {
|
||||
case .one:
|
||||
rerolls.roll(howMany: one)
|
||||
one = 0
|
||||
self.add(pool: rerolls)
|
||||
case .two:
|
||||
rerolls.roll(howMany: two)
|
||||
two = 0
|
||||
self.add(pool: rerolls)
|
||||
case .three:
|
||||
rerolls.roll(howMany: three)
|
||||
three = 0
|
||||
self.add(pool: rerolls)
|
||||
case .four:
|
||||
rerolls.roll(howMany: four)
|
||||
four = 0
|
||||
self.add(pool: rerolls)
|
||||
case .five:
|
||||
rerolls.roll(howMany: five)
|
||||
five = 0
|
||||
self.add(pool: rerolls)
|
||||
case .six:
|
||||
rerolls.roll(howMany: six)
|
||||
six = 0
|
||||
self.add(pool: rerolls)
|
||||
}
|
||||
}
|
||||
|
||||
mutating func blowup(dice: DiceType) {
|
||||
var rolls = Dice()
|
||||
if dice == .six {
|
||||
rolls.roll(howMany: six)
|
||||
self.add(pool: rolls)
|
||||
} else if dice == .five {
|
||||
rolls.roll(howMany: six + five)
|
||||
self.add(pool: rolls)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// OnboardingModel.swift
|
||||
// Bunch O' Dice
|
||||
//
|
||||
// Created by Rory Hinnen on 22/6/11.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct DTCourse: Identifiable {
|
||||
var id = UUID()
|
||||
var title: String
|
||||
var subtitle: String
|
||||
var desc: String
|
||||
var imageName: String = ""
|
||||
}
|
||||
|
||||
extension DTCourse {
|
||||
static let title = "DieHammer"
|
||||
static var pages: [DTCourse] {
|
||||
[
|
||||
DTCourse(title: "DieHammer", subtitle: "A chaos manager for Warhammer or 40k", desc: "Welcome! This app will help you manage simple rolls to hit, wound, or save for Warhammer and Warhammer:40,000. Let's walk through the interface to help you understand how to use it.", imageName: "one"),
|
||||
DTCourse(title: "State", subtitle: "Types of Rolls", desc: "You can make three kinds of rolls: Hit, Wound or Armor Save. The top of the screen shows you what roll you are making. You can change the roll at any time by tapping the icon.", imageName: "two"),
|
||||
DTCourse(title: "The Pool", subtitle: "Rolling the Dice", desc: "The pool shows how many dice you are going to roll. Tap on the pool to change the amount.", imageName: "three"),
|
||||
DTCourse(title: "The Result", subtitle: "How bad is it, Doc?", desc: "Results will count up the number of dice that apply to the roll. We always count damage, so the Armour Save total shows how many wounds to apply. Tapping on results will save the current roll, and move on to the next.", imageName: "four"),
|
||||
DTCourse(title: "Re-Rolling", subtitle: "Ooo...yeah.", desc: "You can re-roll at any time by tapping the re-roll icon", imageName: "five"),
|
||||
DTCourse(title: "Hit Settings", subtitle: "Sweet, sweet modifiers", desc: "Tap the die that relates to your hit value, and adjust a hit modifier if you have one. If you have a special rule for Blowing up a hit, tapping the icon will add the new rolls.", imageName: "six"),
|
||||
DTCourse(title: "Wound", subtitle: "Make them bleed!", desc: "Set the Attackers Strength and the Defenders strength to calculate the new Wound cutoff. Results are always updated in real time.", imageName: "seven"),
|
||||
DTCourse(title: "Armour Save", subtitle: "This is your last chance!", desc: "Amour Save will show how many dice in the roll fail, counting up the number of wounds to distribute.", imageName: "eight"),
|
||||
DTCourse(title: "History & Settings", subtitle: "Wait, what happened?", desc: "You can always pull up your history to see the old rolls you've made. You can also add a roll to the history at any time.", imageName: "nine"),
|
||||
DTCourse(title: title, subtitle: "Have Fun!", desc: "", imageName: "one")
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
//
|
||||
// State.swift
|
||||
// Bunch O' Dice
|
||||
//
|
||||
// Created by Rory Hinnen on 22/5/21.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
// MARK: Extensions
|
||||
extension Int {
|
||||
func digits() -> [Int] {
|
||||
var digits: [Int] = []
|
||||
var num = self
|
||||
|
||||
digits.append(num % 10)
|
||||
|
||||
repeat {
|
||||
num = num / 10
|
||||
digits.append(num % 10)
|
||||
} while num >= 10
|
||||
while digits.count < 3 {
|
||||
digits.append(0)
|
||||
}
|
||||
return digits
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Enums
|
||||
enum RollState: Int {
|
||||
case hit
|
||||
case wound
|
||||
case armour
|
||||
|
||||
func print() -> String {
|
||||
switch self {
|
||||
case .hit:
|
||||
return "⚔️"
|
||||
case .wound:
|
||||
return "🩸"
|
||||
case .armour:
|
||||
return "🛡"
|
||||
}
|
||||
}
|
||||
|
||||
func text() -> String {
|
||||
switch self {
|
||||
case .hit:
|
||||
return "Hit"
|
||||
case .wound:
|
||||
return "Wound"
|
||||
case .armour:
|
||||
return "Damage"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Appearance: Int, CaseIterable, Identifiable {
|
||||
case light, dark, automatic
|
||||
|
||||
var id: Int { self.rawValue }
|
||||
|
||||
var name: String {
|
||||
switch self {
|
||||
case .light: return "Light"
|
||||
case .dark: return "Dark"
|
||||
case .automatic: return "Automatic"
|
||||
}
|
||||
}
|
||||
|
||||
var type: ColorScheme? {
|
||||
switch self {
|
||||
case .light: return ColorScheme.light
|
||||
case .dark: return ColorScheme.dark
|
||||
case .automatic: return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Structs
|
||||
struct Event: Identifiable {
|
||||
let id: UUID
|
||||
var total: Int
|
||||
var pool: Dice
|
||||
var state: RollState
|
||||
|
||||
var poolTotal: Int {
|
||||
get {
|
||||
return pool.one + pool.two + pool.three + pool.four + pool.five + pool.six
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
id = UUID()
|
||||
total = 0
|
||||
pool = Dice()
|
||||
state = .hit
|
||||
}
|
||||
|
||||
init(total: Int, pool: Dice, state: RollState) {
|
||||
self.id = UUID()
|
||||
self.total = total
|
||||
self.pool = pool
|
||||
self.state = state
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Classes
|
||||
class Roll: ObservableObject {
|
||||
//Published
|
||||
@Published var dice = Dice()
|
||||
@Published var total = 0
|
||||
@Published var state = RollState.hit
|
||||
@Published var history = [Event()]
|
||||
@Published var appearance = Appearance.automatic
|
||||
@Published var firstView = true
|
||||
|
||||
@Published var hitCutoff = Dice.DiceType.four
|
||||
@Published var modifier = Dice.RollModifiers.none
|
||||
|
||||
@Published var strength = 7
|
||||
@Published var toughness = 5
|
||||
@Published var woundModifier = Dice.RollModifiers.none
|
||||
@Published var mortal = false
|
||||
|
||||
@Published var armourPenetration = 0
|
||||
@Published var armourSave = 3
|
||||
@Published var invulnerable = false
|
||||
|
||||
@Published var currentPage: String
|
||||
|
||||
// calculated variables
|
||||
var totalDigits: [Int] {
|
||||
get {
|
||||
return total.digits()
|
||||
}
|
||||
}
|
||||
|
||||
var result: Int {
|
||||
get
|
||||
{
|
||||
switch self.state {
|
||||
case .hit:
|
||||
return hit
|
||||
case .wound:
|
||||
return wound
|
||||
case .armour:
|
||||
return save
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var woundCutoff: Int {
|
||||
get
|
||||
{
|
||||
if Float(self.strength) / Float(self.toughness) >= 2.0 {
|
||||
return 2
|
||||
} else if Float(self.strength) / Float(self.toughness) > 1.0 {
|
||||
return 3
|
||||
} else if Float(self.strength) / Float(self.toughness) == 1 {
|
||||
return 4
|
||||
} else if Float(self.strength) / Float(self.toughness) <= 0.5 {
|
||||
return 6
|
||||
} else {
|
||||
return 5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var cutoff: Dice.DiceType {
|
||||
get {
|
||||
switch self.state {
|
||||
case .hit:
|
||||
return hitCutoff
|
||||
case .wound:
|
||||
if Float(self.strength) / Float(self.toughness) >= 2.0 {
|
||||
return .two
|
||||
} else if Float(self.strength) / Float(self.toughness) > 1.0 {
|
||||
return .three
|
||||
} else if Float(self.strength) / Float(self.toughness) == 1 {
|
||||
return .four
|
||||
} else if Float(self.strength) / Float(self.toughness) <= 0.5 {
|
||||
return .six
|
||||
} else {
|
||||
return .five
|
||||
}
|
||||
case .armour:
|
||||
return Dice.DiceType(rawValue: self.armourSave) ?? .one
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var hit: Int {
|
||||
get {
|
||||
return self.dice.hit(die: total, cutoff: self.hitCutoff.rawValue, modifier: self.modifier.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
var wound: Int {
|
||||
get {
|
||||
return self.dice.wound(die: total, mortal: self.mortal, cutoff: self.woundCutoff, modifier: woundModifier.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
var save: Int {
|
||||
get {
|
||||
return self.dice.armour(die: total, invulnerable: self.invulnerable, save: self.armourSave, armourPenetration: self.armourPenetration)
|
||||
}
|
||||
}
|
||||
|
||||
// init
|
||||
init() {
|
||||
if !UserDefaults.standard.bool(forKey: "didLaunchBefore") {
|
||||
UserDefaults.standard.set(true, forKey: "didLaunchBefore")
|
||||
currentPage = "OnboardingView"
|
||||
} else {
|
||||
currentPage = "Bunch"
|
||||
}
|
||||
}
|
||||
|
||||
// modifier controllers
|
||||
// MARK: wound controllers
|
||||
func addStrength() {
|
||||
self.strength += 1
|
||||
}
|
||||
|
||||
func loseStrength() {
|
||||
if self.strength > 1 {
|
||||
self.strength -= 1
|
||||
}
|
||||
}
|
||||
|
||||
func addToughness() {
|
||||
self.toughness += 1
|
||||
}
|
||||
|
||||
func loseToughness() {
|
||||
if self.toughness > 1 {
|
||||
self.toughness -= 1
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: armour controllers
|
||||
func addArmour() {
|
||||
if self.armourSave < 6 {
|
||||
self.armourSave += 1
|
||||
}
|
||||
}
|
||||
|
||||
func loseArmour() {
|
||||
if self.armourSave > 1 {
|
||||
self.armourSave -= 1
|
||||
}
|
||||
}
|
||||
|
||||
func addPenetration() {
|
||||
self.armourPenetration += 1
|
||||
}
|
||||
|
||||
func losePenetration() {
|
||||
self.armourPenetration -= 1
|
||||
}
|
||||
|
||||
// MARK: total pool
|
||||
func incrementDigits(place: Int) {
|
||||
if totalDigits[place] < 9 {
|
||||
self.total += Int(pow(10.0, Float(place)))
|
||||
}
|
||||
}
|
||||
|
||||
func decrementDigits(place: Int) {
|
||||
if totalDigits[place] > 0 {
|
||||
self.total -= Int(pow(10.0, Float(place)))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: utility function
|
||||
func incrementState() {
|
||||
var x = 0
|
||||
switch self.state {
|
||||
case .hit:
|
||||
x = self.hit
|
||||
case .wound:
|
||||
x = self.wound
|
||||
case .armour:
|
||||
x = self.armourSave
|
||||
}
|
||||
if self.history[0].total == 0 {
|
||||
self.history[0] = Event(total: x, pool: self.dice, state: self.state)
|
||||
} else {
|
||||
self.history.insert(Event(total: x, pool: self.dice, state: self.state), at: 0)
|
||||
}
|
||||
switch self.state {
|
||||
case .hit:
|
||||
self.total = hit
|
||||
self.state = .wound
|
||||
case .wound:
|
||||
self.total = wound
|
||||
self.state = .armour
|
||||
case .armour:
|
||||
self.total = save
|
||||
self.state = .hit
|
||||
}
|
||||
self.dice.roll(howMany: self.total)
|
||||
}
|
||||
|
||||
// MARK: extra
|
||||
func add(howMuch: Int) {
|
||||
var newTotal: Int = 0
|
||||
newTotal = self.total + howMuch
|
||||
if newTotal < 0 {
|
||||
newTotal = 0
|
||||
}
|
||||
self.total = newTotal
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user