added modal reroll
This commit is contained in:
@@ -104,11 +104,19 @@ struct MainView: View {
|
||||
.padding()
|
||||
}
|
||||
Spacer()
|
||||
VStack{
|
||||
VStack {
|
||||
Text("Reroll")
|
||||
Button("🎲", action: {
|
||||
current.dice.roll(howMany: current.total)
|
||||
})
|
||||
Picker("", selection: $current.saveRerollMode) {
|
||||
ForEach(RerollMode.allCases, id: \.self) { mode in
|
||||
Text(mode.label).tag(mode)
|
||||
}
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
.frame(width: 180)
|
||||
Button("🎲") {
|
||||
current.applyReroll()
|
||||
}
|
||||
.disabled(current.saveRerollMode == .none || current.saveHasRerolled)
|
||||
.padding()
|
||||
.font(.system(size: controlSize))
|
||||
}
|
||||
@@ -173,11 +181,19 @@ struct MainView: View {
|
||||
Text("Modifier")
|
||||
}
|
||||
Spacer()
|
||||
VStack{
|
||||
VStack {
|
||||
Text("Reroll")
|
||||
Button("🎲", action: {
|
||||
current.dice.roll(howMany: current.total)
|
||||
})
|
||||
Picker("", selection: $current.woundRerollMode) {
|
||||
ForEach(RerollMode.allCases, id: \.self) { mode in
|
||||
Text(mode.label).tag(mode)
|
||||
}
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
.frame(width: 180)
|
||||
Button("🎲") {
|
||||
current.applyReroll()
|
||||
}
|
||||
.disabled(current.woundRerollMode == .none || current.woundHasRerolled)
|
||||
.padding()
|
||||
.font(.system(size: controlSize))
|
||||
}
|
||||
@@ -223,11 +239,19 @@ struct MainView: View {
|
||||
.font(.system(size: controlSize))
|
||||
|
||||
}
|
||||
VStack{
|
||||
VStack {
|
||||
Text("Reroll")
|
||||
Button("🎲", action: {
|
||||
current.dice.roll(howMany: current.total)
|
||||
})
|
||||
Picker("", selection: $current.hitRerollMode) {
|
||||
ForEach(RerollMode.allCases, id: \.self) { mode in
|
||||
Text(mode.label).tag(mode)
|
||||
}
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
.frame(width: 180)
|
||||
Button("🎲") {
|
||||
current.applyReroll()
|
||||
}
|
||||
.disabled(current.hitRerollMode == .none || current.hitHasRerolled)
|
||||
.padding()
|
||||
.font(.system(size: controlSize))
|
||||
}
|
||||
@@ -304,7 +328,7 @@ struct MainView: View {
|
||||
buttons(color: blue, label: "Pool", value: current.total)
|
||||
}
|
||||
.sheet(isPresented: $showFillView,
|
||||
onDismiss: {current.dice.roll(howMany: current.total)}) {
|
||||
onDismiss: { current.resetPool() }) {
|
||||
VStack {
|
||||
AddToPool()
|
||||
Button("Accept", action: {showFillView.toggle()})
|
||||
|
||||
@@ -279,6 +279,25 @@ struct Dice {
|
||||
}
|
||||
}
|
||||
|
||||
mutating func rerollBelow(cutoff: Int) {
|
||||
var count = 0
|
||||
for faceValue in 1..<cutoff {
|
||||
guard let face = DiceType(rawValue: faceValue) else { continue }
|
||||
count += value(which: face)
|
||||
switch face {
|
||||
case .one: one = 0
|
||||
case .two: two = 0
|
||||
case .three: three = 0
|
||||
case .four: four = 0
|
||||
case .five: five = 0
|
||||
case .six: six = 0
|
||||
}
|
||||
}
|
||||
var rerolls = Dice()
|
||||
rerolls.roll(howMany: count)
|
||||
add(pool: rerolls)
|
||||
}
|
||||
|
||||
mutating func blowup(dice: DiceType) {
|
||||
var rolls = Dice()
|
||||
if dice == .six {
|
||||
@@ -291,4 +310,3 @@ struct Dice {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -78,6 +78,19 @@ enum Appearance: Int, CaseIterable, Identifiable {
|
||||
}
|
||||
}
|
||||
|
||||
enum RerollMode: Int, CaseIterable {
|
||||
case none, ones, failed, all
|
||||
|
||||
var label: String {
|
||||
switch self {
|
||||
case .none: return "None"
|
||||
case .ones: return "1s"
|
||||
case .failed: return "Failed"
|
||||
case .all: return "All"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Structs
|
||||
struct Event: Identifiable {
|
||||
let id: UUID
|
||||
@@ -130,6 +143,14 @@ class Roll: ObservableObject {
|
||||
|
||||
@Published var currentPage: String
|
||||
|
||||
@Published var hitRerollMode = RerollMode.none
|
||||
@Published var woundRerollMode = RerollMode.none
|
||||
@Published var saveRerollMode = RerollMode.none
|
||||
|
||||
@Published var hitHasRerolled = false
|
||||
@Published var woundHasRerolled = false
|
||||
@Published var saveHasRerolled = false
|
||||
|
||||
// calculated variables
|
||||
var totalDigits: [Int] {
|
||||
get {
|
||||
@@ -209,6 +230,22 @@ class Roll: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
var currentRerollMode: RerollMode {
|
||||
switch state {
|
||||
case .hit: return hitRerollMode
|
||||
case .wound: return woundRerollMode
|
||||
case .armour: return saveRerollMode
|
||||
}
|
||||
}
|
||||
|
||||
var currentHasRerolled: Bool {
|
||||
switch state {
|
||||
case .hit: return hitHasRerolled
|
||||
case .wound: return woundHasRerolled
|
||||
case .armour: return saveHasRerolled
|
||||
}
|
||||
}
|
||||
|
||||
// init
|
||||
init() {
|
||||
if !UserDefaults.standard.bool(forKey: "didLaunchBefore") {
|
||||
@@ -295,17 +332,61 @@ class Roll: ObservableObject {
|
||||
case .hit:
|
||||
self.total = hit
|
||||
self.state = .wound
|
||||
woundHasRerolled = false
|
||||
case .wound:
|
||||
self.total = wound
|
||||
self.state = .armour
|
||||
saveHasRerolled = false
|
||||
case .armour:
|
||||
self.total = save
|
||||
self.state = .hit
|
||||
hitHasRerolled = false
|
||||
}
|
||||
self.dice.roll(howMany: self.total)
|
||||
}
|
||||
|
||||
// MARK: extra
|
||||
func resetPool() {
|
||||
dice.roll(howMany: total)
|
||||
hitHasRerolled = false
|
||||
}
|
||||
|
||||
func applyReroll() {
|
||||
guard !currentHasRerolled else { return }
|
||||
|
||||
let mode: RerollMode
|
||||
let cutoff: Int
|
||||
|
||||
switch state {
|
||||
case .hit:
|
||||
mode = hitRerollMode
|
||||
cutoff = hitCutoff.rawValue
|
||||
case .wound:
|
||||
mode = woundRerollMode
|
||||
cutoff = woundCutoff
|
||||
case .armour:
|
||||
mode = saveRerollMode
|
||||
cutoff = invulnerable ? armourSave : (armourSave - armourPenetration)
|
||||
}
|
||||
|
||||
switch mode {
|
||||
case .none:
|
||||
return
|
||||
case .ones:
|
||||
dice.reroll(dice: .one)
|
||||
case .failed:
|
||||
dice.rerollBelow(cutoff: cutoff)
|
||||
case .all:
|
||||
dice.roll(howMany: total)
|
||||
}
|
||||
|
||||
switch state {
|
||||
case .hit: hitHasRerolled = true
|
||||
case .wound: woundHasRerolled = true
|
||||
case .armour: saveHasRerolled = true
|
||||
}
|
||||
}
|
||||
|
||||
func add(howMuch: Int) {
|
||||
var newTotal: Int = 0
|
||||
newTotal = self.total + howMuch
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
768C2F3A304F04E6002FEA9A /* Goals.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Goals.md; sourceTree = "<group>"; };
|
||||
7692E8422BD55CDE005BDD76 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
980EF453285E2BAD002FE8A0 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
|
||||
981AD0BA27C30E31005A6492 /* Bunch O' Dice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Bunch O' Dice.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -97,6 +98,7 @@
|
||||
981AD0B127C30E31005A6492 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
768C2F3A304F04E6002FEA9A /* Goals.md */,
|
||||
981AD0BC27C30E31005A6492 /* Bunch-O--Dice */,
|
||||
981AD0CD27C30E32005A6492 /* Bunch O' DiceTests */,
|
||||
981AD0D727C30E32005A6492 /* Bunch O' DiceUITests */,
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
- [ ] Update graphics to clarify roll context (to hit / to wound / armor save) #focus/professional
|
||||
- [ ] Add stacking flat hit/wound modifier input, capped at net ±1 #focus/professional
|
||||
- [ ] Add reroll mode selector (none / reroll 1s / reroll all failed / reroll all) #focus/professional
|
||||
- [ ] Add critical-trigger layer keyed off unmodified natural 6s (Sustained Hits, Lethal Hits, Devastating Wounds, Anti-X) #focus/professional
|
||||
- [ ] Add "ignore all modifiers" flag (Psychic) #focus/professional
|
||||
- [ ] Add "auto-success, no roll" flag (Torrent) #focus/professional
|
||||
- Android
|
||||
- [ ] Android: set up official Swift-on-Android toolchain. #focus/professional #android
|
||||
- [ ] Android: extract game logic (dice/modifier engine) into shared Swift library #focus/professional #android
|
||||
- [ ] Android: rewrite UI natively in Jetpack Compose #focus/professional #android
|
||||
Reference in New Issue
Block a user