1 /*
2  *  PowerTables.c
3  *  Brogue
4  *
5  *  Created by Brian Walker on 4/9/17.
6  *  Copyright 2017. All rights reserved.
7  *
8  *  This file is part of Brogue.
9  *
10  *  This program is free software: you can redistribute it and/or modify
11  *  it under the terms of the GNU Affero General Public License as
12  *  published by the Free Software Foundation, either version 3 of the
13  *  License, or (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU Affero General Public License for more details.
19  *
20  *  You should have received a copy of the GNU Affero General Public License
21  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 #include "Rogue.h"
25 
26 #define LAST_INDEX(a) (sizeof(a) / sizeof(fixpt) - 1)
27 
28 // As of v1.7.5, Brogue does not use floating-point math in any calculations
29 // that have an effect on substantive gameplay. The two operations that were
30 // annoying to convert were sqrt() (handled by an open source fixed point sqrt
31 // implementation in Sqrt.c) and especially pow(). I could not find a fixed point
32 // pow implementation that was good enough for the wide range of fractional bases
33 // and exponents. Fortunately, all uses of pow() involved a fixed base and an exponent
34 // that varied by increments of at least 0.25 (or really 0.1 for armor calculations but
35 // I fudged that), or a fixed exponent and base that varied similarly. The one exception
36 // were runic weapon activation chances, which modified the base by the damage of the weapon
37 // and varied the exponent by the level, but I moved the damage modification into the exponent
38 // without much affecting the results. So now pow() has been replaced by lookup tables.
39 // Hopefully this will help with out of sync errors for saved games and recordings...
40 
41 // game data formulae:
42 
wandDominate(creature * monst)43 short wandDominate(creature *monst)                 {return (((monst)->currentHP * 5 < (monst)->info.maxHP) ? 100 : \
44                                                      max(0, 100 * ((monst)->info.maxHP - (monst)->currentHP) / (monst)->info.maxHP));}
45 
46 // All "enchant" parameters must already be multiplied by FP_FACTOR:
staffDamageLow(fixpt enchant)47 short staffDamageLow(fixpt enchant)            {return ((int) ((2 + enchant / FP_FACTOR) * 3 / 4));}
staffDamageHigh(fixpt enchant)48 short staffDamageHigh(fixpt enchant)           {return ((int) (4 + (5 * enchant / FP_FACTOR / 2)));}
staffDamage(fixpt enchant)49 short staffDamage(fixpt enchant)               {return ((int) randClumpedRange(staffDamageLow(enchant), staffDamageHigh(enchant), 1 + (enchant) / 3 / FP_FACTOR));}
staffBlinkDistance(fixpt enchant)50 short staffBlinkDistance(fixpt enchant)        {return ((int) (2 + enchant * 2 / FP_FACTOR));}
staffHasteDuration(fixpt enchant)51 short staffHasteDuration(fixpt enchant)        {return ((int) (2 + enchant * 4 / FP_FACTOR));}
staffBladeCount(fixpt enchant)52 short staffBladeCount(fixpt enchant)           {return ((int) (enchant * 3 / 2 / FP_FACTOR));}
staffDiscordDuration(fixpt enchant)53 short staffDiscordDuration(fixpt enchant)      {return ((int) (enchant * 4 / FP_FACTOR));}
staffEntrancementDuration(fixpt enchant)54 short staffEntrancementDuration(fixpt enchant) {return ((int) (enchant * 3 / FP_FACTOR));}
staffProtection(fixpt enchant)55 int staffProtection(fixpt enchant) {
56     return 130 * fp_pow(FP_FACTOR * 140 / 100, enchant / FP_FACTOR - 2) / FP_FACTOR;
57 }
staffPoison(fixpt enchant)58 int staffPoison(fixpt enchant) {
59     const fixpt POW_POISON[] = {
60         // 1.3^x fixed point, with x from 0 to 50 in increments of 1:
61         65536, 85196, 110755, 143982, 187177, 243330, 316329, 411228, 534597, 694976, 903469, 1174510, 1526863, 1984922, 2580398, 3354518, 4360874, 5669136, 7369877,
62         9580840, 12455093, 16191620, 21049107, 27363839, 35572991, 46244888, 60118355, 78153861, 101600020, 132080026, 171704034, 223215244, 290179818, 377233763,
63         490403892, 637525060, 828782579, 1077417352, 1400642558, 1820835326, 2367085924, 3077211701, 4000375211, 5200487775, 6760634107, 8788824340, 11425471642,
64         14853113134, 19309047075, 25101761197, 32632289557};
65 
66     short idx = clamp(enchant / FP_FACTOR - 2, 0, LAST_INDEX(POW_POISON));
67     return 5 * POW_POISON[idx] / FP_FACTOR;
68 }
69 
ringWisdomMultiplier(fixpt enchant)70 fixpt ringWisdomMultiplier(fixpt enchant) {
71     const fixpt POW_WISDOM[] = {
72         // 1.3^x fixed point, with x from -10 to 30 in increments of 1:
73         4753, 6180, 8034, 10444, 13577, 17650, 22945, 29829, 38778, 50412, 65536, 85196, 110755, 143982, 187177, 243330, 316329, 411228, 534597, 694976, 903469,
74         1174510, 1526863, 1984922, 2580398, 3354518, 4360874, 5669136, 7369877, 9580840, 12455093, 16191620, 21049107, 27363839, 35572991, 46244888, 60118355,
75         78153861, 101600020, 132080026, 171704034};
76 
77     short idx = clamp(min(27, enchant / FP_FACTOR) + 10, 0, LAST_INDEX(POW_WISDOM));
78     return POW_WISDOM[idx];
79 }
80 
charmHealing(fixpt enchant)81 short charmHealing(fixpt enchant)              {return ((int) clamp(20 * (enchant) / FP_FACTOR, 0, 100));}
charmShattering(fixpt enchant)82 short charmShattering(fixpt enchant)           {return ((int) (4 + (enchant / FP_FACTOR)));}
charmGuardianLifespan(fixpt enchant)83 short charmGuardianLifespan(fixpt enchant)     {return ((int) (4 + 2 * (enchant / FP_FACTOR)));}
charmNegationRadius(fixpt enchant)84 short charmNegationRadius(fixpt enchant)       {return ((int) (1 + 3 * (enchant / FP_FACTOR)));}
charmProtection(fixpt enchant)85 int charmProtection(fixpt enchant) {
86     const fixpt POW_CHARM_PROTECTION[] = {
87         // 1.35^x fixed point, with x from 0 to 50 in increments of 1:
88         65536, 88473, 119439, 161243, 217678, 293865, 396718, 535570, 723019, 976076, 1317703, 1778899, 2401514, 3242044, 4376759, 5908625, 7976644, 10768469,
89         14537434, 19625536, 26494473, 35767539, 48286178, 65186341, 88001560, 118802106, 160382844, 216516839, 292297733, 394601940, 532712620, 719162037, 970868750,
90         1310672812, 1769408297, 2388701201, 3224746621, 4353407939, 5877100717, 7934085969, 10711016058, 14459871678, 19520826766, 26353116134, 35576706781,
91         48028554155, 64838548109, 87532039948, 118168253930, 159527142806, 215361642788};
92 
93     short idx = clamp(enchant / FP_FACTOR - 1, 0, LAST_INDEX(POW_CHARM_PROTECTION));
94     return 150 * POW_CHARM_PROTECTION[idx] / FP_FACTOR;
95 }
96 
weaponParalysisDuration(fixpt enchant)97 short weaponParalysisDuration(fixpt enchant)   {return (max(2, (int) (2 + ((enchant) / 2 / FP_FACTOR))));}
weaponConfusionDuration(fixpt enchant)98 short weaponConfusionDuration(fixpt enchant)   {return (max(3, (int) ((enchant) * 3/2 / FP_FACTOR)));}
weaponForceDistance(fixpt enchant)99 short weaponForceDistance(fixpt enchant)       {return (max(4, (int) (((enchant) * 2 / FP_FACTOR) + 2)));} // Depends on definition of staffBlinkDistance() above.
weaponSlowDuration(fixpt enchant)100 short weaponSlowDuration(fixpt enchant)        {return (max(3, (int) ((((enchant) / FP_FACTOR) + 2) * ((enchant) + (2 * FP_FACTOR))) / 3 / FP_FACTOR));}
weaponImageCount(fixpt enchant)101 short weaponImageCount(fixpt enchant)          {return (clamp((int) ((enchant) / 3 / FP_FACTOR), 1, 7));}
weaponImageDuration(fixpt enchant)102 short weaponImageDuration(fixpt enchant)       {return 3;}
103 
armorReprisalPercent(fixpt enchant)104 short armorReprisalPercent(fixpt enchant)      {return (max(5, (int) ((enchant) * 5 / FP_FACTOR)));}
armorAbsorptionMax(fixpt enchant)105 short armorAbsorptionMax(fixpt enchant)        {return (max(1, (int) ((enchant) / FP_FACTOR)));}
armorImageCount(fixpt enchant)106 short armorImageCount(fixpt enchant)           {return (clamp((int) ((enchant) / 3 / FP_FACTOR), 1, 5));}
reflectionChance(fixpt enchant)107 short reflectionChance(fixpt enchant) {
108     const fixpt POW_REFLECT[] = {
109         // 0.85^x fixed point, with x from 0.25 to 50 in increments of 0.25:
110         62926, 60421, 58015, 55705, 53487, 51358, 49313, 47349, 45464, 43654, 41916, 40247, 38644, 37106, 35628, 34210, 32848, 31540, 30284, 29078, 27920,
111         26809, 25741, 24716, 23732, 22787, 21880, 21009, 20172, 19369, 18598, 17857, 17146, 16464, 15808, 15179, 14574, 13994, 13437, 12902, 12388, 11895, 11421,
112         10967, 10530, 10111, 9708, 9321, 8950, 8594, 8252, 7923, 7608, 7305, 7014, 6735, 6466, 6209, 5962, 5724, 5496, 5278, 5067, 4866, 4672, 4486, 4307, 4136,
113         3971, 3813, 3661, 3515, 3375, 3241, 3112, 2988, 2869, 2755, 2645, 2540, 2439, 2341, 2248, 2159, 2073, 1990, 1911, 1835, 1762, 1692, 1624, 1559, 1497, 1438,
114         1380, 1325, 1273, 1222, 1173, 1127, 1082, 1039, 997, 958, 919, 883, 848, 814, 781, 750, 720, 692, 664, 638, 612, 588, 564, 542, 520, 500, 480, 461, 442,
115         425, 408, 391, 376, 361, 346, 333, 319, 307, 294, 283, 271, 261, 250, 240, 231, 221, 213, 204, 196, 188, 181, 173, 166, 160, 153, 147, 141, 136, 130, 125,
116         120, 115, 111, 106, 102, 98, 94, 90, 87, 83, 80, 77, 74, 71, 68, 65, 62, 60, 58, 55, 53, 51, 49, 47, 45, 43, 41, 40, 38, 37, 35, 34, 32, 31, 30, 29, 27,
117         26, 25, 24, 23, 22, 21, 21, 20, 19};
118 
119     short idx = clamp(enchant * 4 / FP_FACTOR - 1, 0, LAST_INDEX(POW_REFLECT));
120     return clamp(100 - (100 * POW_REFLECT[idx] / FP_FACTOR), 1, 100);
121 }
122 
turnsForFullRegenInThousandths(fixpt bonus)123 long turnsForFullRegenInThousandths(fixpt bonus) {
124     const fixpt POW_REGEN[] = {
125         // 0.75^x fixed point, with x from -10 to 50 in increments of 1:
126         1163770, 872827, 654620, 490965, 368224, 276168, 207126, 155344, 116508, 87381, 65536, 49152, 36864, 27648, 20736, 15552, 11664, 8748, 6561, 4920, 3690,
127         2767, 2075, 1556, 1167, 875, 656, 492, 369, 277, 207, 155, 116, 87, 65, 49, 36, 27, 20, 15, 11, 8, 6, 4, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
128 
129     // This will max out at full regeneration in about two turns.
130     // This is the Syd nerf, after Syd broke the game over his knee with a +18 ring of regeneration.
131     short idx = clamp(bonus / FP_FACTOR + 10, 0, LAST_INDEX(POW_REGEN));
132     return (1000 * TURNS_FOR_FULL_REGEN * POW_REGEN[idx] / FP_FACTOR) + 2000;
133 }
134 
135 
damageFraction(fixpt netEnchant)136 fixpt damageFraction(fixpt netEnchant) {
137     const fixpt POW_DAMAGE_FRACTION[] = {
138         // 1.065^x fixed point, with x representing a change in 0.25 weapon enchantment points, ranging from -20 to 50.
139         18598, 18894, 19193, 19498, 19807, 20122, 20441, 20765, 21095, 21430, 21770, 22115, 22466, 22823, 23185, 23553, 23926, 24306, 24692, 25084, 25482, 25886,
140         26297, 26714, 27138, 27569, 28006, 28451, 28902, 29361, 29827, 30300, 30781, 31269, 31765, 32269, 32781, 33302, 33830, 34367, 34912, 35466, 36029, 36601,
141         37182, 37772, 38371, 38980, 39598, 40227, 40865, 41514, 42172, 42842, 43521, 44212, 44914, 45626, 46350, 47086, 47833, 48592, 49363, 50146, 50942, 51751,
142         52572, 53406, 54253, 55114, 55989, 56877, 57780, 58697, 59628, 60574, 61536, 62512, 63504, 64512, 65536, 66575, 67632, 68705, 69795, 70903, 72028, 73171,
143         74332, 75512, 76710, 77927, 79164, 80420, 81696, 82992, 84309, 85647, 87006, 88387, 89789, 91214, 92662, 94132, 95626, 97143, 98685, 100251, 101842, 103458,
144         105099, 106767, 108461, 110182, 111931, 113707, 115511, 117344, 119206, 121098, 123020, 124972, 126955, 128969, 131016, 133095, 135207, 137352, 139532,
145         141746, 143995, 146280, 148602, 150960, 153355, 155789, 158261, 160772, 163323, 165915, 168548, 171222, 173939, 176699, 179503, 182352, 185245, 188185,
146         191171, 194205, 197286, 200417, 203597, 206828, 210110, 213444, 216831, 220272, 223767, 227318, 230925, 234589, 238312, 242094, 245935, 249838, 253802,
147         257830, 261921, 266077, 270300, 274589, 278946, 283372, 287869, 292437, 297078, 301792, 306581, 311445, 316388, 321408, 326508, 331689, 336953, 342300,
148         347731, 353249, 358855, 364549, 370334, 376211, 382180, 388245, 394406, 400664, 407022, 413481, 420042, 426707, 433479, 440357, 447345, 454443, 461655,
149         468980, 476422, 483982, 491662, 499464, 507390, 515441, 523620, 531929, 540370, 548945, 557656, 566505, 575494, 584626, 593903, 603328, 612901, 622627,
150         632507, 642544, 652740, 663098, 673620, 684309, 695168, 706199, 717406, 728790, 740354, 752102, 764037, 776161, 788477, 800989, 813699, 826611, 839728,
151         853053, 866590, 880341, 894311, 908502, 922918, 937563, 952441, 967555, 982908, 998505, 1014350, 1030446, 1046797, 1063408, 1080282, 1097425, 1114839,
152         1132529, 1150501, 1168757, 1187303, 1206144, 1225283, 1244726, 1264478, 1284543, 1304927, 1325634, 1346669, 1368039, 1389747, 1411800, 1434203, 1456961,
153         1480081, 1503567, 1527426};
154 
155     short idx = clamp(netEnchant * 4 / FP_FACTOR + 80, 0, LAST_INDEX(POW_DAMAGE_FRACTION));
156     return POW_DAMAGE_FRACTION[idx];
157 }
158 
accuracyFraction(fixpt netEnchant)159 fixpt accuracyFraction(fixpt netEnchant) {
160     const fixpt POW_ACCURACY_FRACTION[] = {
161         // 1.065^x fixed point, with x representing a change in 0.25 weapon enchantment points (as displayed), ranging from -20 to 50.
162         18598, 18894, 19193, 19498, 19807, 20122, 20441, 20765, 21095, 21430, 21770, 22115, 22466, 22823, 23185, 23553, 23926, 24306, 24692, 25084, 25482, 25886,
163         26297, 26714, 27138, 27569, 28006, 28451, 28902, 29361, 29827, 30300, 30781, 31269, 31765, 32269, 32781, 33302, 33830, 34367, 34912, 35466, 36029, 36601,
164         37182, 37772, 38371, 38980, 39598, 40227, 40865, 41514, 42172, 42842, 43521, 44212, 44914, 45626, 46350, 47086, 47833, 48592, 49363, 50146, 50942, 51751,
165         52572, 53406, 54253, 55114, 55989, 56877, 57780, 58697, 59628, 60574, 61536, 62512, 63504, 64512, 65536, 66575, 67632, 68705, 69795, 70903, 72028, 73171,
166         74332, 75512, 76710, 77927, 79164, 80420, 81696, 82992, 84309, 85647, 87006, 88387, 89789, 91214, 92662, 94132, 95626, 97143, 98685, 100251, 101842, 103458,
167         105099, 106767, 108461, 110182, 111931, 113707, 115511, 117344, 119206, 121098, 123020, 124972, 126955, 128969, 131016, 133095, 135207, 137352, 139532,
168         141746, 143995, 146280, 148602, 150960, 153355, 155789, 158261, 160772, 163323, 165915, 168548, 171222, 173939, 176699, 179503, 182352, 185245, 188185,
169         191171, 194205, 197286, 200417, 203597, 206828, 210110, 213444, 216831, 220272, 223767, 227318, 230925, 234589, 238312, 242094, 245935, 249838, 253802,
170         257830, 261921, 266077, 270300, 274589, 278946, 283372, 287869, 292437, 297078, 301792, 306581, 311445, 316388, 321408, 326508, 331689, 336953, 342300,
171         347731, 353249, 358855, 364549, 370334, 376211, 382180, 388245, 394406, 400664, 407022, 413481, 420042, 426707, 433479, 440357, 447345, 454443, 461655,
172         468980, 476422, 483982, 491662, 499464, 507390, 515441, 523620, 531929, 540370, 548945, 557656, 566505, 575494, 584626, 593903, 603328, 612901, 622627,
173         632507, 642544, 652740, 663098, 673620, 684309, 695168, 706199, 717406, 728790, 740354, 752102, 764037, 776161, 788477, 800989, 813699, 826611, 839728,
174         853053, 866590, 880341, 894311, 908502, 922918, 937563, 952441, 967555, 982908, 998505, 1014350, 1030446, 1046797, 1063408, 1080282, 1097425, 1114839,
175         1132529, 1150501, 1168757, 1187303, 1206144, 1225283, 1244726, 1264478, 1284543, 1304927, 1325634, 1346669, 1368039, 1389747, 1411800, 1434203, 1456961,
176         1480081, 1503567, 1527426};
177 
178     short idx = clamp(netEnchant * 4 / FP_FACTOR + 80, 0, LAST_INDEX(POW_ACCURACY_FRACTION));
179     return POW_ACCURACY_FRACTION[idx];
180 }
181 
defenseFraction(fixpt netDefense)182 fixpt defenseFraction(fixpt netDefense) {
183     const fixpt POW_DEFENSE_FRACTION[] = {
184         // 0.877347265^x fixed point, with x representing a change in 0.25 armor points (as displayed), ranging from -20 to 50.
185         897530, 868644, 840688, 813632, 787446, 762103, 737575, 713837, 690863, 668629, 647110, 626283, 606127, 586619, 567740, 549468,
186         531784, 514669, 498105, 482074, 466559, 451543, 437011, 422946, 409334, 396160, 383410, 371071, 359128, 347570, 336384, 325558,
187         315080, 304940, 295125, 285627, 276435, 267538, 258927, 250594, 242529, 234724, 227169, 219858, 212782, 205934, 199306, 192892,
188         186684, 180676, 174861, 169233, 163786, 158515, 153414, 148476, 143698, 139073, 134597, 130265, 126073, 122015, 118088, 114288,
189         110609, 107050, 103604, 100270, 97043, 93920, 90897, 87971, 85140, 82400, 79748, 77181, 74697, 72293, 69967, 67715, 65536, 63426,
190         61385, 59409, 57497, 55647, 53856, 52123, 50445, 48822, 47250, 45730, 44258, 42833, 41455, 40121, 38829, 37580, 36370, 35200, 34067,
191         32970, 31909, 30882, 29888, 28926, 27995, 27094, 26222, 25378, 24562, 23771, 23006, 22266, 21549, 20855, 20184, 19535, 18906, 18297,
192         17709, 17139, 16587, 16053, 15536, 15036, 14552, 14084, 13631, 13192, 12768, 12357, 11959, 11574, 11201, 10841, 10492, 10154, 9828,
193         9511, 9205, 8909, 8622, 8345, 8076, 7816, 7565, 7321, 7085, 6857, 6637, 6423, 6216, 6016, 5823, 5635, 5454, 5278, 5108, 4944, 4785,
194         4631, 4482, 4337, 4198, 4063, 3932, 3805, 3683, 3564, 3450, 3339, 3231, 3127, 3026, 2929, 2835, 2744, 2655, 2570, 2487, 2407, 2329,
195         2255, 2182, 2112, 2044, 1978, 1914, 1853, 1793, 1735, 1679, 1625, 1573, 1522, 1473, 1426, 1380, 1336, 1293, 1251, 1211, 1172, 1134,
196         1097, 1062, 1028, 995, 963, 932, 902, 873, 845, 817, 791, 766, 741, 717, 694, 672, 650, 629, 609, 589, 570, 552, 534, 517, 500, 484,
197         469, 453, 439, 425, 411, 398, 385, 373, 361, 349, 338, 327, 316, 306, 296, 287, 277, 268, 260, 251, 243, 235, 228, 221, 213, 207,
198         200, 193, 187, 181, 175, 170, 164, 159, 154, 149, 144, 139, 135, 130, 126, 122, 118, 114, 111, 107, 104, 100, 97, 94};
199 
200     short idx = clamp(netDefense * 4 / 10 / FP_FACTOR + 80, 0, LAST_INDEX(POW_DEFENSE_FRACTION));
201     return POW_DEFENSE_FRACTION[idx];
202 }
203 
charmEffectDuration(short charmKind,short enchant)204 short charmEffectDuration(short charmKind, short enchant) {
205     const fixpt POW_0_CHARM_INCREMENT[] = { // 1.0
206         65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536,
207         65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536,
208         65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536, 65536};
209     const fixpt POW_120_CHARM_INCREMENT[] = { // 1.20^x fixed point, with x from 1 to 50 in increments of 1:
210         78643, 94371, 113246, 135895, 163074, 195689, 234827, 281792, 338151, 405781, 486937, 584325, 701190, 841428, 1009714, 1211657,
211         1453988, 1744786, 2093744, 2512492, 3014991, 3617989, 4341587, 5209905, 6251886, 7502263, 9002716, 10803259, 12963911, 15556694,
212         18668032, 22401639, 26881967, 32258360, 38710033, 46452039, 55742447, 66890937, 80269124, 96322949, 115587539, 138705047, 166446056,
213         199735268, 239682321, 287618785, 345142543, 414171051, 497005262, 596406314, 715687577};
214     const fixpt POW_125_CHARM_INCREMENT[] = { // 1.25^x fixed point, with x from 1 to 50 in increments of 1:
215         81920, 102400, 128000, 160000, 200000, 250000, 312500, 390625, 488281, 610351, 762939, 953674, 1192092, 1490116, 1862645, 2328306,
216         2910383, 3637978, 4547473, 5684341, 7105427, 8881784, 11102230, 13877787, 17347234, 21684043, 27105054, 33881317, 42351647, 52939559,
217         66174449, 82718061, 103397576, 129246970, 161558713, 201948391, 252435489, 315544362, 394430452, 493038065, 616297582, 770371977,
218         962964972, 1203706215, 1504632769, 1880790961, 2350988701, 2938735877, 3673419846, 4591774807, 5739718509};
219     const short duration[NUMBER_CHARM_KINDS] = {
220         3,  // Health
221         20, // Protection
222         7,  // Haste
223         10, // Fire immunity
224         5,  // Invisibility
225         25, // Telepathy
226         10, // Levitation
227         0,  // Shattering
228         18, // Guardian
229         0,  // Teleportation
230         0,  // Recharging
231         0,  // Negation
232     };
233     const fixpt *increment[NUMBER_CHARM_KINDS] = {
234         POW_0_CHARM_INCREMENT,      // Health
235         POW_0_CHARM_INCREMENT,      // Protection
236         POW_120_CHARM_INCREMENT,    // Haste
237         POW_125_CHARM_INCREMENT,    // Fire immunity
238         POW_120_CHARM_INCREMENT,    // Invisibility
239         POW_125_CHARM_INCREMENT,    // Telepathy
240         POW_125_CHARM_INCREMENT,    // Levitation
241         POW_0_CHARM_INCREMENT,      // Shattering
242         POW_0_CHARM_INCREMENT,      // Guardian
243         POW_0_CHARM_INCREMENT,      // Teleportation
244         POW_0_CHARM_INCREMENT,      // Recharging
245         POW_0_CHARM_INCREMENT,      // Negation
246     };
247 
248     short idx = clamp(enchant - 1, 0, LAST_INDEX(POW_125_CHARM_INCREMENT));
249     return duration[charmKind] * increment[charmKind][idx] / FP_FACTOR;
250 }
251 
charmRechargeDelay(short charmKind,short enchant)252 short charmRechargeDelay(short charmKind, short enchant) {
253     const short duration[NUMBER_CHARM_KINDS] = {
254         2500,   // Health
255         1000,   // Protection
256         800,    // Haste
257         800,    // Fire immunity
258         800,    // Invisibility
259         800,    // Telepathy
260         800,    // Levitation
261         2500,   // Shattering
262         700,    // Guardian
263         920,    // Teleportation
264         10000,  // Recharging
265         2500,   // Negation
266     };
267     const fixpt base[NUMBER_CHARM_KINDS] = {
268         FP_FACTOR * 55 / 100, // Health
269         FP_FACTOR * 60 / 100, // Protection
270         FP_FACTOR * 65 / 100, // Haste
271         FP_FACTOR * 60 / 100, // Fire immunity
272         FP_FACTOR * 65 / 100, // Invisibility
273         FP_FACTOR * 65 / 100, // Telepathy
274         FP_FACTOR * 65 / 100, // Levitation
275         FP_FACTOR * 60 / 100, // Shattering
276         FP_FACTOR * 70 / 100, // Guardian
277         FP_FACTOR * 60 / 100, // Teleportation
278         FP_FACTOR * 55 / 100, // Recharging
279         FP_FACTOR * 60 / 100, // Negation
280     };
281 
282     enchant = clamp(enchant, 1, 50);
283     short delay = charmEffectDuration(charmKind, enchant)
284         + (duration[charmKind] * fp_pow(base[charmKind], enchant) / FP_FACTOR);
285     return max(1, delay);
286 }
287 
runicWeaponChance(item * theItem,boolean customEnchantLevel,fixpt enchantLevel)288 short runicWeaponChance(item *theItem, boolean customEnchantLevel, fixpt enchantLevel) {
289     const fixpt POW_16_RUNIC_DECREMENT[] = { // (1-0.16)^x fixed point, with x from 0 to 50 in increments of 0.25:
290         65536, 62740, 60064, 57502, 55050, 52702, 50454, 48302, 46242, 44269, 42381, 40574, 38843, 37186, 35600, 34082, 32628, 31236, 29904,
291         28629, 27407, 26238, 25119, 24048, 23022, 22040, 21100, 20200, 19339, 18514, 17724, 16968, 16244, 15551, 14888, 14253, 13645, 13063,
292         12506, 11972, 11462, 10973, 10505, 10057, 9628, 9217, 8824, 8448, 8087, 7742, 7412, 7096, 6793, 6503, 6226, 5961, 5706, 5463, 5230,
293         5007, 4793, 4589, 4393, 4206, 4026, 3854, 3690, 3533, 3382, 3238, 3100, 2967, 2841, 2720, 2604, 2492, 2386, 2284, 2187, 2094, 2004,
294         1919, 1837, 1759, 1684, 1612, 1543, 1477, 1414, 1354, 1296, 1241, 1188, 1137, 1089, 1042, 998, 955, 914, 875, 838, 802, 768, 735,
295         704, 674, 645, 617, 591, 566, 542, 519, 496, 475, 455, 436, 417, 399, 382, 366, 350, 335, 321, 307, 294, 281, 269, 258, 247, 236,
296         226, 217, 207, 198, 190, 182, 174, 167, 159, 153, 146, 140, 134, 128, 123, 117, 112, 108, 103, 99, 94, 90, 86, 83, 79, 76, 73, 69,
297         66, 64, 61, 58, 56, 53, 51, 49, 47, 45, 43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 18, 17, 16,
298         15, 15, 14, 13, 13, 12, 12, 11, 11, 10};
299     const fixpt POW_15_RUNIC_DECREMENT[] = { // (1-0.15)^x fixed point, with x from 0 to 50 in increments of 0.25:
300         65536, 62926, 60421, 58015, 55705, 53487, 51358, 49313, 47349, 45464, 43654, 41916, 40247, 38644, 37106, 35628, 34210, 32848, 31540,
301         30284, 29078, 27920, 26809, 25741, 24716, 23732, 22787, 21880, 21009, 20172, 19369, 18598, 17857, 17146, 16464, 15808, 15179, 14574,
302         13994, 13437, 12902, 12388, 11895, 11421, 10967, 10530, 10111, 9708, 9321, 8950, 8594, 8252, 7923, 7608, 7305, 7014, 6735, 6466, 6209,
303         5962, 5724, 5496, 5278, 5067, 4866, 4672, 4486, 4307, 4136, 3971, 3813, 3661, 3515, 3375, 3241, 3112, 2988, 2869, 2755, 2645, 2540,
304         2439, 2341, 2248, 2159, 2073, 1990, 1911, 1835, 1762, 1692, 1624, 1559, 1497, 1438, 1380, 1325, 1273, 1222, 1173, 1127, 1082, 1039,
305         997, 958, 919, 883, 848, 814, 781, 750, 720, 692, 664, 638, 612, 588, 564, 542, 520, 500, 480, 461, 442, 425, 408, 391, 376, 361, 346,
306         333, 319, 307, 294, 283, 271, 261, 250, 240, 231, 221, 213, 204, 196, 188, 181, 173, 166, 160, 153, 147, 141, 136, 130, 125, 120, 115,
307         111, 106, 102, 98, 94, 90, 87, 83, 80, 77, 74, 71, 68, 65, 62, 60, 58, 55, 53, 51, 49, 47, 45, 43, 41, 40, 38, 37, 35, 34, 32, 31, 30,
308         29, 27, 26, 25, 24, 23, 22, 21, 21, 20, 19};
309     const fixpt POW_14_RUNIC_DECREMENT[] = { // (1-0.14)^x fixed point, with x from 0 to 50 in increments of 0.25:
310         65536, 63110, 60775, 58526, 56360, 54275, 52267, 50332, 48470, 46676, 44949, 43286, 41684, 40142, 38656, 37226, 35848, 34522, 33244,
311         32014, 30829, 29689, 28590, 27532, 26513, 25532, 24587, 23677, 22801, 21958, 21145, 20363, 19609, 18883, 18185, 17512, 16864, 16240,
312         15639, 15060, 14503, 13966, 13449, 12952, 12472, 12011, 11566, 11138, 10726, 10329, 9947, 9579, 9224, 8883, 8554, 8238, 7933, 7639,
313         7357, 7084, 6822, 6570, 6327, 6092, 5867, 5650, 5441, 5239, 5046, 4859, 4679, 4506, 4339, 4179, 4024, 3875, 3732, 3593, 3460, 3332,
314         3209, 3090, 2976, 2866, 2760, 2658, 2559, 2465, 2373, 2285, 2201, 2119, 2041, 1965, 1893, 1823, 1755, 1690, 1628, 1567, 1509, 1454,
315         1400, 1348, 1298, 1250, 1204, 1159, 1116, 1075, 1035, 997, 960, 924, 890, 857, 825, 795, 765, 737, 710, 684, 658, 634, 610, 588, 566,
316         545, 525, 505, 487, 469, 451, 435, 418, 403, 388, 374, 360, 346, 334, 321, 309, 298, 287, 276, 266, 256, 247, 237, 229, 220, 212, 204,
317         197, 189, 182, 176, 169, 163, 157, 151, 145, 140, 135, 130, 125, 120, 116, 111, 107, 103, 99, 96, 92, 89, 85, 82, 79, 76, 73, 71, 68,
318         66, 63, 61, 58, 56, 54, 52, 50, 48, 47, 45, 43, 42, 40, 38, 37, 36, 34};
319     const fixpt POW_11_RUNIC_DECREMENT[] = { // (1-0.11)^x fixed point, with x from 0 to 50 in increments of 0.25:
320         65536, 63654, 61826, 60051, 58327, 56652, 55025, 53445, 51911, 50420, 48972, 47566, 46200, 44874, 43585, 42334, 41118, 39938, 38791,
321         37677, 36595, 35544, 34524, 33533, 32570, 31634, 30726, 29844, 28987, 28155, 27346, 26561, 25798, 25058, 24338, 23639, 22960, 22301,
322         21661, 21039, 20435, 19848, 19278, 18725, 18187, 17665, 17157, 16665, 16186, 15721, 15270, 14832, 14406, 13992, 13590, 13200, 12821,
323         12453, 12095, 11748, 11411, 11083, 10765, 10456, 10155, 9864, 9581, 9305, 9038, 8779, 8527, 8282, 8044, 7813, 7589, 7371, 7159, 6954,
324         6754, 6560, 6372, 6189, 6011, 5838, 5671, 5508, 5350, 5196, 5047, 4902, 4761, 4624, 4492, 4363, 4237, 4116, 3997, 3883, 3771, 3663,
325         3558, 3456, 3356, 3260, 3166, 3075, 2987, 2901, 2818, 2737, 2658, 2582, 2508, 2436, 2366, 2298, 2232, 2168, 2106, 2045, 1986, 1929,
326         1874, 1820, 1768, 1717, 1668, 1620, 1573, 1528, 1484, 1442, 1400, 1360, 1321, 1283, 1246, 1210, 1176, 1142, 1109, 1077, 1046, 1016,
327         987, 959, 931, 904, 878, 853, 829, 805, 782, 759, 737, 716, 696, 676, 656, 637, 619, 601, 584, 567, 551, 535, 520, 505, 490, 476, 462,
328         449, 436, 424, 412, 400, 388, 377, 366, 356, 345, 336, 326, 317, 307, 299, 290, 282, 274, 266, 258, 251, 243, 236, 230, 223, 217, 210,
329         204, 198, 193};
330     const fixpt POW_7_RUNIC_DECREMENT[] = { // (1-0.07)^x fixed point, with x from 0 to 50 in increments of 0.25:
331         65536, 64357, 63200, 62064, 60948, 59852, 58776, 57719, 56682, 55662, 54662, 53679, 52714, 51766, 50835, 49921, 49024, 48142, 47277,
332         46427, 45592, 44772, 43967, 43177, 42401, 41638, 40890, 40155, 39433, 38724, 38027, 37344, 36672, 36013, 35365, 34730, 34105, 33492,
333         32890, 32298, 31718, 31147, 30587, 30038, 29497, 28967, 28446, 27935, 27433, 26939, 26455, 25979, 25512, 25054, 24603, 24161, 23726,
334         23300, 22881, 22470, 22066, 21669, 21279, 20897, 20521, 20152, 19790, 19434, 19084, 18741, 18404, 18073, 17748, 17429, 17116, 16808,
335         16506, 16209, 15918, 15632, 15351, 15075, 14804, 14537, 14276, 14019, 13767, 13520, 13277, 13038, 12804, 12573, 12347, 12125, 11907,
336         11693, 11483, 11276, 11074, 10875, 10679, 10487, 10299, 10113, 9931, 9753, 9578, 9405, 9236, 9070, 8907, 8747, 8590, 8435, 8284, 8135,
337         7988, 7845, 7704, 7565, 7429, 7296, 7164, 7036, 6909, 6785, 6663, 6543, 6425, 6310, 6196, 6085, 5976, 5868, 5763, 5659, 5557, 5457,
338         5359, 5263, 5168, 5075, 4984, 4894, 4806, 4720, 4635, 4552, 4470, 4390, 4311, 4233, 4157, 4082, 4009, 3937, 3866, 3796, 3728, 3661,
339         3595, 3531, 3467, 3405, 3344, 3283, 3224, 3166, 3110, 3054, 2999, 2945, 2892, 2840, 2789, 2739, 2689, 2641, 2594, 2547, 2501, 2456,
340         2412, 2369, 2326, 2284, 2243, 2203, 2163, 2124, 2086, 2048, 2012, 1975, 1940, 1905, 1871, 1837, 1804, 1772, 1740};
341     const fixpt POW_6_RUNIC_DECREMENT[] = { // (1-0.06)^x fixed point, with x from 0 to 50 in increments of 0.25:
342         65536, 64530, 63539, 62564, 61603, 60658, 59727, 58810, 57907, 57018, 56143, 55281, 54433, 53597, 52774, 51964, 51167, 50381, 49608,
343         48846, 48097, 47358, 46631, 45916, 45211, 44517, 43833, 43161, 42498, 41846, 41203, 40571, 39948, 39335, 38731, 38137, 37551, 36975,
344         36407, 35848, 35298, 34756, 34223, 33698, 33180, 32671, 32169, 31676, 31189, 30711, 30239, 29775, 29318, 28868, 28425, 27989, 27559,
345         27136, 26719, 26309, 25905, 25508, 25116, 24731, 24351, 23977, 23609, 23247, 22890, 22539, 22193, 21852, 21516, 21186, 20861, 20541,
346         20225, 19915, 19609, 19308, 19012, 18720, 18433, 18150, 17871, 17597, 17327, 17061, 16799, 16541, 16287, 16037, 15791, 15549, 15310,
347         15075, 14843, 14616, 14391, 14170, 13953, 13739, 13528, 13320, 13116, 12914, 12716, 12521, 12329, 12139, 11953, 11770, 11589, 11411,
348         11236, 11063, 10894, 10726, 10562, 10400, 10240, 10083, 9928, 9776, 9625, 9478, 9332, 9189, 9048, 8909, 8772, 8638, 8505, 8374, 8246,
349         8119, 7995, 7872, 7751, 7632, 7515, 7400, 7286, 7174, 7064, 6956, 6849, 6744, 6640, 6538, 6438, 6339, 6242, 6146, 6052, 5959, 5867,
350         5777, 5688, 5601, 5515, 5430, 5347, 5265, 5184, 5105, 5026, 4949, 4873, 4798, 4725, 4652, 4581, 4510, 4441, 4373, 4306, 4240, 4175,
351         4111, 4047, 3985, 3924, 3864, 3805, 3746, 3689, 3632, 3576, 3521, 3467, 3414, 3362, 3310, 3259, 3209, 3160, 3111, 3064, 3017, 2970};
352     const fixpt *effectChances[NUMBER_WEAPON_RUNIC_KINDS] = {
353         POW_16_RUNIC_DECREMENT, // W_SPEED
354         POW_6_RUNIC_DECREMENT,  // W_QUIETUS
355         POW_7_RUNIC_DECREMENT,  // W_PARALYSIS
356         POW_15_RUNIC_DECREMENT, // W_MULTIPLICITY
357         POW_14_RUNIC_DECREMENT, // W_SLOWING
358         POW_11_RUNIC_DECREMENT, // W_CONFUSION
359         POW_15_RUNIC_DECREMENT, // W_FORCE
360         0,      // W_SLAYING
361         0,      // W_MERCY
362         0};     // W_PLENTY
363 
364     fixpt modifier;
365     short runicType = theItem->enchant2;
366     short chance, adjustedBaseDamage, tableIndex;
367 
368     if (runicType == W_SLAYING) {
369         return 0;
370     }
371     if (runicType >= NUMBER_GOOD_WEAPON_ENCHANT_KINDS) { // bad runic
372         return 15;
373     }
374     if (!customEnchantLevel) {
375         enchantLevel = netEnchant(theItem);
376     }
377 
378     // Innately high-damage weapon types are less likely to trigger runic effects.
379     adjustedBaseDamage = (tableForItemCategory(theItem->category, NULL)[theItem->kind].range.lowerBound
380                           + tableForItemCategory(theItem->category, NULL)[theItem->kind].range.upperBound) / 2;
381 
382     if (theItem->flags & ITEM_ATTACKS_STAGGER) {
383         adjustedBaseDamage /= 2; // Normalize as though they attacked once per turn instead of every other turn.
384     }
385     //    if (theItem->flags & ITEM_ATTACKS_QUICKLY) {
386     //      adjustedBaseDamage *= 2; // Normalize as though they attacked once per turn instead of twice per turn.
387     //  } // Testing disabling this for balance reasons...
388 
389     modifier = FP_FACTOR - min((99 * FP_FACTOR)/100, (adjustedBaseDamage * FP_FACTOR) / 18);
390 
391     if (enchantLevel < 0) {
392         chance = 0;
393     } else {
394         tableIndex = enchantLevel * modifier * 4 / FP_FACTOR / FP_FACTOR;
395         tableIndex = clamp(tableIndex, 0, LAST_INDEX(POW_16_RUNIC_DECREMENT));
396         chance = 100 - (short) (100LL * effectChances[runicType][tableIndex] / FP_FACTOR); // good runic
397     }
398 
399     // Slow weapons get an adjusted chance of 1 - (1-p)^2 to reflect two bites at the apple instead of one.
400     if (theItem->flags & ITEM_ATTACKS_STAGGER) {
401         chance = 100 - (100 - chance) * (100 - chance) / 100;
402     }
403     // Fast weapons get an adjusted chance of 1 - sqrt(1-p) to reflect one bite at the apple instead of two.
404     if (theItem->flags & ITEM_ATTACKS_QUICKLY) {
405         chance = 100 * (FP_FACTOR - fp_sqrt(FP_FACTOR - (chance * FP_FACTOR)/100)) / FP_FACTOR;
406     }
407 
408     // The lowest percent change that a weapon will ever have is its enchantment level (if greater than 0).
409     // That is so that even really heavy weapons will improve at least 1% per enchantment.
410     chance = clamp(chance, max(1, (short) (enchantLevel / FP_FACTOR)), 100);
411 
412     return chance;
413 }
414