forked from syntax53/Nightmare-Redux
-
Notifications
You must be signed in to change notification settings - Fork 0
/
clsMonsterAttackSim.cls
1382 lines (1108 loc) · 51.7 KB
/
clsMonsterAttackSim.cls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
Persistable = 0 'NotPersistable
DataBindingBehavior = 0 'vbNone
DataSourceBehavior = 0 'vbNone
MTSTransactionMode = 0 'NotAnMTSObject
END
Attribute VB_Name = "clsMonsterAttackSim"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Attribute VB_Ext_KEY = "SavedWithClassBuilder6" ,"Yes"
Attribute VB_Ext_KEY = "Top_Level" ,"Yes"
Attribute VB_Ext_KEY = "Member0" ,"colMonsterAttacks"
Option Explicit
Option Base 0
Private m_sAtkName(0 To 4) As String
Private m_nAtkType(0 To 4) As Integer
Private m_nAtkEnergy(0 To 4) As Integer
Private m_nAtkMin(0 To 4) As Integer
Private m_nAtkMax(0 To 4) As Integer
Private m_nAtkChance(0 To 4) As Integer
Private m_nAtkSuccess(0 To 4) As Integer
Private m_nAtkHitSpellMin(0 To 4) As Integer
Private m_nAtkHitSpellMax(0 To 4) As Integer
Private m_sAtkHitSpellName(0 To 4) As String
Private m_nAtkResist(0 To 4) As Integer
Private m_nAtkMRdmgResist(0 To 4) As Integer
Private m_nAtkDuration(0 To 4) As Integer
Private m_nStatAtkAttempted(0 To 4) As Currency
Private m_nStatAtkHits(0 To 4) As Currency
Private m_nStatAtkDmgResisted(0 To 4) As Currency
Private m_nStatAtkAttemptDodgedOrResisted(0 To 4) As Currency
Private m_nStatAtkTotalDamage(0 To 4) As Currency
Private m_nUserAC As Long
Private m_nUserDR As Long
Private m_nUserDodge As Long
Private m_nUserMR As Long
Private m_nUserAntiMagic As Integer
Private m_nEnergyPerRound As Integer
Private m_nNumberOfRounds As Long
Private m_nTotalAttacks As Currency
Private m_nTotalDamage As Currency
Private m_nMaxRoundDamage As Currency
Private m_nAverageDamage As Currency
Private m_nMaxEnergyPerRound As Long
Private m_bHideEnergyInfo As Boolean
Private m_bDynamicCalc As Boolean
Private m_nDynamicCalcDifference As Currency
Private m_bUseCPU As Boolean
Private m_cProgressBar As ProgressBar
Private nProgressBarScale As Integer
Private nProgressBarScaleCount As Long
Private m_sCombatLog As String
Private m_nCombatLogMaxRounds As Long
Private nCombatLogRoundCount As Long
Private m_bCombatLogMaxRoundOnly As Boolean
Private m_sBetweenRoundName(0 To 4) As String
Private m_nBetweenRoundMin(0 To 4) As Integer
Private m_nBetweenRoundMax(0 To 4) As Integer
Private m_nBetweenRoundChance(0 To 4) As Integer
Private m_nBetweenRoundResistType(0 To 4) As Integer
Private m_nBetweenRoundResistDmgMR(0 To 4) As Integer
Private m_nBetweenRoundDuration(0 To 4) As Integer
Private nActiveAtkSpells_Ticks(0 To 4) As Integer
Private nActiveAtkSpells_DurationLeft(0 To 4) As Currency
Private nActiveAtkSpells_Value(0 To 4) As Integer
Private nActiveAtkSpells_ValueOriginal(0 To 4) As Integer
Private nActiveBetweenSpells_Ticks(0 To 4) As Integer
Private nActiveBetweenSpells_DurationLeft(0 To 4) As Currency
Private nActiveBetweenSpells_Value(0 To 4) As Integer
Private nActiveBetweenSpells_ValueOriginal(0 To 4) As Integer
Public Property Let bHideEnergyInfo(ByVal vData As Boolean)
m_bHideEnergyInfo = vData
End Property
Public Property Get bHideEnergyInfo() As Boolean
bHideEnergyInfo = m_bHideEnergyInfo
End Property
Public Property Let bCombatLogMaxRoundOnly(ByVal vData As Boolean)
m_bCombatLogMaxRoundOnly = vData
End Property
Public Property Get bCombatLogMaxRoundOnly() As Boolean
bCombatLogMaxRoundOnly = m_bCombatLogMaxRoundOnly
End Property
Public Property Get nMaxEnergyPerRound() As Long
nMaxEnergyPerRound = m_nMaxEnergyPerRound
End Property
Public Property Get nAverageDamage() As Currency
nAverageDamage = m_nAverageDamage
End Property
Public Property Let nDynamicCalcDifference(ByVal vData As Currency)
m_nDynamicCalcDifference = vData
End Property
Public Property Get nDynamicCalcDifference() As Currency
nDynamicCalcDifference = m_nDynamicCalcDifference
End Property
Public Property Let bDynamicCalc(ByVal vData As Boolean)
m_bDynamicCalc = vData
End Property
Public Property Get bDynamicCalc() As Boolean
bDynamicCalc = m_bDynamicCalc
End Property
Public Property Get nAtkDuration(ByVal Index As Integer) As Integer
nAtkDuration = m_nAtkDuration(Index)
End Property
Public Property Let nAtkDuration(ByVal Index As Integer, ByVal iData As Integer)
m_nAtkDuration(Index) = iData
End Property
Public Property Get nBetweenRoundDuration(ByVal Index As Integer) As Integer
nBetweenRoundDuration = m_nBetweenRoundDuration(Index)
End Property
Public Property Let nBetweenRoundDuration(ByVal Index As Integer, ByVal iData As Integer)
m_nBetweenRoundDuration(Index) = iData
End Property
Public Property Get nBetweenRoundResistDmgMR(ByVal Index As Integer) As Integer
nBetweenRoundResistDmgMR = m_nBetweenRoundResistDmgMR(Index)
End Property
Public Property Let nBetweenRoundResistDmgMR(ByVal Index As Integer, ByVal iData As Integer)
m_nBetweenRoundResistDmgMR(Index) = iData
End Property
Public Property Get nBetweenRoundResistType(ByVal Index As Integer) As Integer
nBetweenRoundResistType = m_nBetweenRoundResistType(Index)
End Property
Public Property Let nBetweenRoundResistType(ByVal Index As Integer, ByVal iData As Integer)
m_nBetweenRoundResistType(Index) = iData
End Property
Public Property Get sBetweenRoundName(ByVal Index As Integer) As String
sBetweenRoundName = m_sBetweenRoundName(Index)
End Property
Public Property Let sBetweenRoundName(ByVal Index As Integer, ByVal sData As String)
m_sBetweenRoundName(Index) = sData
End Property
Public Property Get nBetweenRoundMin(ByVal Index As Integer) As Integer
nBetweenRoundMin = m_nBetweenRoundMin(Index)
End Property
Public Property Get nBetweenRoundMax(ByVal Index As Integer) As Integer
nBetweenRoundMax = m_nBetweenRoundMax(Index)
End Property
Public Property Get nBetweenRoundChance(ByVal Index As Integer) As Integer
nBetweenRoundChance = m_nBetweenRoundChance(Index)
End Property
Public Property Let nBetweenRoundChance(ByVal Index As Integer, ByVal iData As Integer)
m_nBetweenRoundChance(Index) = iData
End Property
Public Property Let nBetweenRoundMax(ByVal Index As Integer, ByVal iData As Integer)
m_nBetweenRoundMax(Index) = iData
End Property
Public Property Let nBetweenRoundMin(ByVal Index As Integer, ByVal iData As Integer)
m_nBetweenRoundMin(Index) = iData
End Property
Public Property Get nMaxRoundDamage() As Long
nMaxRoundDamage = m_nMaxRoundDamage
End Property
Public Property Get nCombatLogMaxRounds() As Long
nCombatLogMaxRounds = m_nCombatLogMaxRounds
End Property
Public Property Let nCombatLogMaxRounds(ByVal lNewValue As Long)
m_nCombatLogMaxRounds = lNewValue
End Property
Public Property Get sCombatLog() As String
sCombatLog = m_sCombatLog
End Property
Public Property Get nTotalDamage() As Currency
nTotalDamage = m_nTotalDamage
End Property
Public Property Get nTotalAttacks() As Long
nTotalAttacks = m_nTotalAttacks
End Property
Public Property Let bUseCPU(ByVal vData As Boolean)
m_bUseCPU = vData
End Property
Public Property Get bUseCPU() As Boolean
bUseCPU = m_bUseCPU
End Property
Public Function RandomNumber(startNum As Integer, endNum As Integer) As Integer
RandomNumber = Int(((endNum - startNum + 1) * Rnd) + startNum)
End Function
Private Sub AddToCombatLog(sLeft As String, Optional sRight As String = "")
On Error GoTo error:
If nCombatLogRoundCount >= m_nCombatLogMaxRounds Then Exit Sub
If m_bHideEnergyInfo Then
If InStr(1, sRight, "Energy", vbTextCompare) > 0 Then sRight = ""
End If
If Len(sRight) > 0 And Len(sLeft) > 29 Then
sLeft = Mid(sLeft, 1, 26) & "..."
End If
m_sCombatLog = m_sCombatLog & vbCrLf & sLeft
If Len(sRight) > 0 Then m_sCombatLog = m_sCombatLog & String(30 - Len(sLeft), " ") & sRight
out:
On Error Resume Next
Exit Sub
error:
Call privHandleError("AddToCombatLog")
Resume out:
End Sub
Public Function GetMaxDamage()
Dim x As Integer, bNothingToSim As Boolean
Dim nAttack As Integer
Dim nLeastEnergyUsed As Long, nLowestCostAttack As Long, nLowEnergy As Long
Dim nMaxEnergyRound As Long, nMaxCostAttack As Long
Dim nDamage As Long, nMaxDamage As Long, nMaxAttempts As Integer, nMaxDPE As Currency
Dim nEnergyForAttack As Long, nEnergyRemaining As Long, nDamagePerEnergy As Currency
On Error GoTo error:
bNothingToSim = True: x = 0
Do While x <= 4 And bNothingToSim
If m_nAtkMin(x) > 0 Then bNothingToSim = False
If m_nAtkMax(x) > 0 Then bNothingToSim = False
If m_nAtkHitSpellMin(x) > 0 Then bNothingToSim = False
If m_nAtkHitSpellMax(x) > 0 Then bNothingToSim = False
If m_nBetweenRoundMin(x) > 0 Then bNothingToSim = False
If m_nBetweenRoundMax(x) > 0 Then bNothingToSim = False
x = x + 1
Loop
If bNothingToSim Then GoTo out:
'determin lowest cost attack and highest cost attack
For nAttack = 0 To 4
If m_nAtkType(nAttack) > 0 And m_nAtkEnergy(nAttack) > 0 Then
nLowEnergy = m_nAtkEnergy(nAttack)
If m_nAtkType(nAttack) = 2 Then 'spell
If ((m_nAtkResist(nAttack) = 1 And m_nUserAntiMagic = 1) Or m_nAtkResist(nAttack) = 2) _
Or m_nAtkSuccess(nAttack) < 100 Then 'resistable or failable
nLowEnergy = Round(m_nAtkEnergy(nAttack) / 2)
End If
End If
If (nLowestCostAttack = 0 Or nLowEnergy < nLowestCostAttack) And nLowEnergy > 0 Then
nLowestCostAttack = nLowEnergy
End If
If nMaxCostAttack = 0 Or m_nAtkEnergy(nAttack) > nMaxCostAttack Then
nMaxCostAttack = m_nAtkEnergy(nAttack)
End If
ElseIf m_nAtkType(nAttack) > 0 And m_nAtkEnergy(nAttack) = 0 And m_nAtkChance(nAttack) > 0 Then
nLowestCostAttack = 0
nMaxEnergyRound = m_nEnergyPerRound * 2
GoTo zero_energy_attack_skip_calc:
End If
Next nAttack
If nLowestCostAttack = 0 Then GoTo out:
'determine max energy / round
nMaxEnergyRound = m_nEnergyPerRound
nLeastEnergyUsed = nLowestCostAttack
Do While (nLeastEnergyUsed + nMaxCostAttack) <= nMaxEnergyRound
nLeastEnergyUsed = nLeastEnergyUsed + nLowestCostAttack
Loop
nEnergyRemaining = (m_nEnergyPerRound - nLeastEnergyUsed)
If nEnergyRemaining < nLowestCostAttack Then nEnergyRemaining = nEnergyRemaining + (nLowestCostAttack - 1)
nMaxEnergyRound = m_nEnergyPerRound + nEnergyRemaining
zero_energy_attack_skip_calc:
'determine max damage from regular attacks
nEnergyRemaining = nMaxEnergyRound
x = 1
Do While nEnergyRemaining >= nLowestCostAttack And x <= 6
nDamage = 0: nMaxDamage = 0: nEnergyForAttack = 0: nMaxDPE = 0
For nAttack = 0 To 4
If m_nAtkEnergy(nAttack) <= nEnergyRemaining And m_nAtkEnergy(nAttack) > 0 Then
If (m_nAtkType(nAttack) <> 2 Or m_nAtkSuccess(nAttack) > 0) And m_nAtkType(nAttack) > 0 Then
nDamage = m_nAtkMax(nAttack)
If m_nAtkType(nAttack) = 1 Then
If Not m_nAtkDuration(nAttack) > 1 Then
nDamage = nDamage + m_nAtkHitSpellMax(nAttack)
End If
End If
nMaxAttempts = Fix(nEnergyRemaining / m_nAtkEnergy(nAttack))
If nMaxAttempts > (6 - x + 1) Then nMaxAttempts = (6 - x + 1)
nDamagePerEnergy = (nDamage * nMaxAttempts) / nEnergyRemaining
If nDamagePerEnergy > nMaxDPE Then
nMaxDamage = nDamage
nMaxDPE = nDamagePerEnergy
nEnergyForAttack = m_nAtkEnergy(nAttack)
End If
End If
End If
Next nAttack
GetMaxDamage = GetMaxDamage + nMaxDamage
nEnergyRemaining = nEnergyRemaining - nEnergyForAttack
x = x + 1
Loop
'add spell/hitspell duration ticks
For nAttack = 0 To 4
If m_nAtkType(nAttack) = 1 And m_nAtkDuration(nAttack) > 1 Then
GetMaxDamage = GetMaxDamage + m_nAtkHitSpellMax(nAttack)
If m_nAtkDuration(nAttack) > 2 Then GetMaxDamage = GetMaxDamage + m_nAtkHitSpellMax(nAttack)
ElseIf m_nAtkType(nAttack) = 2 And m_nAtkDuration(nAttack) > 1 Then
GetMaxDamage = GetMaxDamage + m_nAtkMax(nAttack)
If m_nAtkDuration(nAttack) > 2 Then GetMaxDamage = GetMaxDamage + m_nAtkMax(nAttack)
End If
Next nAttack
'between rounds
nMaxDamage = 0
For x = 0 To 4
If m_nBetweenRoundChance(x) > 0 And Not m_nBetweenRoundDuration(x) > 1 Then
nDamage = m_nBetweenRoundMax(x)
If nDamage > nMaxDamage Then nMaxDamage = nDamage
End If
Next x
GetMaxDamage = GetMaxDamage + nMaxDamage
'add between round duration ticks
For x = 0 To 4
If m_nBetweenRoundChance(x) > 0 And m_nBetweenRoundDuration(x) > 1 Then
GetMaxDamage = GetMaxDamage + m_nBetweenRoundMax(x)
If m_nBetweenRoundDuration(x) > 2 Then GetMaxDamage = GetMaxDamage + m_nBetweenRoundMax(x)
End If
Next x
out:
On Error Resume Next
Exit Function
error:
Call HandleError("GetMaxDamage")
Resume out:
End Function
Public Sub RunSim()
Dim nRound As Long, nAttempt As Integer, nAttack As Integer, x As Integer
Dim nRemainingEnergy As Long, nEnergyUsed As Integer, bShowHitSpell As Boolean
Dim nDR_DamageResisted As Currency, nMR_Reduction As Currency
Dim bAttackHit As Boolean, bDodged As Boolean, bGlanced As Boolean, bResisted As Boolean
Dim nLastAttackType As Integer, nLastAttackEnergy As Integer, nAttack_AdjSuccessChance As Currency
Dim nRoll_AttackChance As Integer, nRoll_HitChance As Integer, nRoll_DodgeChance As Integer
Dim nDamage As Currency, nHitSpellDamage As Currency, nRoundDamage As Long, nOriginalDamage As Currency
Dim bSepShown As Boolean, bDurSpellApplied As Boolean, bNothingToSim As Boolean
Dim nCurrentAverageDamage As Currency, nDifference As Currency, nDynamicRoundCount As Long
Dim sMaxRoundCombatLog As String, sHitSpellName As String
On Error GoTo error:
Randomize
If m_bDynamicCalc Then m_nNumberOfRounds = 100000
If m_nNumberOfRounds < 1 Then Exit Sub
If m_nEnergyPerRound < 1 Then Exit Sub
m_nTotalAttacks = 0
m_nTotalDamage = 0
m_nMaxRoundDamage = 0
m_nMaxEnergyPerRound = 0
Call ResetActiveSpells
bNothingToSim = True: x = 0
Do While x <= 4 And bNothingToSim
If m_nAtkMin(x) > 0 Then bNothingToSim = False
If m_nAtkMax(x) > 0 Then bNothingToSim = False
If m_nAtkHitSpellMin(x) > 0 Then bNothingToSim = False
If m_nAtkHitSpellMax(x) > 0 Then bNothingToSim = False
If m_nBetweenRoundMin(x) > 0 Then bNothingToSim = False
If m_nBetweenRoundMax(x) > 0 Then bNothingToSim = False
x = x + 1
Loop
If bNothingToSim Then GoTo end_sim:
Call ProgressBarSetRange(m_nNumberOfRounds)
m_sCombatLog = "=================================================================="
nCombatLogRoundCount = 0
If m_nCombatLogMaxRounds < 0 Then m_nCombatLogMaxRounds = 0
nRemainingEnergy = 0
For nRound = 1 To m_nNumberOfRounds
nRoundDamage = 0
bSepShown = False
'============================================================================
' CHECK FOR EXTRA SPELL ROUND TICKS
' (SPELL ROUND = 3s, COMBAT ROUND 5s ... EVERY 3 ROUNDS = EXTRA SPELL ROUND)
'============================================================================
For x = 0 To 4
'============================================================================
' regular attack spell duration and hit spell duration
'============================================================================
If nActiveAtkSpells_DurationLeft(x) > 0 Then
If nActiveAtkSpells_Ticks(x) = 3 Then '15 seconds has based, second tick goes off
nRoundDamage = nRoundDamage + nActiveAtkSpells_Value(x)
m_nTotalDamage = m_nTotalDamage + nActiveAtkSpells_Value(x)
m_nStatAtkTotalDamage(x) = m_nStatAtkTotalDamage(x) + nActiveAtkSpells_Value(x)
m_nStatAtkDmgResisted(x) = m_nStatAtkDmgResisted(x) + (nActiveAtkSpells_ValueOriginal(x) - nActiveAtkSpells_Value(x))
If Not bSepShown Then
Call AddToCombatLog("")
bSepShown = True
End If
nActiveAtkSpells_DurationLeft(x) = nActiveAtkSpells_DurationLeft(x) - 1
If m_nAtkType(x) = 2 Then 'spell
Call AddToCombatLog("[" & m_sAtkName(x) & ", spell tick] for " & nActiveAtkSpells_Value(x) _
& " -- " & nActiveAtkSpells_DurationLeft(x) & " rounds rem.")
Else
sHitSpellName = IIf(Len(m_sAtkHitSpellName(x)) = 0, "attack " & (x + 1), m_sAtkHitSpellName(x))
Call AddToCombatLog("[" & sHitSpellName & ", hit spell tick] for " & nActiveAtkSpells_Value(x) _
& " -- " & nActiveAtkSpells_DurationLeft(x) & " rounds rem.")
End If
If nActiveAtkSpells_DurationLeft(x) < 1 Then Call ResetActiveAtkSpell(x)
End If
End If
'============================================================================
' between round spell durations
'============================================================================
If nActiveBetweenSpells_DurationLeft(x) > 0 Then
If nActiveBetweenSpells_Ticks(x) = 3 Then '15 seconds has based, second tick goes off
nRoundDamage = nRoundDamage + nActiveBetweenSpells_Value(x)
m_nTotalDamage = m_nTotalDamage + nActiveBetweenSpells_Value(x)
If Not bSepShown Then
Call AddToCombatLog("")
bSepShown = True
End If
nActiveBetweenSpells_DurationLeft(x) = nActiveBetweenSpells_DurationLeft(x) - 1
Call AddToCombatLog("[" & m_sBetweenRoundName(x) & ", between spell tick] for " & nActiveBetweenSpells_Value(x) _
& " -- " & nActiveBetweenSpells_DurationLeft(x) & " rounds rem.")
If nActiveBetweenSpells_DurationLeft(x) < 1 Then Call ResetActiveBetweenSpell(x)
End If
End If
Next x
If bSepShown Then
Call AddToCombatLog("")
bSepShown = False
End If
If m_bHideEnergyInfo Then
Call AddToCombatLog("ROUND " & nRound)
Else
Call AddToCombatLog("ROUND " & nRound & " / Energy: " _
& nRemainingEnergy & " + " & m_nEnergyPerRound & " = " & (nRemainingEnergy + m_nEnergyPerRound))
End If
Call AddToCombatLog("")
nRemainingEnergy = nRemainingEnergy + m_nEnergyPerRound
If nRemainingEnergy > m_nMaxEnergyPerRound Then m_nMaxEnergyPerRound = nRemainingEnergy
'============================================================================
' BEGIN REGULAR ATTACK ATTEMPTS
'============================================================================
For nAttempt = 1 To 6
nRoll_AttackChance = Me.RandomNumber(1, 100)
nLastAttackType = 0
nLastAttackEnergy = 0
For nAttack = 0 To 4
nDamage = 0: nHitSpellDamage = 0: nOriginalDamage = 0: nMR_Reduction = 0
bShowHitSpell = False: bDurSpellApplied = False
If nRoll_AttackChance <= m_nAtkChance(nAttack) And m_nAtkType(nAttack) > 0 Then
nLastAttackEnergy = m_nAtkEnergy(nAttack)
nLastAttackType = m_nAtkType(nAttack)
If nRemainingEnergy < m_nAtkEnergy(nAttack) Then
'no energy for attack
Else
m_nStatAtkAttempted(nAttack) = m_nStatAtkAttempted(nAttack) + 1
m_nTotalAttacks = m_nTotalAttacks + 1
bAttackHit = False: bDodged = False: bGlanced = False: bResisted = False
' CHANCE TO HIT / CAST
nAttack_AdjSuccessChance = m_nAtkSuccess(nAttack)
If m_nAtkType(nAttack) <> 2 Then 'not spell
If m_nUserAC > 0 Then
'=((AC*AC)/100)/((ACCY*ACCY)/140)=fail %
nAttack_AdjSuccessChance = Round(1 - (((m_nUserAC * m_nUserAC) / 100) / ((nAttack_AdjSuccessChance * nAttack_AdjSuccessChance) / 140)), 2) * 100
Else
nAttack_AdjSuccessChance = 99
End If
'PHYSICAL ATTACKS = 9% MIN HIT CHANCE, 99% MAX
If nAttack_AdjSuccessChance < 9 Then nAttack_AdjSuccessChance = 9
If nAttack_AdjSuccessChance > 99 Then nAttack_AdjSuccessChance = 99
End If
nRoll_HitChance = Me.RandomNumber(1, 100)
If nRoll_HitChance <= nAttack_AdjSuccessChance Then
bAttackHit = True
If m_nAtkType(nAttack) <> 2 And m_nUserDodge > 0 Then
nRoll_DodgeChance = Me.RandomNumber(1, 100)
If nRoll_DodgeChance <= m_nUserDodge Then
bAttackHit = False: bDodged = True
m_nStatAtkAttemptDodgedOrResisted(nAttack) = m_nStatAtkAttemptDodgedOrResisted(nAttack) + 1
End If
End If
End If
If bAttackHit Then
nDamage = Me.RandomNumber(m_nAtkMin(nAttack), m_nAtkMax(nAttack))
nOriginalDamage = nDamage
'============================================================================
' SPELL ATTACK ?
'============================================================================
If m_nAtkType(nAttack) = 2 Then 'spell
nActiveAtkSpells_ValueOriginal(nAttack) = nDamage
If m_nAtkMRdmgResist(nAttack) = 1 And nDamage > 0 Then
nMR_Reduction = Round(CalcResistedDamage(nDamage, m_nUserMR, m_nUserAntiMagic))
'If m_nAtkDuration(nAttack) = 0 Then
' m_nStatAtkDmgResisted(nAttack) = m_nStatAtkDmgResisted(nAttack) + (nDamage - nMR_Reduction)
'End If
nDamage = nMR_Reduction
End If
If m_nAtkDuration(nAttack) > 0 Then
If nActiveAtkSpells_DurationLeft(nAttack) < 1 Or nActiveAtkSpells_Value(nAttack) <> nDamage Then
If IsSpellResisted(m_nAtkResist(nAttack), m_nUserMR, m_nUserAntiMagic) Then
m_nStatAtkAttemptDodgedOrResisted(nAttack) = m_nStatAtkAttemptDodgedOrResisted(nAttack) + 1
bResisted = True
bAttackHit = False
nDamage = 0
Else
Call ResetActiveAtkSpell(nAttack)
nActiveAtkSpells_DurationLeft(nAttack) = m_nAtkDuration(nAttack)
nActiveAtkSpells_Value(nAttack) = nDamage
bDurSpellApplied = True
nDamage = 0
End If
Else
'DURATION CONTINUES, NOT REALLY AN ATTEMPT
m_nStatAtkAttempted(nAttack) = m_nStatAtkAttempted(nAttack) - 1
m_nTotalAttacks = m_nTotalAttacks - 1
GoTo choose_next_attack:
End If
Else
If IsSpellResisted(m_nAtkResist(nAttack), m_nUserMR, m_nUserAntiMagic) Then
m_nStatAtkAttemptDodgedOrResisted(nAttack) = m_nStatAtkAttemptDodgedOrResisted(nAttack) + 1
'm_nStatAtkDmgResisted(nAttack) = m_nStatAtkDmgResisted(nAttack) + nDamage
bResisted = True
bAttackHit = False
nDamage = 0
End If
End If
'============================================================================
' NORMAL ATTACK
'============================================================================
Else
'normal/rob
nDR_DamageResisted = m_nUserDR '(m_nUserDR / 2)
If nDR_DamageResisted > nDamage Then nDR_DamageResisted = nDamage
m_nStatAtkDmgResisted(nAttack) = m_nStatAtkDmgResisted(nAttack) + nDR_DamageResisted
nDamage = nDamage - nDR_DamageResisted
'============================================================================
' HIT SPELL APPLICATION CHECK
'============================================================================
If m_nAtkHitSpellMin(nAttack) > 0 Or m_nAtkHitSpellMax(nAttack) > 0 Or m_nAtkDuration(nAttack) > 0 Then
nHitSpellDamage = Round(Me.RandomNumber(m_nAtkHitSpellMin(nAttack), m_nAtkHitSpellMax(nAttack)))
nActiveAtkSpells_ValueOriginal(nAttack) = nHitSpellDamage
If m_nAtkMRdmgResist(nAttack) = 1 And nHitSpellDamage > 0 Then
nMR_Reduction = Round(CalcResistedDamage(nHitSpellDamage, m_nUserMR, m_nUserAntiMagic))
If m_nAtkDuration(nAttack) = 0 Then
m_nStatAtkDmgResisted(nAttack) = m_nStatAtkDmgResisted(nAttack) + (nHitSpellDamage - nMR_Reduction)
End If
nHitSpellDamage = nMR_Reduction
End If
If m_nAtkDuration(nAttack) > 0 Then
If nActiveAtkSpells_DurationLeft(nAttack) < 1 Or nActiveAtkSpells_Value(nAttack) <> nHitSpellDamage Then
If IsSpellResisted(m_nAtkResist(nAttack), m_nUserMR, m_nUserAntiMagic) Then
m_nStatAtkDmgResisted(nAttack) = m_nStatAtkDmgResisted(nAttack) + nHitSpellDamage
bShowHitSpell = True
bResisted = True
nHitSpellDamage = 0
Else
Call ResetActiveAtkSpell(nAttack)
nActiveAtkSpells_DurationLeft(nAttack) = m_nAtkDuration(nAttack)
nActiveAtkSpells_Value(nAttack) = nHitSpellDamage
bDurSpellApplied = True
bShowHitSpell = True
nHitSpellDamage = 0
End If
End If
Else
If IsSpellResisted(m_nAtkResist(nAttack), m_nUserMR, m_nUserAntiMagic) Then
m_nStatAtkDmgResisted(nAttack) = m_nStatAtkDmgResisted(nAttack) + nHitSpellDamage
bResisted = True
nHitSpellDamage = 0
End If
bShowHitSpell = True
End If
If Not bShowHitSpell Then nHitSpellDamage = 0
End If
End If
If nDamage <= 0 Then
If m_nAtkType(nAttack) <> 2 Then bGlanced = True
nDamage = 0
End If
If bAttackHit Then
If nOriginalDamage <> nDamage And m_nAtkType(nAttack) = 2 And m_nAtkDuration(nAttack) < 1 Then 'spell
m_nStatAtkDmgResisted(nAttack) = m_nStatAtkDmgResisted(nAttack) + (nOriginalDamage - nDamage)
End If
nRoundDamage = nRoundDamage + nDamage + nHitSpellDamage
m_nTotalDamage = m_nTotalDamage + nDamage + nHitSpellDamage
nRemainingEnergy = nRemainingEnergy - m_nAtkEnergy(nAttack)
m_nStatAtkHits(nAttack) = m_nStatAtkHits(nAttack) + 1
m_nStatAtkTotalDamage(nAttack) = m_nStatAtkTotalDamage(nAttack) + nDamage + nHitSpellDamage
If m_nAtkType(nAttack) = 2 And m_nAtkDuration(nAttack) > 0 Then 'duration spell
Call AddToCombatLog(m_sAtkName(nAttack) & " applied (" & nActiveAtkSpells_ValueOriginal(nAttack) & ")", _
"Energy used: " & m_nAtkEnergy(nAttack) & " ... Remaining: " & nRemainingEnergy)
Else
Call AddToCombatLog(m_sAtkName(nAttack) & " for " & Round(nDamage) _
& IIf(bGlanced, " (GLANCE)", ""), _
"Energy used: " & m_nAtkEnergy(nAttack) & " ... Remaining: " & nRemainingEnergy)
End If
If bShowHitSpell Then
If bDurSpellApplied Then
Call AddToCombatLog(" - duration spell applied (" & nActiveAtkSpells_Value(nAttack) & ")")
Else
sHitSpellName = IIf(Len(m_sAtkHitSpellName(nAttack)) = 0, "attack " & (x + 1), m_sAtkHitSpellName(nAttack))
Call AddToCombatLog(" -" & sHitSpellName & " " & IIf(bResisted, "(resist)", "for " & Round(nHitSpellDamage)))
End If
End If
End If
End If
If Not bAttackHit Then
If m_nAtkType(nAttack) = 2 Then 'spell
'If m_nAtkDuration(nAttack) = 0 Or nActiveAtkSpells_DurationLeft(nAttack) < 1 Then
'If m_nAtkDuration(nAttack) = 0 Or bResisted Then
If m_nAtkDuration(nAttack) = 0 Or bResisted Then
nEnergyUsed = Round(m_nAtkEnergy(nAttack) / 2, 0)
nRemainingEnergy = nRemainingEnergy - nEnergyUsed
Call AddToCombatLog(m_sAtkName(nAttack) & " (" _
& IIf(bResisted, "RESIST", "FAIL") & ")", _
"Energy used: " & nEnergyUsed & " ... Remaining: " & nRemainingEnergy)
End If
Else
nRemainingEnergy = nRemainingEnergy - m_nAtkEnergy(nAttack)
Call AddToCombatLog(m_sAtkName(nAttack) & " (" _
& IIf(bDodged, "DODGE", "MISS") & ")", _
"Energy used: " & m_nAtkEnergy(nAttack) & " ... Remaining: " & nRemainingEnergy)
End If
End If
End If
GoTo next_attempt:
End If
choose_next_attack:
Next nAttack
next_attempt:
If nLastAttackType = 1 Then 'spell
If nRemainingEnergy < nLastAttackEnergy Then GoTo next_round:
End If
Next nAttempt
next_round:
'============================================================================
' BETWEEN ROUND SPELL CAST
'============================================================================
bSepShown = False
nRoll_AttackChance = Me.RandomNumber(1, 100)
For x = 0 To 4
bAttackHit = False: bResisted = False: bDurSpellApplied = False
If m_nBetweenRoundChance(x) > 0 Then
If nRoll_AttackChance <= m_nBetweenRoundChance(x) Then
nDamage = Me.RandomNumber(m_nBetweenRoundMin(x), m_nBetweenRoundMax(x))
nActiveBetweenSpells_ValueOriginal(x) = nDamage
If m_nBetweenRoundResistDmgMR(x) = 1 And nDamage > 0 Then
nMR_Reduction = Round(CalcResistedDamage(nDamage, m_nUserMR, m_nUserAntiMagic))
nDamage = nMR_Reduction
End If
If m_nBetweenRoundDuration(x) > 0 Then
If nActiveBetweenSpells_DurationLeft(x) < 1 Or nActiveBetweenSpells_Value(x) <> nDamage Then
If IsSpellResisted(m_nBetweenRoundResistType(x), m_nUserMR, m_nUserAntiMagic) Then
bResisted = True
nDamage = 0
Else
Call ResetActiveBetweenSpell(x)
nActiveBetweenSpells_DurationLeft(x) = m_nBetweenRoundDuration(x)
nActiveBetweenSpells_Value(x) = nDamage
bDurSpellApplied = True
nDamage = 0
End If
End If
Else
If IsSpellResisted(m_nBetweenRoundResistType(x), m_nUserMR, m_nUserAntiMagic) Then
bResisted = True
nDamage = 0
Else
bAttackHit = True
End If
End If
End If
End If
If Not bSepShown And (bDurSpellApplied Or bResisted Or bAttackHit) Then
Call AddToCombatLog("")
bSepShown = True
End If
If bDurSpellApplied Then
Call AddToCombatLog("[between round] " & m_sBetweenRoundName(x) & " - duration spell applied (" & nActiveBetweenSpells_Value(x) & ")")
GoTo duration_ticks:
ElseIf bResisted Then
Call AddToCombatLog("[between round] " & m_sBetweenRoundName(x) & " (RESIST)")
GoTo duration_ticks:
ElseIf bAttackHit Then
Call AddToCombatLog("[between round] " & m_sBetweenRoundName(x) & " for " & Round(nDamage))
nRoundDamage = nRoundDamage + nDamage
m_nTotalDamage = m_nTotalDamage + nDamage
GoTo duration_ticks:
End If
Next x
duration_ticks:
'============================================================================
' ALL SPELL DURATION TICKS
'============================================================================
bSepShown = False
For x = 0 To 4
If nActiveAtkSpells_DurationLeft(x) > 0 Then
nRoundDamage = nRoundDamage + nActiveAtkSpells_Value(x)
m_nTotalDamage = m_nTotalDamage + nActiveAtkSpells_Value(x)
m_nStatAtkTotalDamage(x) = m_nStatAtkTotalDamage(x) + nActiveAtkSpells_Value(x)
m_nStatAtkDmgResisted(x) = m_nStatAtkDmgResisted(x) + (nActiveAtkSpells_ValueOriginal(x) - nActiveAtkSpells_Value(x))
If Not bSepShown Then
Call AddToCombatLog("")
bSepShown = True
End If
nActiveAtkSpells_DurationLeft(x) = nActiveAtkSpells_DurationLeft(x) - 1
If m_nAtkType(x) = 2 Then 'spell
Call AddToCombatLog("[" & m_sAtkName(x) & ", attack spell tick] for " & nActiveAtkSpells_Value(x) _
& " -- " & nActiveAtkSpells_DurationLeft(x) & " rounds rem.")
Else
sHitSpellName = IIf(Len(m_sAtkHitSpellName(x)) = 0, "attack " & (x + 1), m_sAtkHitSpellName(x))
Call AddToCombatLog("[" & sHitSpellName & ", hit spell tick] for " & nActiveAtkSpells_Value(x) _
& " -- " & nActiveAtkSpells_DurationLeft(x) & " rounds rem.")
End If
If nActiveAtkSpells_Ticks(x) >= 3 Then
nActiveAtkSpells_Ticks(x) = 1
Else
nActiveAtkSpells_Ticks(x) = nActiveAtkSpells_Ticks(x) + 1
End If
If nActiveAtkSpells_DurationLeft(x) < 1 Then Call ResetActiveAtkSpell(x)
End If
If nActiveBetweenSpells_DurationLeft(x) > 0 Then
nRoundDamage = nRoundDamage + nActiveBetweenSpells_Value(x)
m_nTotalDamage = m_nTotalDamage + nActiveBetweenSpells_Value(x)
If Not bSepShown Then
Call AddToCombatLog("")
bSepShown = True
End If
nActiveBetweenSpells_DurationLeft(x) = nActiveBetweenSpells_DurationLeft(x) - 1
Call AddToCombatLog("[" & m_sBetweenRoundName(x) & ", between spell tick] for " & nActiveBetweenSpells_Value(x) _
& " -- " & nActiveBetweenSpells_DurationLeft(x) & " rounds rem.")
If nActiveBetweenSpells_Ticks(x) >= 3 Then
nActiveBetweenSpells_Ticks(x) = 1
Else
nActiveBetweenSpells_Ticks(x) = nActiveBetweenSpells_Ticks(x) + 1
End If
If nActiveBetweenSpells_DurationLeft(x) < 1 Then Call ResetActiveBetweenSpell(x)
End If
Next x
Call AddToCombatLog("")
Call AddToCombatLog("Damage for round: " & nRoundDamage, "Energy Remaining: " & nRemainingEnergy)
Call AddToCombatLog("==================================================================")
nCombatLogRoundCount = nCombatLogRoundCount + 1
If nRoundDamage > m_nMaxRoundDamage Then
m_nMaxRoundDamage = nRoundDamage
If m_bCombatLogMaxRoundOnly Then sMaxRoundCombatLog = m_sCombatLog
ElseIf m_bCombatLogMaxRoundOnly Then
m_sCombatLog = ""
nCombatLogRoundCount = 0
End If
If nDynamicRoundCount > 1000 And m_bDynamicCalc Then
If nCurrentAverageDamage = 0 Then
nCurrentAverageDamage = Round(m_nTotalDamage / nRound, 3)
If nCurrentAverageDamage < 1 Then
m_nNumberOfRounds = nRound
GoTo end_sim:
End If
nDynamicRoundCount = 0
Else
nDifference = Abs(1 - (Round(m_nTotalDamage / nRound, 3) / nCurrentAverageDamage))
If nDifference < nDynamicCalcDifference Then
m_nNumberOfRounds = nRound
GoTo end_sim:
Else
nCurrentAverageDamage = Round(m_nTotalDamage / nRound, 3)
nDynamicRoundCount = 0
End If
End If
End If
nDynamicRoundCount = nDynamicRoundCount + 1
Call ProgressBarIncrease
If Not m_bUseCPU Then DoEvents
Next nRound
end_sim:
If nRound > 0 Then
m_nAverageDamage = Round(m_nTotalDamage / nRound, 1)
End If
If m_bCombatLogMaxRoundOnly Then m_sCombatLog = sMaxRoundCombatLog
out:
On Error Resume Next
Exit Sub
error:
Call privHandleError("RunSim")
Resume out:
End Sub
Private Sub ResetActiveAtkSpell(ByVal nAttack As Integer)
On Error GoTo error:
nActiveAtkSpells_DurationLeft(nAttack) = 0
nActiveAtkSpells_Ticks(nAttack) = 0
nActiveAtkSpells_Value(nAttack) = 0
out:
On Error Resume Next
Exit Sub
error:
Call HandleError("ResetActiveAtkSpell")
Resume out:
End Sub
Private Sub ResetActiveBetweenSpell(ByVal nAttack As Integer)
On Error GoTo error:
nActiveBetweenSpells_DurationLeft(nAttack) = 0
nActiveBetweenSpells_Ticks(nAttack) = 0
nActiveBetweenSpells_Value(nAttack) = 0
out:
On Error Resume Next
Exit Sub
error:
Call HandleError("ResetActiveBetweenSpell")
Resume out:
End Sub
Public Function IsSpellResisted(ByVal nAttackResistType As Integer, ByVal nMR As Integer, ByVal nAntiMagic As Integer) As Boolean
Dim nRoll_ResistChance As Integer
On Error GoTo error:
IsSpellResisted = False
If (nAttackResistType = 1 And nAntiMagic = 1) Or nAttackResistType = 2 Then
'if( TYPEofRESIST=Never , 0 , IF( ANTI_MAGIC=Yes or TYPEofRESIST=Yes , IF( MR>196 , 0.98 , MR/200 ) , 0 ) )
nRoll_ResistChance = Me.RandomNumber(1, 100)
If nMR > 196 Then nMR = 196
If nRoll_ResistChance <= nMR / 2 Then
IsSpellResisted = True
End If
End If
out:
On Error Resume Next
Exit Function
error:
Call privHandleError("IsSpellResisted")
Resume out:
End Function
Public Function CalcResistedDamage(ByVal nDamage As Currency, ByVal nMR As Integer, ByVal nAntiMagic As Integer) As Currency
Dim nPercentReduction As Currency
On Error GoTo error:
If nMR > 150 Then nMR = 150
If nAntiMagic = 0 Then
'DAMAGE = DAMAGE - ( DAMAGE * IF( MR<50, (MR-50)/100, IF( MR>150, 0.5, (MR-50)/200 ) ) )
If nMR < 50 Then