USER
Private isUpdating As Boolean
Private Sub UserForm_Initialize()
' 初始化隨機數生成器
Randomize
Dim rng As Range
' 初始化 ComboBox1 到 ComboBox6 的資料
Set rng = ThisWorkbook.Sheets("武將表").Range("F12:F121")
InitComboBox Me.ComboBox1, rng
InitComboBox Me.ComboBox2, rng
InitComboBox Me.ComboBox3, rng
InitComboBox Me.ComboBox4, rng
InitComboBox Me.ComboBox5, rng
InitComboBox Me.ComboBox6, rng
' 初始化 ComboBox7 到 ComboBox18 的資料
Set rng = ThisWorkbook.Sheets("武將表").Range("AM122:AM234")
InitComboBox Me.ComboBox7, rng
InitComboBox Me.ComboBox8, rng
InitComboBox Me.ComboBox9, rng
InitComboBox Me.ComboBox10, rng
InitComboBox Me.ComboBox11, rng
InitComboBox Me.ComboBox12, rng
InitComboBox Me.ComboBox13, rng
InitComboBox Me.ComboBox14, rng
InitComboBox Me.ComboBox15, rng
InitComboBox Me.ComboBox16, rng
InitComboBox Me.ComboBox17, rng
InitComboBox Me.ComboBox18, rng
' 初始化兵種ComboBox
InitTypeComboBox Me.ComboBox19, ThisWorkbook.Sheets("武將表").Range("M11:Q11")
InitTypeComboBox Me.ComboBox20, ThisWorkbook.Sheets("武將表").Range("M11:Q11")
' 初始化特定範圍 TextBox 的值為空白
ClearTextBox 7, 12
' 更新按鈕狀態
UpdateButtonStates
End Sub
Private Sub InitComboBox(cmb As MSForms.comboBox, rng As Range)
Dim cell As Range
cmb.Clear
For Each cell In rng
If Not IsEmpty(cell.value) Then
cmb.AddItem cell.value
End If
Next cell
End Sub
Private Sub InitTypeComboBox(cmb As MSForms.comboBox, rng As Range)
Dim cell As Range
cmb.Clear
For Each cell In rng
If Not IsEmpty(cell.value) Then
cmb.AddItem cell.value
End If
Next cell
End Sub
Private Sub ClearTextBox(startIndex As Integer, endIndex As Integer)
Dim i As Integer
For i = startIndex To endIndex
Me.Controls("TextBox" & i).value = ""
Next i
End Sub
Private Sub ComboBox7_Change()
UpdateComboBoxesForSubset Array(Me.ComboBox7, Me.ComboBox8, Me.ComboBox9, Me.ComboBox13, Me.ComboBox14, Me.ComboBox15)
End Sub
Private Sub ComboBox8_Change()
UpdateComboBoxesForSubset Array(Me.ComboBox7, Me.ComboBox8, Me.ComboBox9, Me.ComboBox13, Me.ComboBox14, Me.ComboBox15)
End Sub
Private Sub ComboBox9_Change()
UpdateComboBoxesForSubset Array(Me.ComboBox7, Me.ComboBox8, Me.ComboBox9, Me.ComboBox13, Me.ComboBox14, Me.ComboBox15)
End Sub
Private Sub ComboBox10_Change()
UpdateComboBoxesForSubset Array(Me.ComboBox10, Me.ComboBox11, Me.ComboBox12, Me.ComboBox16, Me.ComboBox17, Me.ComboBox18)
End Sub
Private Sub ComboBox11_Change()
UpdateComboBoxesForSubset Array(Me.ComboBox10, Me.ComboBox11, Me.ComboBox12, Me.ComboBox16, Me.ComboBox17, Me.ComboBox18)
End Sub
Private Sub ComboBox12_Change()
UpdateComboBoxesForSubset Array(Me.ComboBox10, Me.ComboBox11, Me.ComboBox12, Me.ComboBox16, Me.ComboBox17, Me.ComboBox18)
End Sub
Private Sub ComboBox13_Change()
UpdateComboBoxesForSubset Array(Me.ComboBox7, Me.ComboBox8, Me.ComboBox9, Me.ComboBox13, Me.ComboBox14, Me.ComboBox15)
End Sub
Private Sub ComboBox14_Change()
UpdateComboBoxesForSubset Array(Me.ComboBox7, Me.ComboBox8, Me.ComboBox9, Me.ComboBox13, Me.ComboBox14, Me.ComboBox15)
End Sub
Private Sub ComboBox15_Change()
UpdateComboBoxesForSubset Array(Me.ComboBox7, Me.ComboBox8, Me.ComboBox9, Me.ComboBox13, Me.ComboBox14, Me.ComboBox15)
End Sub
Private Sub ComboBox16_Change()
UpdateComboBoxesForSubset Array(Me.ComboBox10, Me.ComboBox11, Me.ComboBox12, Me.ComboBox16, Me.ComboBox17, Me.ComboBox18)
End Sub
Private Sub ComboBox17_Change()
UpdateComboBoxesForSubset Array(Me.ComboBox10, Me.ComboBox11, Me.ComboBox12, Me.ComboBox16, Me.ComboBox17, Me.ComboBox18)
End Sub
Private Sub ComboBox18_Change()
UpdateComboBoxesForSubset Array(Me.ComboBox10, Me.ComboBox11, Me.ComboBox12, Me.ComboBox16, Me.ComboBox17, Me.ComboBox18)
End Sub
Private Sub UpdateComboBoxesForSubset(comboBoxes As Variant)
If isUpdating Then Exit Sub
isUpdating = True
Dim i As Integer, j As Integer
Dim cmb As MSForms.comboBox
Dim currentValue As String
Dim selectedValues As New Collection
' 收集所有被選擇的值
On Error Resume Next
For i = LBound(comboBoxes) To UBound(comboBoxes)
Set cmb = comboBoxes(i)
If cmb.value <> "" Then
selectedValues.Add cmb.value, CStr(cmb.value)
End If
Next i
On Error GoTo 0
' 更新每個 ComboBox 列表, 移除已選擇的值
For i = LBound(comboBoxes) To UBound(comboBoxes)
Set cmb = comboBoxes(i)
currentValue = cmb.value
InitComboBox cmb, ThisWorkbook.Sheets("武將表").Range("AM122:AM234")
' 移除已選擇的值
For j = cmb.ListCount - 1 To 0 Step -1
If IsValueInCollection(selectedValues, cmb.list(j)) And cmb.list(j) <> currentValue Then
cmb.RemoveItem j
End If
Next j
cmb.value = currentValue
Next i
isUpdating = False
End Sub
Private Function IsValueInCollection(coll As Collection, value As String) As Boolean
Dim item As Variant
IsValueInCollection = False
On Error Resume Next
For Each item In coll
If item = value Then
IsValueInCollection = True
Exit Function
End If
Next item
On Error GoTo 0
End Function
Private Sub ComboBox_Change(comboBox As MSForms.comboBox, displayTextBox As MSForms.TextBox, associatedTextBoxStart As Integer, displayTextBox67 As MSForms.TextBox)
If Not isUpdating Then
UpdateComboBoxes (IIf(comboBox.Name Like "ComboBox[1-3]", 1, 2))
UpdateTextBox comboBox, displayTextBox
UpdateTextBox67WithComboBox comboBox, displayTextBox67
UpdateAssociatedTextBoxes comboBox, associatedTextBoxStart
End If
Dim txtIndex As Integer: txtIndex = CInt(Mid(comboBox.Name, Len(comboBox.Name)))
Me.Controls("TextBox" & (txtIndex + 6)).value = IIf(comboBox.value = "", "", "10000")
End Sub
Private Sub ComboBox1_Change()
ComboBox_Change Me.ComboBox1, Me.TextBox1, 13, Me.TextBox67
End Sub
Private Sub ComboBox2_Change()
ComboBox_Change Me.ComboBox2, Me.TextBox2, 19, Me.TextBox68
End Sub
Private Sub ComboBox3_Change()
ComboBox_Change Me.ComboBox3, Me.TextBox3, 25, Me.TextBox69
End Sub
Private Sub ComboBox4_Change()
ComboBox_Change Me.ComboBox4, Me.TextBox4, 31, Me.TextBox70
End Sub
Private Sub ComboBox5_Change()
ComboBox_Change Me.ComboBox5, Me.TextBox5, 37, Me.TextBox71
End Sub
Private Sub ComboBox6_Change()
ComboBox_Change Me.ComboBox6, Me.TextBox6, 43, Me.TextBox72
End Sub
Private Sub UpdateComboBoxes(group As Integer)
Dim items As Collection
Set items = New Collection
Dim i As Integer, j As Integer, k As Integer
Dim combos(1 To 3) As MSForms.comboBox
Dim selectedValues As Collection
Dim currentValue As String
isUpdating = True
Set selectedValues = New Collection
For i = 1 To 3
Set combos(i) = Me.Controls("ComboBox" & ((group - 1) * 3 + i))
Next i
' 收集所有已選擇的值
For i = 1 To 3
If combos(i).value <> "" Then
On Error Resume Next
selectedValues.Add combos(i).value, CStr(combos(i).value)
On Error GoTo 0
End If
Next i
' 更新可選項
For i = 1 To 3
currentValue = combos(i).value
InitComboBox combos(i), ThisWorkbook.Sheets("武將表").Range("F12:F121")
' 移除已選擇的值
For j = 1 To selectedValues.Count
If CStr(selectedValues(j)) <> currentValue Then
For k = combos(i).ListCount - 1 To 0 Step -1
If combos(i).list(k) = selectedValues(j) Then
combos(i).RemoveItem k
End If
Next k
End If
Next j
combos(i).value = currentValue
Next i
isUpdating = False
End Sub
Private Sub UpdateTextBox(cmb As MSForms.comboBox, txt As MSForms.TextBox)
Dim ws As Worksheet
Dim found As Range
Dim r As Range
Set ws = ThisWorkbook.Sheets("武將表")
Set r = ws.Range("F12:F121")
Set found = r.Find(What:=cmb.value, LookIn:=xlValues, LookAt:=xlWhole)
If Not found Is Nothing Then
txt.value = ws.Cells(found.Row, "AM").value
Else
txt.value = "未找到對應的值"
End If
End Sub
Private Sub UpdateAssociatedTextBoxes(cmb As MSForms.comboBox, startTextBoxIndex As Integer)
Dim ws As Worksheet
Dim found As Range
Dim r As Range
Dim rowIndex As Long
Dim colIndex As Integer
Dim txt As MSForms.TextBox
Set ws = ThisWorkbook.Sheets("武將表")
Set r = ws.Range("F12:F121")
Set found = r.Find(What:=cmb.value, LookIn:=xlValues, LookAt:=xlWhole)
If Not found Is Nothing Then
rowIndex = found.Row
For colIndex = 0 To 5
Set txt = Me.Controls("TextBox" & startTextBoxIndex + colIndex)
txt.value = ws.Cells(rowIndex, 30 + colIndex).value
Next colIndex
Else
For colIndex = 0 To 5
Set txt = Me.Controls("TextBox" & startTextBoxIndex + colIndex)
txt.value = ""
Next colIndex
End If
End Sub
Private Sub UpdateTextBox67WithComboBox(cmb As MSForms.comboBox, txt As MSForms.TextBox)
Dim ws As Worksheet
Dim r As Range
Dim found As Range
Set ws = ThisWorkbook.Sheets("武將表")
Set r = ws.Range("F12:F121")
Set found = r.Find(What:=cmb.value, LookIn:=xlValues, LookAt:=xlWhole)
If Not found Is Nothing Then
txt.value = ws.Cells(found.Row, "G").value
Else
txt.value = "未找到對應值"
End If
End Sub
Private Sub ComboBox19_Change()
UpdateProficiencyTextBoxes Me.ComboBox19, Me.ComboBox1, Me.ComboBox2, Me.ComboBox3, Me.TextBox49, Me.TextBox50, Me.TextBox51
End Sub
Private Sub ComboBox20_Change()
UpdateProficiencyTextBoxes Me.ComboBox20, Me.ComboBox4, Me.ComboBox5, Me.ComboBox6, Me.TextBox52, Me.TextBox53, Me.TextBox54
End Sub
' 更新武將適性文本框
Private Sub UpdateProficiencyTextBoxes(typeCombo As MSForms.comboBox, warriorCombo1 As MSForms.comboBox, warriorCombo2 As MSForms.comboBox, warriorCombo3 As MSForms.comboBox, txt1 As MSForms.TextBox, txt2 As MSForms.TextBox, txt3 As MSForms.TextBox)
Dim ws As Worksheet
Dim colOffset As Integer
Set ws = ThisWorkbook.Sheets("武將表")
' 使用 Application.Match 來避免錯誤 1004
Dim matchResult As Variant
matchResult = Application.Match(typeCombo.value, ws.Range("M11:Q11"), 0)
If IsError(matchResult) Then
MsgBox "不能找到匹配的值。請檢查 ComboBox 的輸入值是否正確。", vbExclamation
colOffset = 0 ' 設置默認值或相應處理
Else
colOffset = matchResult - 1
End If
UpdateTextBoxForWarrior ws, warriorCombo1, colOffset, txt1
UpdateTextBoxForWarrior ws, warriorCombo2, colOffset, txt2
UpdateTextBoxForWarrior ws, warriorCombo3, colOffset, txt3
End Sub
Private Sub UpdateTextBoxForWarrior(ws As Worksheet, warriorCombo As MSForms.comboBox, colOffset As Integer, txt As MSForms.TextBox)
Dim r As Range
Dim found As Range
Set r = ws.Range("F12:F121")
Set found = r.Find(What:=warriorCombo.value, LookIn:=xlValues, LookAt:=xlWhole)
If Not found Is Nothing Then
txt.value = ws.Cells(found.Row, "M").Offset(0, colOffset).value
Else
txt.value = ""
End If
End Sub
Private Sub LimitTextBoxValue(txt As MSForms.TextBox)
Dim inputValue As Integer
inputValue = Val(txt.value)
If inputValue > 5 Then
txt.value = "5"
End If
End Sub
Private Sub UpdateTextBox_55()
Me.TextBox55.value = GetTotal(Me.CheckBox1, Me.CheckBox7, Me.TextBox61)
End Sub
Private Sub UpdateTextBox_56()
Me.TextBox56.value = GetTotal(Me.CheckBox2, Me.CheckBox8, Me.TextBox62)
End Sub
Private Sub UpdateTextBox_57()
Me.TextBox57.value = GetTotal(Me.CheckBox3, Me.CheckBox9, Me.TextBox63)
End Sub
Private Sub UpdateTextBox_58()
Me.TextBox58.value = GetTotal(Me.CheckBox4, Me.CheckBox10, Me.TextBox64)
End Sub
Private Sub UpdateTextBox_59()
Me.TextBox59.value = GetTotal(Me.CheckBox5, Me.CheckBox11, Me.TextBox65)
End Sub
Private Sub UpdateTextBox_60()
Me.TextBox60.value = GetTotal(Me.CheckBox6, Me.CheckBox12, Me.TextBox66)
End Sub
Private Function GetTotal(chk1 As MSForms.CheckBox, chk2 As MSForms.CheckBox, txtSrc As MSForms.TextBox) As String
Dim total As Integer
total = 0
If chk1.value = True Then total = total + 10
If chk2.value = True Then total = total + 10
total = total + (Val(txtSrc.value) * 10)
GetTotal = CStr(total)
End Function
Private Sub TextBox61_Change()
LimitTextBoxValue Me.TextBox61
UpdateTextBox_55
End Sub
Private Sub CheckBox1_Click()
UpdateTextBox_55
End Sub
Private Sub CheckBox7_Click()
UpdateTextBox_55
End Sub
Private Sub TextBox62_Change()
LimitTextBoxValue Me.TextBox62
UpdateTextBox_56
End Sub
Private Sub CheckBox2_Click()
UpdateTextBox_56
End Sub
Private Sub CheckBox8_Click()
UpdateTextBox_56
End Sub
Private Sub TextBox63_Change()
LimitTextBoxValue Me.TextBox63
UpdateTextBox_57
End Sub
Private Sub CheckBox3_Click()
UpdateTextBox_57
End Sub
Private Sub CheckBox9_Click()
UpdateTextBox_57
End Sub
Private Sub TextBox64_Change()
LimitTextBoxValue Me.TextBox64
UpdateTextBox_58
End Sub
Private Sub CheckBox4_Click()
UpdateTextBox_58
End Sub
Private Sub CheckBox10_Click()
UpdateTextBox_58
End Sub
Private Sub TextBox65_Change()
LimitTextBoxValue Me.TextBox65
UpdateTextBox_59
End Sub
Private Sub CheckBox5_Click()
UpdateTextBox_59
End Sub
Private Sub CheckBox11_Click()
UpdateTextBox_59
End Sub
Private Sub TextBox66_Change()
LimitTextBoxValue Me.TextBox66
UpdateTextBox_60
End Sub
Private Sub CheckBox6_Click()
UpdateTextBox_60
End Sub
Private Sub CheckBox12_Click()
UpdateTextBox_60
End Sub
Private Sub CommandButton1_Click()
' 檢查 ComboBox19 和 ComboBox20 是否為空
If Me.ComboBox19.value = "" Then
MsgBox "兵種請勿空白(我方)", vbExclamation, "輸入錯誤"
Exit Sub
End If
If Me.ComboBox20.value = "" Then
MsgBox "兵種請勿空白(敵方)", vbExclamation, "輸入錯誤"
Exit Sub
End If
' 初始化我方和敵方武將的集合
Dim allUnits As Collection
Set allUnits = New Collection
' 清空 ListBox1
Me.ListBox1.Clear
' 初始化武將及其屬性
AddUnit allUnits, "主將", ComboBox1, 13, TextBox7, TextBox49
AddUnit allUnits, "副將", ComboBox2, 19, TextBox8, TextBox50
AddUnit allUnits, "副將", ComboBox3, 25, TextBox9, TextBox51
AddUnit allUnits, "主將", ComboBox4, 31, TextBox10, TextBox52
AddUnit allUnits, "副將", ComboBox5, 37, TextBox11, TextBox53
AddUnit allUnits, "副將", ComboBox6, 43, TextBox12, TextBox54
' 計算初始兵力總和
Dim initialTeam1Forces As Double
Dim initialTeam2Forces As Double
initialTeam1Forces = Val(TextBox7.value) + Val(TextBox8.value) + Val(TextBox9.value)
initialTeam2Forces = Val(TextBox10.value) + Val(TextBox11.value) + Val(TextBox12.value)
' 開始模擬回合
SimulateRounds allUnits, initialTeam1Forces, initialTeam2Forces
' 更新 ListBox1 顯示 TextBox109 的內容
UpdateListBoxFromTextBox
End Sub
Private Sub UpdateListBoxFromTextBox()
Dim content As String
Dim lines() As String
Dim i As Integer
Dim paragraphEmpty As Boolean
' 取得 TextBox109 的所有內容
content = Me.TextBox109.Text
' 按行分隔內容
lines = Split(content, vbCrLf)
' 清除 ListBox1 的內容
Me.ListBox1.Clear
' 初始段落空行為 True
paragraphEmpty = True
' 逐行添加到 ListBox1 中
For i = LBound(lines) To UBound(lines)
Dim trimmedLine As String
trimmedLine = Trim(lines(i))
If trimmedLine = "" Then
' 只在非段落開頭和非空段落後插入空白行
If Not paragraphEmpty Then
Me.ListBox1.AddItem ""
paragraphEmpty = True
End If
Else
Me.ListBox1.AddItem trimmedLine
paragraphEmpty = False
End If
Next i
End Sub
Private Sub CommandButton2_Click()
' 清除 TextBox109 的內容
Me.TextBox109.Text = ""
' 清除 Label26 和 Label27 的內容
Me.Label26.Caption = ""
Me.Label27.Caption = ""
' 清除 ListBox1 的內容
Me.ListBox1.Clear
End Sub
Private Function GetProficiencyFactor(proficiency As String) As Double
Select Case proficiency
Case "S"
GetProficiencyFactor = 1.2
Case "A"
GetProficiencyFactor = 1
Case "B"
GetProficiencyFactor = 0.85
Case "C"
GetProficiencyFactor = 0.7
Case Else
GetProficiencyFactor = 1
End Select
End Function
Private Sub AddUnit(units As Collection, Name As String, cmb As MSForms.comboBox, startIndex As Integer, forceTextBox As MSForms.TextBox, proficiencyTextBox As MSForms.TextBox)
If cmb.value <> "" Then
Dim unit As Object
Dim proficiencyFactor As Double
Dim comboIndex As Integer
Set unit = CreateObject("Scripting.Dictionary")
' 設置兵種適性
unit.Add "proficiency", proficiencyTextBox.value
' 預先計算適性調整因子
Select Case proficiencyTextBox.value
Case "S"
proficiencyFactor = 1.2
Case "A"
proficiencyFactor = 1#
Case "B"
proficiencyFactor = 0.85
Case "C"
proficiencyFactor = 0.7
Case Else
proficiencyFactor = 1#
End Select
unit.Add "name", Name
unit.Add "startIndex", startIndex
unit.Add "speed", Val(Me.Controls("TextBox" & startIndex + 3).value) * proficiencyFactor
unit.Add "force", Val(Me.Controls("TextBox" & startIndex).value) * proficiencyFactor
unit.Add "warriorName", cmb.value
unit.Add "forces", Val(forceTextBox.value)
' 根據 ComboBox 名稱判斷 index
comboIndex = CInt(Mid(cmb.Name, Len("ComboBox") + 1))
' 添加兵種
If comboIndex >= 1 And comboIndex <= 3 Then
unit.Add "兵種", Me.Controls("ComboBox19").value
ElseIf comboIndex >= 4 And comboIndex <= 6 Then
unit.Add "兵種", Me.Controls("ComboBox20").value
End If
unit.Add "兵種適性", proficiencyTextBox.value
' 添加戰法信息
Dim selfSkillName As String
selfSkillName = Me.Controls("TextBox" & comboIndex).Text
unit.Add "selfSkillName", selfSkillName
unit.Add "selfSkillProbability", GetWarSkillProbability(selfSkillName)
unit.Add "selfSkillType", GetWarSkillType(selfSkillName)
' 添加額外戰法信息
Dim additionalSkillName As String
additionalSkillName = Me.Controls("ComboBox" & (comboIndex + 6)).value
unit.Add "additionalSkillName", additionalSkillName
unit.Add "additionalSkillProbability", GetWarSkillProbability(additionalSkillName)
unit.Add "additionalSkillType", GetWarSkillType(additionalSkillName)
' 為第三組 ComboBox 初始化額外額外戰法信息
Dim extraSkillName As String
extraSkillName = Me.Controls("ComboBox" & (comboIndex + 12)).value
unit.Add "extraSkillName", extraSkillName
unit.Add "extraSkillProbability", GetWarSkillProbability(extraSkillName)
unit.Add "extraSkillType", GetWarSkillType(extraSkillName)
' 添加單位到集合
units.Add unit
End If
End Sub
Private Function SortUnitsBySpeed(units As Collection) As Collection
Dim i As Integer, j As Integer
Dim unit As Object
Dim sortedUnits As New Collection
For i = 1 To units.Count
Set unit = units(i)
If sortedUnits.Count = 0 Then
sortedUnits.Add unit
Else
For j = 1 To sortedUnits.Count
If unit("speed") > sortedUnits(j)("speed") Then
sortedUnits.Add unit, , j
Exit For
End If
Next j
If j > sortedUnits.Count Then sortedUnits.Add unit
End If
Next i
Set SortUnitsBySpeed = sortedUnits
End Function
Private Sub SimulateRounds(units As Collection, initialTeam1Forces As Double, initialTeam2Forces As Double)
Dim attacker As Object, target As Object
Dim speedSortedUnits As Collection
Dim i As Integer
Dim targetIndex As Integer
Dim team1Forces As Double, team2Forces As Double
Dim displayText As String
' 初始化顯示文本並重新排列顯示順序
displayText = "準備回合" & vbCrLf & vbCrLf & "雙方屬性數值:" & vbCrLf
For i = 1 To units.Count
Dim unit As Object
Set unit = units(i)
Dim proficiencyFactor As Double
proficiencyFactor = GetProficiencyFactor(unit("proficiency"))
Dim teamName As String
' 判斷是我方還是敵方
If unit("startIndex") <= 25 Then
teamName = "我方"
Else
teamName = "敵方"
End If
displayText = displayText & "(" & teamName & ") " & unit("warriorName") & " 的兵種適性為 " & unit("proficiency") & ",調整後屬性:" & _
"武力: " & Format(Val(Me.Controls("TextBox" & unit("startIndex")).value) * proficiencyFactor, "0.0") & "" & _
"智力: " & Format(Val(Me.Controls("TextBox" & (unit("startIndex") + 1)).value) * proficiencyFactor, "0.0") & "" & _
"統率: " & Format(Val(Me.Controls("TextBox" & (unit("startIndex") + 2)).value) * proficiencyFactor, "0.0") & "" & _
"速度: " & Format(Val(Me.Controls("TextBox" & (unit("startIndex") + 3)).value) * proficiencyFactor, "0.0") & "" & _
"政治: " & Format(Val(Me.Controls("TextBox" & (unit("startIndex") + 4)).value) * proficiencyFactor, "0.0") & "" & _
"魅力: " & Format(Val(Me.Controls("TextBox" & (unit("startIndex") + 5)).value) * proficiencyFactor, "0.0") & vbCrLf & vbCrLf
Next i
' 準備回合:觸發指揮、兵種、陣營類型的戰法
For Each attacker In units
If attacker("forces") > 0 Then
TriggerPreparationSkills attacker, displayText
End If
Next attacker
' 開始模擬
For i = 1 To 8 ' 限制到最多八回合
displayText = displayText & vbCrLf & "第 " & i & " 回合:" & vbCrLf
' 按速度排序單元
Set speedSortedUnits = SortUnitsBySpeed(units)
' 初始化隊伍力量
team1Forces = 0
team2Forces = 0
For Each attacker In speedSortedUnits
' 忽略已陣亡的角色
If attacker("forces") > 0 Then
Dim attackerTeam As String
If attacker("startIndex") <= 25 Then
attackerTeam = "我方"
team1Forces = team1Forces + attacker("forces")
Else
attackerTeam = "敵方"
team2Forces = team2Forces + attacker("forces")
End If
displayText = displayText & "(" & attackerTeam & ") " & attacker("warriorName") & " 開始行動" & vbCrLf
' 試圖選擇一個有效的目標
Do
targetIndex = Application.WorksheetFunction.RandBetween(1, speedSortedUnits.Count)
Set target = speedSortedUnits(targetIndex)
Loop While (SameTeam(attacker("startIndex"), target("startIndex")) Or target("forces") <= 0)
' 依次發動 主動 → 普通攻擊 → 突擊 → 被動
TryCombatSkills attacker, attackerTeam, target, displayText
' 為簡易閱讀增加換行段落
displayText = displayText & vbCrLf
End If
Next attacker
' 添加分隔線
displayText = displayText & String(143, "-") & vbCrLf
' 停止模擬,如果任一主將被擊敗
If units(1)("forces") <= 0 Or units(4)("forces") <= 0 Then
Exit For
End If
Next i
' 更新 Label26 和 Label27 來顯示剩餘/初始兵力
Me.Label26.Caption = team1Forces & "/" & initialTeam1Forces
Me.Label27.Caption = team2Forces & "/" & initialTeam2Forces
Me.TextBox109.Text = displayText
' 確定勝利者並設置字體顏色
If team1Forces > team2Forces Then
Me.Label28.Caption = "勝"
Me.Label28.ForeColor = RGB(255, 255, 0) ' 黃色
Me.Label29.Caption = "敗"
Me.Label29.ForeColor = RGB(255, 0, 0) ' 紅色
ElseIf team1Forces < team2Forces Then
Me.Label28.Caption = "敗"
Me.Label28.ForeColor = RGB(255, 0, 0) ' 紅色
Me.Label29.Caption = "勝"
Me.Label29.ForeColor = RGB(255, 255, 0) ' 黃色
Else
Me.Label28.Caption = "平"
Me.Label28.ForeColor = RGB(255, 255, 255) ' 白色
Me.Label29.Caption = "平"
Me.Label29.ForeColor = RGB(255, 255, 255) ' 白色
End If
End Sub
Private Sub TryCombatSkills(attacker As Object, team As String, target As Object, ByRef displayText As String)
Dim attackOrder As Variant
attackOrder = Array("主動", "普通", "突擊", "被動")
Dim allSkills As Collection
Set allSkills = New Collection
allSkills.Add Array(attacker("selfSkillName"), attacker("selfSkillProbability"), attacker("selfSkillType"))
allSkills.Add Array(attacker("additionalSkillName"), attacker("additionalSkillProbability"), attacker("additionalSkillType"))
allSkills.Add Array(attacker("extraSkillName"), attacker("extraSkillProbability"), attacker("extraSkillType"))
Dim skillInfo As Variant
Dim rng As Double
Dim isTriggered As Boolean
' 設定隊伍名稱
Dim teamName As String
If attacker("startIndex") <= 25 Then
teamName = "我方"
Else
teamName = "敵方"
End If
' 確認技能順序和普通攻擊順序
For Each Order In attackOrder
For Each skillInfo In allSkills
If skillInfo(0) <> "" And skillInfo(2) = Order Then
rng = Rnd()
isTriggered = rng <= skillInfo(1)
displayText = displayText & "(" & teamName & ") " & attacker("warriorName") & " 嘗試發動 " & skillInfo(0) & " (" & _
Format(skillInfo(1) * 100, "0.0") & "%) - " & IIf(isTriggered, "成功", "失敗") & "。" & vbCrLf
End If
Next skillInfo
If Order = "普通" Then
Dim damage As Double
damage = CalculateDamage(attacker, target)
' 更新目標的兵力
target("forces") = target("forces") - damage
' 調整displayText以包含損失與剩餘信息
displayText = displayText & "(" & teamName & ") " & attacker("warriorName") & " 對 " & target("warriorName") & " 發動普通攻擊,造成損失 " & damage & " 兵力。" & _
" (剩餘 " & target("forces") & " 兵力)" & vbCrLf
End If
Next Order
End Sub
Private Sub TriggerPreparationSkills(attacker As Object, ByRef displayText As String)
Dim skillTypes As Variant
skillTypes = Array("指揮", "兵種", "陣法")
TriggerSkillsByType attacker, skillTypes, displayText, "準備階段"
End Sub
Private Sub TriggerSkillsByType(attacker As Object, types As Variant, ByRef displayText As String, phase As String)
Dim skillNames As Variant
Dim SkillType As String
Dim rng As Double
Dim isTriggered As Boolean
Dim teamName As String
' Determine if the unit is from team 1 or team 2
If attacker("startIndex") <= 25 Then
teamName = "我方"
Else
teamName = "敵方"
End If
skillNames = Array(attacker("selfSkillName"), attacker("additionalSkillName"), attacker("extraSkillName"))
' Check skills and trigger them if applicable at the current phase
For Each SkillName In skillNames
If Not IsNull(SkillName) And SkillName <> "" Then ' Ensure skill names are not empty or null
SkillType = GetWarSkillType(CStr(SkillName))
If IsInList(SkillType, types) Then
rng = Rnd()
isTriggered = rng <= GetWarSkillProbability(CStr(SkillName))
If isTriggered Then
displayText = displayText & "(" & teamName & ") " & attacker("warriorName") & " 發動 " & SkillName & " (" _
& Format(GetWarSkillProbability(CStr(SkillName)) * 100, "0.0") & "%) - 成功" & vbCrLf
Else
displayText = displayText & "(" & teamName & ") " & attacker("warriorName") & " 嘗試發動 " & SkillName & " (" _
& Format(GetWarSkillProbability(CStr(SkillName)) * 100, "0.0") & "%) - 失敗" & vbCrLf
End If
End If
End If
Next SkillName
End Sub
Private Function IsInList(value As String, list As Variant) As Boolean
Dim i As Integer
For i = LBound(list) To UBound(list)
If list(i) = value Then
IsInList = True
Exit Function
End If
Next i
IsInList = False
End Function
Private Function GetWarSkillProbability(SkillName As String) As Double
Dim ws As Worksheet
Dim r As Range
Dim found As Range
Set ws = ThisWorkbook.Sheets("武將表")
Set r = ws.Range("AM12:AM234") ' 假設技能名稱信息位於這個範圍
Set found = r.Find(What:=Trim(SkillName), LookIn:=xlValues, LookAt:=xlWhole)
If Not found Is Nothing Then
GetWarSkillProbability = ws.Cells(found.Row, "AO").value
Else
GetWarSkillProbability = 0
End If
End Function
Private Function GetWarSkillType(SkillName As String) As String
Dim ws As Worksheet
Dim r As Range
Dim found As Range
Set ws = ThisWorkbook.Sheets("武將表")
Set r = ws.Range("AM12:AM234") ' 假設技能名稱信息位於這個範圍
Set found = r.Find(What:=Trim(SkillName), LookIn:=xlValues, LookAt:=xlWhole)
If Not found Is Nothing Then
GetWarSkillType = ws.Cells(found.Row, "AN").value
Else
GetWarSkillType = ""
End If
End Function
Private Function CalculateDamage(attacker As Object, target As Object) As Double
Dim attack As Double
Dim defense As Double
Dim advantage As Double
Dim proficiencyFactor As Double
Dim Z As Double
Dim s As Double
Dim baseDamage As Double
Dim minimumDamage As Double
attack = attacker("force")
defense = target("force")
proficiencyFactor = GetProficiencyFactor(attacker("proficiency"))
advantage = 1
' 驗證兵種剋制
Select Case attacker("兵種")
Case "騎兵"
If target("兵種") = "盾兵" Or target("兵種") = "器械" Then
advantage = 1.15
End If
Case "盾兵"
If target("兵種") = "弓兵" Or target("兵種") = "器械" Then
advantage = 1.15
End If
Case "弓兵"
If target("兵種") = "槍兵" Or target("兵種") = "器械" Then
advantage = 1.15
End If
Case "槍兵"
If target("兵種") = "騎兵" Or target("兵種") = "器械" Then
advantage = 1.15
End If
End Select
' 計算 Z 和 S
Z = attack * proficiencyFactor * advantage
s = ((Z - defense) / 150 + 1) * (attacker("forces") / 20)
' 判斷是否需要使用傷害公式 2
If s <= 0 Then
baseDamage = GetBaseDamage(attacker("forces"))
minimumDamage = GetMinimumDamage(attacker("forces"))
s = baseDamage + (attack * 1.6 - defense * 1.6) * 0.9 + minimumDamage
If s < 0 Then s = 0 ' 防止負值
End If
' 無條件進位傷害至整數
CalculateDamage = Application.WorksheetFunction.RoundUp(s, 0)
End Function
Private Function GetBaseDamage(forces As Double) As Double
Select Case forces
Case Is <= 1000: GetBaseDamage = 88
Case Is <= 2000: GetBaseDamage = 176
Case Is <= 3000: GetBaseDamage = 232
Case Is <= 4000: GetBaseDamage = 276
Case Is <= 5000: GetBaseDamage = 314
Case Is <= 6000: GetBaseDamage = 334
Case Is <= 7000: GetBaseDamage = 350
Case Is <= 8000: GetBaseDamage = 364
Case Is <= 9000: GetBaseDamage = 376
Case Else: GetBaseDamage = 387
End Select
End Function
Private Function GetMinimumDamage(forces As Double) As Double
Select Case forces
Case Is <= 1000: GetMinimumDamage = 20
Case Is <= 2000: GetMinimumDamage = 40
Case Is <= 3000: GetMinimumDamage = 53
Case Is <= 4000: GetMinimumDamage = 64
Case Is <= 5000: GetMinimumDamage = 73
Case Is <= 6000: GetMinimumDamage = 77
Case Is <= 7000: GetMinimumDamage = 81
Case Is <= 8000: GetMinimumDamage = 84
Case Is <= 9000: GetMinimumDamage = 87
Case Else: GetMinimumDamage = 90
End Select
End Function
Private Function SameTeam(index1 As Integer, index2 As Integer) As Boolean
' 判斷兩個索引是否在相同隊伍
SameTeam = (index1 <= 25 And index2 <= 25) Or (index1 > 25 And index2 > 25)
End Function
' 第一組 CommandButton 和 TextBox 的事件處理
Private Sub CommandButton3_Click()
UpdateValues Me.TextBox55, Me.TextBox13, Me.TextBox73
End Sub
Private Sub CommandButton4_Click()
UpdateValues Me.TextBox55, Me.TextBox14, Me.TextBox74
End Sub
Private Sub CommandButton5_Click()
UpdateValues Me.TextBox55, Me.TextBox15, Me.TextBox75
End Sub
Private Sub CommandButton6_Click()
UpdateValues Me.TextBox55, Me.TextBox16, Me.TextBox76
End Sub
Private Sub CommandButton7_Click()
UpdateValues Me.TextBox55, Me.TextBox17, Me.TextBox77
End Sub
Private Sub CommandButton8_Click()
UpdateValues Me.TextBox55, Me.TextBox18, Me.TextBox78
End Sub
' 第二組 CommandButton 和 TextBox 的事件
Private Sub CommandButton9_Click()
UpdateValues Me.TextBox56, Me.TextBox19, Me.TextBox79
End Sub
Private Sub CommandButton10_Click()
UpdateValues Me.TextBox56, Me.TextBox20, Me.TextBox80
End Sub
Private Sub CommandButton11_Click()
UpdateValues Me.TextBox56, Me.TextBox21, Me.TextBox81
End Sub
Private Sub CommandButton12_Click()
UpdateValues Me.TextBox56, Me.TextBox22, Me.TextBox82
End Sub
Private Sub CommandButton13_Click()
UpdateValues Me.TextBox56, Me.TextBox23, Me.TextBox83
End Sub
Private Sub CommandButton14_Click()
UpdateValues Me.TextBox56, Me.TextBox24, Me.TextBox84
End Sub
' 第三組 CommandButton 和 TextBox 的事件
Private Sub CommandButton15_Click()
UpdateValues Me.TextBox57, Me.TextBox25, Me.TextBox85
End Sub
Private Sub CommandButton16_Click()
UpdateValues Me.TextBox57, Me.TextBox26, Me.TextBox86
End Sub
Private Sub CommandButton17_Click()
UpdateValues Me.TextBox57, Me.TextBox27, Me.TextBox87
End Sub
Private Sub CommandButton18_Click()
UpdateValues Me.TextBox57, Me.TextBox28, Me.TextBox88
End Sub
Private Sub CommandButton19_Click()
UpdateValues Me.TextBox57, Me.TextBox29, Me.TextBox89
End Sub
Private Sub CommandButton20_Click()
UpdateValues Me.TextBox57, Me.TextBox30, Me.TextBox90
End Sub
' 第四組 CommandButton 和 TextBox 的事件
Private Sub CommandButton21_Click()
UpdateValues Me.TextBox58, Me.TextBox31, Me.TextBox91
End Sub
Private Sub CommandButton22_Click()
UpdateValues Me.TextBox58, Me.TextBox32, Me.TextBox92
End Sub
Private Sub CommandButton23_Click()
UpdateValues Me.TextBox58, Me.TextBox33, Me.TextBox93
End Sub
Private Sub CommandButton24_Click()
UpdateValues Me.TextBox58, Me.TextBox34, Me.TextBox94
End Sub
Private Sub CommandButton25_Click()
UpdateValues Me.TextBox58, Me.TextBox35, Me.TextBox95
End Sub
Private Sub CommandButton26_Click()
UpdateValues Me.TextBox58, Me.TextBox36, Me.TextBox96
End Sub
' 第五組 CommandButton 和 TextBox 的事件
Private Sub CommandButton27_Click()
UpdateValues Me.TextBox59, Me.TextBox37, Me.TextBox97
End Sub
Private Sub CommandButton28_Click()
UpdateValues Me.TextBox59, Me.TextBox38, Me.TextBox98
End Sub
Private Sub CommandButton29_Click()
UpdateValues Me.TextBox59, Me.TextBox39, Me.TextBox99
End Sub
Private Sub CommandButton30_Click()
UpdateValues Me.TextBox59, Me.TextBox40, Me.TextBox100
End Sub
Private Sub CommandButton31_Click()
UpdateValues Me.TextBox59, Me.TextBox41, Me.TextBox101
End Sub
Private Sub CommandButton32_Click()
UpdateValues Me.TextBox59, Me.TextBox42, Me.TextBox102
End Sub
' 第六組 CommandButton 和 TextBox 的事件
Private Sub CommandButton33_Click()
UpdateValues Me.TextBox60, Me.TextBox43, Me.TextBox103
End Sub
Private Sub CommandButton34_Click()
UpdateValues Me.TextBox60, Me.TextBox44, Me.TextBox104
End Sub
Private Sub CommandButton35_Click()
UpdateValues Me.TextBox60, Me.TextBox45, Me.TextBox105
End Sub
Private Sub CommandButton36_Click()
UpdateValues Me.TextBox60, Me.TextBox46, Me.TextBox106
End Sub
Private Sub CommandButton37_Click()
UpdateValues Me.TextBox60, Me.TextBox47, Me.TextBox107
End Sub
Private Sub CommandButton38_Click()
UpdateValues Me.TextBox60, Me.TextBox48, Me.TextBox108
End Sub
' 更新邏輯的核心子程序
Private Sub UpdateValues(sourceTextBox As MSForms.TextBox, incrementTextBox As MSForms.TextBox, counterTextBox As MSForms.TextBox)
Dim currentValue As Integer
Dim currentIncrement As Double
Dim currentCount As Integer
' 確認數值有效
currentValue = SafeVal(sourceTextBox)
currentIncrement = SafeValDouble(incrementTextBox)
currentCount = SafeVal(counterTextBox)
' 確保 Textbox 值大於零才能操作
If currentValue > 0 Then
' 減少來源 TextBox 的值
sourceTextBox.value = currentValue - 1
' 增加到相應 TextBox 並保留一位小數
currentIncrement = currentIncrement + 1
incrementTextBox.value = Format(currentIncrement, "0.0")
' 增至計數 TextBox
counterTextBox.value = currentCount + 1
End If
' 更新按鈕狀態
UpdateButtonStates
End Sub
Private Sub CommandButton39_Click()
ShowRoundContent "準備回合"
End Sub
Private Sub CommandButton40_Click()
ShowRoundContent "第 1 回合"
End Sub
Private Sub CommandButton41_Click()
ShowRoundContent "第 2 回合"
End Sub
Private Sub CommandButton42_Click()
ShowRoundContent "第 3 回合"
End Sub
Private Sub CommandButton43_Click()
ShowRoundContent "第 4 回合"
End Sub
Private Sub CommandButton44_Click()
ShowRoundContent "第 5 回合"
End Sub
Private Sub CommandButton45_Click()
ShowRoundContent "第 6 回合"
End Sub
Private Sub CommandButton46_Click()
ShowRoundContent "第 7 回合"
End Sub
Private Sub CommandButton47_Click()
ShowRoundContent "第 8 回合"
End Sub
Private Sub UpdateButtonStates()
' 檢查 TextBox55 到 TextBox60 的值,並相應地啟用或禁用按鈕
Me.CommandButton3.Enabled = (Val(Me.TextBox55.value) > 0)
Me.CommandButton4.Enabled = (Val(Me.TextBox55.value) > 0)
Me.CommandButton5.Enabled = (Val(Me.TextBox55.value) > 0)
Me.CommandButton6.Enabled = (Val(Me.TextBox55.value) > 0)
Me.CommandButton7.Enabled = (Val(Me.TextBox55.value) > 0)
Me.CommandButton8.Enabled = (Val(Me.TextBox55.value) > 0)
Me.CommandButton9.Enabled = (Val(Me.TextBox56.value) > 0)
Me.CommandButton10.Enabled = (Val(Me.TextBox56.value) > 0)
Me.CommandButton11.Enabled = (Val(Me.TextBox56.value) > 0)
Me.CommandButton12.Enabled = (Val(Me.TextBox56.value) > 0)
Me.CommandButton13.Enabled = (Val(Me.TextBox56.value) > 0)
Me.CommandButton14.Enabled = (Val(Me.TextBox56.value) > 0)
Me.CommandButton15.Enabled = (Val(Me.TextBox57.value) > 0)
Me.CommandButton16.Enabled = (Val(Me.TextBox57.value) > 0)
Me.CommandButton17.Enabled = (Val(Me.TextBox57.value) > 0)
Me.CommandButton18.Enabled = (Val(Me.TextBox57.value) > 0)
Me.CommandButton19.Enabled = (Val(Me.TextBox57.value) > 0)
Me.CommandButton20.Enabled = (Val(Me.TextBox57.value) > 0)
Me.CommandButton21.Enabled = (Val(Me.TextBox58.value) > 0)
Me.CommandButton22.Enabled = (Val(Me.TextBox58.value) > 0)
Me.CommandButton23.Enabled = (Val(Me.TextBox58.value) > 0)
Me.CommandButton24.Enabled = (Val(Me.TextBox58.value) > 0)
Me.CommandButton25.Enabled = (Val(Me.TextBox58.value) > 0)
Me.CommandButton26.Enabled = (Val(Me.TextBox58.value) > 0)
Me.CommandButton27.Enabled = (Val(Me.TextBox59.value) > 0)
Me.CommandButton28.Enabled = (Val(Me.TextBox59.value) > 0)
Me.CommandButton29.Enabled = (Val(Me.TextBox59.value) > 0)
Me.CommandButton30.Enabled = (Val(Me.TextBox59.value) > 0)
Me.CommandButton31.Enabled = (Val(Me.TextBox59.value) > 0)
Me.CommandButton32.Enabled = (Val(Me.TextBox59.value) > 0)
Me.CommandButton33.Enabled = (Val(Me.TextBox60.value) > 0)
Me.CommandButton34.Enabled = (Val(Me.TextBox60.value) > 0)
Me.CommandButton35.Enabled = (Val(Me.TextBox60.value) > 0)
Me.CommandButton36.Enabled = (Val(Me.TextBox60.value) > 0)
Me.CommandButton37.Enabled = (Val(Me.TextBox60.value) > 0)
Me.CommandButton38.Enabled = (Val(Me.TextBox60.value) > 0)
End Sub
Private Sub TextBox55_Change()
If Val(Me.TextBox55.value) < 0 Then Me.TextBox55.value = 0
UpdateButtonStates
End Sub
Private Sub TextBox56_Change()
If Val(Me.TextBox56.value) < 0 Then Me.TextBox56.value = 0
UpdateButtonStates
End Sub
Private Sub TextBox57_Change()
If Val(Me.TextBox57.value) < 0 Then Me.TextBox57.value = 0
UpdateButtonStates
End Sub
Private Sub TextBox58_Change()
If Val(Me.TextBox58.value) < 0 Then Me.TextBox58.value = 0
UpdateButtonStates
End Sub
Private Sub TextBox59_Change()
If Val(Me.TextBox59.value) < 0 Then Me.TextBox59.value = 0
UpdateButtonStates
End Sub
Private Sub TextBox60_Change()
If Val(Me.TextBox60.value) < 0 Then Me.TextBox60.value = 0
UpdateButtonStates
End Sub
Private Function SafeVal(txtBox As MSForms.TextBox) As Integer
' 如果TextBox有合法數字,返回其值,否則返回0
On Error Resume Next
SafeVal = Val(txtBox.value)
If Err.number <> 0 Then
SafeVal = 0
End If
On Error GoTo 0
End Function
Private Function SafeValDouble(txtBox As MSForms.TextBox) As Double
' 如果TextBox有合法數字,返回其值,否則返回0.0
On Error Resume Next
SafeValDouble = CDbl(txtBox.value)
If Err.number <> 0 Then
SafeValDouble = 0#
End If
On Error GoTo 0
End Function
Private Sub ShowRoundContent(roundText As String)
Dim position As Long
Dim content As String
Dim lines() As String
Dim i As Integer
Dim roundContent As String
Dim endOfRound As Boolean
endOfRound = False
' 取得TextBox的全部內容
content = Me.TextBox109.Text
' 以行符拆分內容
lines = Split(content, vbCrLf)
' 找到所需回合文本的開始行
For i = LBound(lines) To UBound(lines)
If InStr(lines(i), roundText) > 0 Then
' 開始行始,取得之后所有內容
roundContent = lines(i) & vbCrLf
i = i + 1
Exit For
End If
Next i
' 繼續取得?容直到下一?回合或文件的末尾
Do While i <= UBound(lines) And Not endOfRound
If Trim(lines(i)) <> "" Then
If InStr(lines(i), "回合") > 0 Then
endOfRound = True
Else
roundContent = roundContent & lines(i) & vbCrLf
' 在每個武將動作之間添加一個空行
roundContent = roundContent & vbCrLf
End If
End If
i = i + 1
Loop
If roundContent <> "" Then
' 設置ListBox的內容
Me.ListBox1.Clear
lines = Split(roundContent, vbCrLf)
' 確保添加空行分隔段落
Dim previousLineWasEmpty As Boolean
previousLineWasEmpty = True
For i = LBound(lines) To UBound(lines)
If Trim(lines(i)) <> "" Then
If Not previousLineWasEmpty Then
Me.ListBox1.AddItem "" ' 增加一行空白分隔
End If
Me.ListBox1.AddItem lines(i)
previousLineWasEmpty = False
Else
previousLineWasEmpty = True
End If
Next i
Else
MsgBox roundText & " 未找到", vbExclamation
End If
End Sub
這使我的程式 我要修改一些功能