I have a Figther / Monk I created for the game and he's got both high strength and dexterity. I didn't cheat when I created my characters but I did roll to legally obtain excellency. Nobody should be penalized because a character has not been created following some subjective criteria. To have your own strong points be used against you is pretty diabolical. Much worse than a bug where a bonus is, for example, not counted or a penalty not applied.
I understand, and I'm not trying to defend the bug itself. My point is that the bug is there and will probably never be fixed given the nature of the bug. The question is what it means for the usefulness of the feat, and, in my opinion, it's still an extremely useful feat for the typical high strength, moderate dex character. As far as game engine bugs it does seem like one of the easier to fix. So maybe there's hope, but it's probably still incredibly difficult.
Yes, I fear it might take lots of effort and intimate knowledge of the engine. But we have talented people here in the Co8 team...
Question: is there any reason the attacker's DEX mod would be legitimately used for trip checks under any circumstances? e.g. using weapon finesse with a trip weapon or sthg. like that.
Not that I know of. With a trip weapon + weapon finesse you use your dex for the initial melee touch attack, but for the actual trip check the rules seem clear that it's always a strength check: Weapon finesse only affects attack rolls so it wouldn't apply here, and I can't think of anything else that would change it to a dex check. In ToEE I believe you always trip with your weapon no matter what, so the concept of trip weapon doesn't really exist.
I'm happy to inform you that your prayers have been answered My only concern is that perhaps something else was using the function as originally written for other purposes. Can you think of any scenario where the game would take the max of the attacker's DEX and Defender's STR? For those interested here are some of my IDA notes. The technique I've used is to enter combat, set up a break point at the Dice Roller function (located at 0x10038B60), work my way backwards, and then bash my head against the keyboard until it all starts to make sense Code: .text:100B6230 .text:100B6230 ; _______________ S U B R O U T I N E _______________________________________ .text:100B6230 .text:100B6230 .text:100B6230 Trip_Check proc near ; CODE XREF: sub_10095B00+4Cp .text:100B6230 ; sub_10095B00+12Ep .text:100B6230 .text:100B6230 Defender_Roll_Result= dword ptr -1188h .text:100B6230 Attacker_Roll_Result= dword ptr -1184h .text:100B6230 var_1180 = dword ptr -1180h .text:100B6230 Defender_DEX = dword ptr -117Ch .text:100B6230 Defender_STR = dword ptr -1178h .text:100B6230 Attacker_STR = dword ptr -1174h .text:100B6230 Defender_Mod = dword ptr -1170h .text:100B6230 var_DF8 = dword ptr -0DF8h .text:100B6230 var_A80 = dword ptr -0A80h .text:100B6230 var_700 = dword ptr -700h .text:100B6230 var_380 = dword ptr -380h .text:100B6230 Attacker_PTR = dword ptr 4 .text:100B6230 Attacker_PTR_Ext= dword ptr 8 .text:100B6230 Defender_PTR = dword ptr 0Ch .text:100B6230 Defender_PTR_Ext= dword ptr 10h .text:100B6230 .text:100B6230 mov eax, 1188h .text:100B6235 call __alloca_probe .text:100B623A push ebx .text:100B623B mov ebx, [esp+118Ch+Defender_PTR_Ext] .text:100B6242 push ebp .text:100B6243 mov ebp, [esp+1190h+Defender_PTR] .text:100B624A push 12Bh .text:100B624F push ebx .text:100B6250 push ebp .text:100B6251 call sub_1004CC00 .text:100B6256 add esp, 0Ch .text:100B6259 test eax, eax .text:100B625B jz short loc_100B628E .text:100B625D mov ecx, dword_10BCA848 .text:100B6263 lea eax, [esp+1190h+Attacker_Roll_Result] .text:100B6267 push eax ; void * .text:100B6268 push ecx ; int .text:100B6269 mov [esp+1198h+Attacker_Roll_Result], 0ABh ; '½' .text:100B6271 call sub_101E65E0 .text:100B6276 mov edx, [esp+1198h+var_1180] .text:100B627A push edx .text:100B627B call sub_100DFFC0 .text:100B6280 add esp, 0Ch .text:100B6283 pop ebp .text:100B6284 xor eax, eax .text:100B6286 pop ebx .text:100B6287 add esp, 1188h .text:100B628D retn .text:100B628E ; ___________________________________________________________________________ .text:100B628E .text:100B628E loc_100B628E: ; CODE XREF: Trip_Check+2Bj .text:100B628E push esi .text:100B628F lea eax, [esp+1194h+var_DF8] .text:100B6296 push edi .text:100B6297 push eax .text:100B6298 call sub_100E60D0 .text:100B629D lea ecx, [esp+119Ch+Defender_Mod] .text:100B62A1 push ecx .text:100B62A2 call sub_100E60D0 ; Some display related function? .text:100B62A2 ; For Trip Attempt it received a String input of "~Strength[TAG_STRENGTH] Bonus~" .text:100B62A7 push 0 ; bonus = 0 .text:100B62A9 push 14h ; die type = d20 .text:100B62AB push 1 ; die number = 1 .text:100B62AD call DiceRoller .text:100B62B2 push 0 .text:100B62B4 push 14h .text:100B62B6 push 1 .text:100B62B8 mov [esp+11B8h+Attacker_Roll_Result], eax .text:100B62BC call DiceRoller ; Returns result in EAX .text:100B62C1 lea edx, [esp+11B8h+var_A80] .text:100B62C8 push edx .text:100B62C9 mov [esp+11BCh+Defender_Roll_Result], eax ; var_1188 <- Defender's Roll .text:100B62CD call sub_1004DA50 ; EAX <- 18F044 .text:100B62D2 lea eax, [esp+11BCh+var_700] ; EAX <- &var_700 .text:100B62D9 push eax .text:100B62DA call sub_1004DA50 ; This modifies var_700 (&var_700 = 18F3C0) .text:100B62DA ; Also EAX <- 18F3C4 .text:100B62DF lea ecx, [esp+11C0h+var_380] ; ECX <- &var_380 .text:100B62E6 push ecx .text:100B62E7 call sub_1004DA50 ; This modifies var_380 .text:100B62E7 ; Also EAX <- 18F744 .text:100B62EC mov esi, [esp+11C4h+Attacker_PTR_Ext] .text:100B62F3 mov edi, [esp+11C4h+Attacker_PTR] .text:100B62FA lea edx, [esp+11C4h+var_A80] .text:100B6301 push edx .text:100B6302 push 0 .text:100B6304 push esi .text:100B6305 push edi .text:100B6306 call Stat_Level_Get ; EAX <- Attacker STR .text:100B630B mov [esp+11D4h+Attacker_STR], eax .text:100B630F lea eax, [esp+11D4h+var_700] .text:100B6316 push eax .text:100B6317 push 0 .text:100B6319 push ebx ; Defender pointer extension .text:100B631A push ebp ; Defender pointer .text:100B631B call Stat_Level_Get ; EAX <- Defender's Strength .text:100B6320 add esp, 4Ch .text:100B6323 lea ecx, [esp+1198h+var_380] ; ECX = &var_380 = 18F740 .text:100B632A push ecx .text:100B632B push 1 ; Parameter - Dexterity .text:100B632D push esi ; WAS: push esi .text:100B632D ; NEW: push ebx .text:100B632E push edi ; WAS: push edi .text:100B632E ; NEW: push ebp .text:100B632F mov [esp+11A8h+Defender_STR], eax .text:100B6333 call Stat_Level_Get ; EAX <- Attacker's Dexterity .text:100B6333 ; .text:100B6333 ; SHOULD BE: .text:100B6333 ; EAX <- Defender's Dexterity .text:100B6333 ; .text:100B6333 ; ECX = 18F740 which is var_380 and right .text:100B6333 ; before where the DEX value gets written .text:100B6338 mov edx, [esp+11A8h+Attacker_STR] .text:100B633C push edx .text:100B633D mov [esp+11ACh+Defender_DEX], eax .text:100B6341 call Get_Stat_Mod ; EAX <- Attacker STR Modifier .text:100B6346 push 67h ; 'g' .text:100B6348 push 0 .text:100B634A push eax .text:100B634B lea eax, [esp+11B8h+var_DF8] .text:100B6352 push eax .text:100B6353 call sub_100E6110 .text:100B6358 push 1 .text:100B635A lea ecx, [esp+11C0h+var_DF8] .text:100B6361 push ecx .text:100B6362 push 0 .text:100B6364 push ebx .text:100B6365 push ebp .text:100B6366 push esi .text:100B6367 push edi .text:100B6368 call sub_1004EF20 ; returns Attacker's overall bonus into EAX, EDX .text:100B6368 ; (including from Improved Trip feat! maybe size too?) .text:100B636D mov eax, [esp+11D8h+Defender_STR] .text:100B6371 mov ecx, [esp+11D8h+Defender_DEX] .text:100B6375 add esp, 40h .text:100B6378 cmp eax, ecx ; Compares STR vs. DEX .text:100B637A jl short loc_100B639C ; Jump if Defender_STR < Defender_DEX .text:100B637C push eax ; When STR is higher .text:100B637D call Get_Stat_Mod .text:100B6382 push 67h ; 'g' .text:100B6384 push 0 .text:100B6386 push eax .text:100B6387 lea edx, [esp+11A8h+Defender_Mod] .text:100B638B push edx .text:100B638C call sub_100E6110 .text:100B6391 push 3 .text:100B6393 lea eax, [esp+11B0h+Defender_Mod] .text:100B6397 push eax .text:100B6398 push 0 .text:100B639A jmp short loc_100B63BA .text:100B639C ; ___________________________________________________________________________ .text:100B639C .text:100B639C loc_100B639C: ; CODE XREF: Trip_Check+14Aj .text:100B639C push ecx ; When DEX is higher .text:100B639D call Get_Stat_Mod .text:100B63A2 push 68h ; 'h' .text:100B63A4 push 0 .text:100B63A6 push eax .text:100B63A7 lea ecx, [esp+11A8h+Defender_Mod] .text:100B63AB push ecx .text:100B63AC call sub_100E6110 .text:100B63B1 push 3 .text:100B63B3 lea edx, [esp+11B0h+Defender_Mod] .text:100B63B7 push edx .text:100B63B8 push 1 .text:100B63BA .text:100B63BA loc_100B63BA: ; CODE XREF: Trip_Check+16Aj .text:100B63BA push esi .text:100B63BB push edi .text:100B63BC push ebx .text:100B63BD push ebp .text:100B63BE call sub_1004EF20 ; Return overall trip defense bonus (including from Improved Trip) .text:100B63C3 add esp, 30h .text:100B63C6 push esi .text:100B63C7 push edi .text:100B63C8 call sub_1004D690 ; returned EAX = 5 .text:100B63CD add esp, 8 .text:100B63D0 sub eax, 5 .text:100B63D3 jz short loc_100B63F0 .text:100B63D5 push 13Ch .text:100B63DA push 0 .text:100B63DC shl eax, 2 .text:100B63DF push eax .text:100B63E0 lea ecx, [esp+11A4h+var_DF8] .text:100B63E7 push ecx .text:100B63E8 call sub_100E6110 .text:100B63ED add esp, 10h .text:100B63F0 .text:100B63F0 loc_100B63F0: ; CODE XREF: Trip_Check+1A3j .text:100B63F0 push ebx .text:100B63F1 push ebp .text:100B63F2 call sub_1004D690 .text:100B63F7 add esp, 8 .text:100B63FA sub eax, 5 .text:100B63FD jz short loc_100B641B .text:100B63FF push 13Ch .text:100B6404 lea edx, ds:0[eax*4] .text:100B640B push 0 .text:100B640D push edx .text:100B640E lea eax, [esp+11A4h+Defender_Mod] .text:100B6412 push eax .text:100B6413 call sub_100E6110 .text:100B6418 add esp, 10h .text:100B641B .text:100B641B loc_100B641B: ; CODE XREF: Trip_Check+1CDj .text:100B641B lea ecx, [esp+1198h+Defender_Mod] .text:100B641F push ecx .text:100B6420 call sub_100E65C0 .text:100B6425 mov ecx, [esp+119Ch+Defender_Roll_Result] .text:100B6429 lea edx, [esp+119Ch+var_DF8] .text:100B6430 mov ebp, eax .text:100B6432 push edx .text:100B6433 add ebp, ecx ; Defender Modifier + Defender Roll Result .text:100B6435 call sub_100E65C0 .text:100B643A mov ecx, [esp+11A0h+Attacker_Roll_Result] .text:100B643E add eax, ecx ; Attacker Modifier + Attack Roll Result .text:100B6440 xor edx, edx .text:100B6442 cmp eax, ebp .text:100B6444 setnle dl .text:100B6447 push 1 .text:100B6449 mov ebp, edx .text:100B644B mov eax, ebp .text:100B644D neg eax .text:100B644F sbb eax, eax .text:100B6451 add eax, 90h ; 'ð' .text:100B6456 push eax .text:100B6457 push 13C6h .text:100B645C lea eax, [esp+11ACh+Defender_Mod] .text:100B6460 push eax .text:100B6461 mov eax, [esp+11B0h+Defender_Roll_Result] .text:100B6465 lea edx, [esp+11B0h+var_DF8] .text:100B646C push edx .text:100B646D push eax .text:100B646E push ecx .text:100B646F mov ecx, [esp+11BCh+Defender_PTR] .text:100B6476 push ebx .text:100B6477 push ecx .text:100B6478 push esi .text:100B6479 push edi .text:100B647A call sub_10047F70 .text:100B647F push eax .text:100B6480 call sub_100DFFF0 .text:100B6485 lea edx, [esp+11D0h+var_A80] .text:100B648C push edx .text:100B648D call sub_1004DA70 .text:100B6492 lea eax, [esp+11D4h+var_700] .text:100B6499 push eax .text:100B649A call sub_1004DA70 .text:100B649F lea ecx, [esp+11D8h+var_380] .text:100B64A6 add esp, 40h .text:100B64A9 push ecx .text:100B64AA call sub_1004DA70 .text:100B64AF add esp, 4 .text:100B64B2 pop edi .text:100B64B3 pop esi .text:100B64B4 mov eax, ebp .text:100B64B6 pop ebp .text:100B64B7 pop ebx .text:100B64B8 add esp, 1188h .text:100B64BE retn .text:100B64BE Trip_Check endp .text:100B64BE .text:100B64BE ; ___________________________________________________________________________ .text:100B64BF align 10h
Wow, that's very impressive, Sitra Achara! It looks even more difficult/cumbersome than I imaged, tbh. I can't think of anything else that would use that function. I went through the list of feats and class abilities and didn't find anything, but I didn't go through spells. Some monster ability, maybe? Directly comparing attributes between two entities doesn't seem very D&D-ish to me at all, though.
If you read here ("bug2"): http://www.co8.org/forum/showpost.php?p=130688&postcount=3 I mentioned already that the manual explicitly speaks of a Strength check to attempt the trip. Never Dexterity. And yes, truly impressive work. I can't even start thinking of you even figured out where to search for the information you needed. Like short, I have been trying to look at the different feats to see where such function could be used the way it is now but I failed to find any... I think that function was expressly created for the Trip feat. I will also look through each spell to make sure you'd not break anything by fixing the function but I am pretty confident you can feel safe about the change. Thanks a lot, Sitra Achara! My prayers have indeed been answered...
Anthropoid, the name is in the top left corner on the screenshot he posted: XVI32. Sitra Achara, could you please upload the fix to the temple.dll somewhere?