Putting the 'role' back in role-playing games since 2002.
Donate to Codex
Good Old Games
  • Welcome to rpgcodex.net, a site dedicated to discussing computer based role-playing games in a free and open fashion. We're less strict than other forums, but please refer to the rules.

    "This message is awaiting moderator approval": All new users must pass through our moderation queue before they will be able to post normally. Until your account has "passed" your posts will only be visible to yourself (and moderators) until they are approved. Give us a week to get around to approving / deleting / ignoring your mundane opinion on crap before hassling us about it. Once you have passed the moderation period (think of it as a test), you will be able to post normally, just like all the other retards.

Made a "mod" to remove natural 20s from NWN diamond

deama

Prophet
Joined
May 13, 2013
Messages
4,417
Location
UK
So I basically hate how they've implemented natural 20s and 1s and was wondering if there's a way to remove them? So they're treated normally instead of an automatic fail or success?

EDIT:
Alright guys, so I worked it out, made a "mod" that removes natural 20s, for everyone. You have to use cheat engine, so just copy the below into a .txt file, rename it to a .ct file and open it with cheat engine. There should be two boxes at the bottom, tick the one that says "no natural 20s", not the other one. This will only work on the diamond edition, I have no idea if it will work in the enhanced one, probably not my guess.

Also, keep in mind, this works by finding out if the roll was a 20, then changing it to a 19 before any checks are done to it. So if you have a weapon that will only crit on 20s, then sorry, you can't crit anymore, though the chance to crit won't be affected if it's 19-20, sorry, couldn't be asked to fix this part.

Oh and if you're looking to disable natural 1s for just saving throws, then you can disable it in the nwnplayer.ini file by putting the "Saving Throw Automatic Failure On 1" to 0.

<?xml version="1.0" encoding="utf-8"?>
<CheatTable CheatEngineTableVersion="26">
<CheatEntries>
<CheatEntry>
<ID>0</ID>
<Description>"old, don't touch"</Description>
<LastState/>
<VariableType>Auto Assembler Script</VariableType>
<AssemblerScript>[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
alloc(newmem,2048)
label(returnhere)
label(originalcode)
label(exit)

newmem: //this is allocated memory, you have read,write,execute access
pop edx
pop ebx
pop eax
mov eax,#18
jmp exit

originalcode:
and eax,00007FFF

push eax
push ebx
push edx
mov ebx,#20
div ebx
cmp edx,#19
je newmem
pop edx
pop ebx
pop eax

exit:
jmp returnhere

"nwmain.exe"+44C118:
jmp originalcode
returnhere:


[DISABLE]
//code from here till the end of the code will be used to disable the cheat
dealloc(newmem)
"nwmain.exe"+44C118:
and eax,00007FFF
//Alt: db 25 FF 7F 00 00
</AssemblerScript>
</CheatEntry>
<CheatEntry>
<ID>1</ID>
<Description>"no natural 20s"</Description>
<LastState Activated="1"/>
<VariableType>Auto Assembler Script</VariableType>
<AssemblerScript>{ Game : nwmain.exe
Version:
Date : 2019-09-10
Author : deama

This script does blah blah blah
}

[ENABLE]

aobscanmodule(INJECT,nwmain.exe,25 FF 7F 00 00 C3) // should be unique
alloc(newmem,$1000)

label(code)
label(return)

newmem:
pop edx
pop ebx
pop eax
mov eax,#18
jmp return


code:
and eax,00007FFF
///////////////////////////
push eax
push ebx
push edx
mov ebx,#20
div ebx
cmp edx,#19
je newmem
pop edx
pop ebx
pop eax
///////////////////////////
jmp return

INJECT:
jmp code
return:
registersymbol(INJECT)

[DISABLE]

INJECT:
db 25 FF 7F 00 00

unregistersymbol(INJECT)
dealloc(newmem)

{
// ORIGINAL CODE - INJECTION POINT: "nwmain.exe"+44C118

"nwmain.exe"+44C0F4: 8B 4C 24 04 - mov ecx,[esp+04]
"nwmain.exe"+44C0F8: 89 48 14 - mov [eax+14],ecx
"nwmain.exe"+44C0FB: C3 - ret
"nwmain.exe"+44C0FC: E8 B2 3C 00 00 - call nwmain.exe+44FDB3
"nwmain.exe"+44C101: 8B 48 14 - mov ecx,[eax+14]
"nwmain.exe"+44C104: 69 C9 FD 43 03 00 - imul ecx,ecx,000343FD
"nwmain.exe"+44C10A: 81 C1 C3 9E 26 00 - add ecx,00269EC3
"nwmain.exe"+44C110: 89 48 14 - mov [eax+14],ecx
"nwmain.exe"+44C113: 8B C1 - mov eax,ecx
"nwmain.exe"+44C115: C1 E8 10 - shr eax,10
// ---------- INJECTING HERE ----------
"nwmain.exe"+44C118: 25 FF 7F 00 00 - and eax,00007FFF
// ---------- DONE INJECTING ----------
"nwmain.exe"+44C11D: C3 - ret
"nwmain.exe"+44C11E: CC - int 3
"nwmain.exe"+44C11F: CC - int 3
"nwmain.exe"+44C120: 83 EC 08 - sub esp,08
"nwmain.exe"+44C123: DD 14 24 - fst qword ptr [esp]
"nwmain.exe"+44C126: E8 1D 71 00 00 - call nwmain.exe+453248
"nwmain.exe"+44C12B: E8 0D 00 00 00 - call nwmain.exe+44C13D
"nwmain.exe"+44C130: 83 C4 08 - add esp,08
"nwmain.exe"+44C133: C3 - ret
"nwmain.exe"+44C134: 8D 54 24 04 - lea edx,[esp+04]
}
</AssemblerScript>
</CheatEntry>
</CheatEntries>
<CheatCodes>
<CodeEntry>
<Description>Change of test ebp,ebp</Description>
<Address>0064A295</Address>
<ModuleName>nwmain.exe</ModuleName>
<ModuleNameOffset>24A295</ModuleNameOffset>
<Before>
<Byte>6C</Byte>
<Byte>24</Byte>
<Byte>40</Byte>
<Byte>75</Byte>
<Byte>3D</Byte>
</Before>
<Actual>
<Byte>85</Byte>
<Byte>ED</Byte>
</Actual>
<After>
<Byte>74</Byte>
<Byte>39</Byte>
<Byte>66</Byte>
<Byte>8B</Byte>
<Byte>45</Byte>
</After>
</CodeEntry>
<CodeEntry>
<Description>Change of jne nwmain.exe+24A2B9</Description>
<Address>0064A2AC</Address>
<ModuleName>nwmain.exe</ModuleName>
<ModuleNameOffset>24A2AC</ModuleNameOffset>
<Before>
<Byte>FF</Byte>
<Byte>00</Byte>
<Byte>00</Byte>
<Byte>3B</Byte>
<Byte>C1</Byte>
</Before>
<Actual>
<Byte>75</Byte>
<Byte>0B</Byte>
</Actual>
<After>
<Byte>BF</Byte>
<Byte>01</Byte>
<Byte>00</Byte>
<Byte>00</Byte>
<Byte>00</Byte>
</After>
</CodeEntry>
<CodeEntry>
<Description>Change of call dword ptr [edx+7C]</Description>
<Address>006BF170</Address>
<ModuleName>nwmain.exe</ModuleName>
<ModuleNameOffset>2BF170</ModuleNameOffset>
<Before>
<Byte>56</Byte>
<Byte>55</Byte>
<Byte>57</Byte>
<Byte>8B</Byte>
<Byte>C8</Byte>
</Before>
<Actual>
<Byte>FF</Byte>
<Byte>52</Byte>
<Byte>7C</Byte>
</Actual>
<After>
<Byte>E9</Byte>
<Byte>CB</Byte>
<Byte>FE</Byte>
<Byte>FF</Byte>
<Byte>FF</Byte>
</After>
</CodeEntry>
<CodeEntry>
<Description>Change of mov eax,[esp+10]</Description>
<Address>7754DEC0</Address>
<ModuleName>ntdll.dll</ModuleName>
<ModuleNameOffset>2DEC0</ModuleNameOffset>
<Before>
<Byte>35</Byte>
<Byte>00</Byte>
<Byte>00</Byte>
<Byte>00</Byte>
<Byte>00</Byte>
</Before>
<Actual>
<Byte>8B</Byte>
<Byte>44</Byte>
<Byte>24</Byte>
<Byte>10</Byte>
</Actual>
<After>
<Byte>89</Byte>
<Byte>6C</Byte>
<Byte>24</Byte>
<Byte>10</Byte>
<Byte>8D</Byte>
</After>
</CodeEntry>
<CodeEntry>
<Description>Change of call nwmain.exe+44FDB3</Description>
<Address>0084C0FC</Address>
<ModuleName>nwmain.exe</ModuleName>
<ModuleNameOffset>44C0FC</ModuleNameOffset>
<Before>
<Byte>04</Byte>
<Byte>89</Byte>
<Byte>48</Byte>
<Byte>14</Byte>
<Byte>C3</Byte>
</Before>
<Actual>
<Byte>E8</Byte>
<Byte>B2</Byte>
<Byte>3C</Byte>
<Byte>00</Byte>
<Byte>00</Byte>
</Actual>
<After>
<Byte>8B</Byte>
<Byte>48</Byte>
<Byte>14</Byte>
<Byte>69</Byte>
<Byte>C9</Byte>
</After>
</CodeEntry>
</CheatCodes>
<UserdefinedSymbols/>
<Structures StructVersion="2">
<Structure Name="unnamed structure" AutoFill="0" AutoCreate="1" DefaultHex="0" AutoDestroy="0" DoNotSaveLocal="0" RLECompression="1" AutoCreateStructsize="4096">
<Elements>
<Element Offset="0" Vartype="4 Bytes" Bytesize="4" RLECount="404" DisplayMethod="Unsigned Integer"/>
</Elements>
</Structure>
</Structures>
<Comments>Info about this table:
</Comments>
</CheatTable>
 
Last edited:

Chippy

Arcane
Patron
Joined
May 5, 2018
Messages
6,066
Steve gets a Kidney but I don't even get a tag.
I never looked to much into this as I didn't want to know if the system was flawed. But I did skim read some bitching over the subject on a forum here and there.

So what was wrong with it? I just remember giving up on saving throws, always assuming my character would roll a 1. Then planning for items and classes that provided immunity.
 

deama

Prophet
Joined
May 13, 2013
Messages
4,417
Location
UK
I never looked to much into this as I didn't want to know if the system was flawed. But I did skim read some bitching over the subject on a forum here and there.

So what was wrong with it? I just remember giving up on saving throws, always assuming my character would roll a 1. Then planning for items and classes that provided immunity.
After rolling 1s too often, I went on the internet and found out NWNs RNG is kinda crap. It seems it's prone to streaks, so for example, at one point you can get a streak of 1s or 20s several times in a row. One guy said he got 5 1s in a row. Another guy mentioned that at one point he always rolled higher than 15 50 times a row; another guy said he rolled below 10 all the time.

Some people tried to explain what was going on, best answer is that the game was using time as one of its random seeds (or maybe only seed), so if you rolled in the same milisecond, you'd get the same result, or something like that.

I was hoping there'd be a way to disable natural 1s and 20s so I don't get popped out of the blue, I swear the luck some mobs have with rolling 20s with death spells is just insane.
 

lukaszek

the determinator
Patron
Joined
Jan 15, 2015
Messages
12,691
deterministic system > RNG
 
Last edited:

deama

Prophet
Joined
May 13, 2013
Messages
4,417
Location
UK
freeze system time you say? Got to try it on next run!
Worry not, I shall distribute my mod for that. It will be neat, ready to run .exe file, you would just need to disable your mcaffe and firewalls.
That would probably break your system in general I would imagine, though who knows. I'm not even sure if NWN takes system time or whether it takes it's own time.
 

cruelio

Augur
Joined
Nov 9, 2014
Messages
370
Just remove them and use 18 sided die that goes from 2-19. Easy.
 

deama

Prophet
Joined
May 13, 2013
Messages
4,417
Location
UK
Alright guys, so I worked it out, made a "mod" that removes natural 20s, for everyone. You have to use cheat engine, so just copy the below into a .txt file, rename it to a .ct file and open it with cheat engine. There should be two boxes at the bottom, tick the one that says "no natural 20s", not the other one. This will only work on the diamond edition, I have no idea if it will work in the enhanced one, probably not my guess.

Also, keep in mind, this works by finding out if the roll was a 20, then changing it to a 19 before any checks are done to it. So if you have a weapon that will only crit on 20s, then sorry, you can't crit anymore, though the chance to crit won't be affected if it's 19-20, sorry, couldn't be asked to fix this part.

<?xml version="1.0" encoding="utf-8"?>
<CheatTable CheatEngineTableVersion="26">
<CheatEntries>
<CheatEntry>
<ID>0</ID>
<Description>"old, don't touch"</Description>
<LastState/>
<VariableType>Auto Assembler Script</VariableType>
<AssemblerScript>[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
alloc(newmem,2048)
label(returnhere)
label(originalcode)
label(exit)

newmem: //this is allocated memory, you have read,write,execute access
pop edx
pop ebx
pop eax
mov eax,#18
jmp exit

originalcode:
and eax,00007FFF

push eax
push ebx
push edx
mov ebx,#20
div ebx
cmp edx,#19
je newmem
pop edx
pop ebx
pop eax

exit:
jmp returnhere

"nwmain.exe"+44C118:
jmp originalcode
returnhere:


[DISABLE]
//code from here till the end of the code will be used to disable the cheat
dealloc(newmem)
"nwmain.exe"+44C118:
and eax,00007FFF
//Alt: db 25 FF 7F 00 00
</AssemblerScript>
</CheatEntry>
<CheatEntry>
<ID>1</ID>
<Description>"no natural 20s"</Description>
<LastState Activated="1"/>
<VariableType>Auto Assembler Script</VariableType>
<AssemblerScript>{ Game : nwmain.exe
Version:
Date : 2019-09-10
Author : deama

This script does blah blah blah
}

[ENABLE]

aobscanmodule(INJECT,nwmain.exe,25 FF 7F 00 00 C3) // should be unique
alloc(newmem,$1000)

label(code)
label(return)

newmem:
pop edx
pop ebx
pop eax
mov eax,#18
jmp return


code:
and eax,00007FFF
///////////////////////////
push eax
push ebx
push edx
mov ebx,#20
div ebx
cmp edx,#19
je newmem
pop edx
pop ebx
pop eax
///////////////////////////
jmp return

INJECT:
jmp code
return:
registersymbol(INJECT)

[DISABLE]

INJECT:
db 25 FF 7F 00 00

unregistersymbol(INJECT)
dealloc(newmem)

{
// ORIGINAL CODE - INJECTION POINT: "nwmain.exe"+44C118

"nwmain.exe"+44C0F4: 8B 4C 24 04 - mov ecx,[esp+04]
"nwmain.exe"+44C0F8: 89 48 14 - mov [eax+14],ecx
"nwmain.exe"+44C0FB: C3 - ret
"nwmain.exe"+44C0FC: E8 B2 3C 00 00 - call nwmain.exe+44FDB3
"nwmain.exe"+44C101: 8B 48 14 - mov ecx,[eax+14]
"nwmain.exe"+44C104: 69 C9 FD 43 03 00 - imul ecx,ecx,000343FD
"nwmain.exe"+44C10A: 81 C1 C3 9E 26 00 - add ecx,00269EC3
"nwmain.exe"+44C110: 89 48 14 - mov [eax+14],ecx
"nwmain.exe"+44C113: 8B C1 - mov eax,ecx
"nwmain.exe"+44C115: C1 E8 10 - shr eax,10
// ---------- INJECTING HERE ----------
"nwmain.exe"+44C118: 25 FF 7F 00 00 - and eax,00007FFF
// ---------- DONE INJECTING ----------
"nwmain.exe"+44C11D: C3 - ret
"nwmain.exe"+44C11E: CC - int 3
"nwmain.exe"+44C11F: CC - int 3
"nwmain.exe"+44C120: 83 EC 08 - sub esp,08
"nwmain.exe"+44C123: DD 14 24 - fst qword ptr [esp]
"nwmain.exe"+44C126: E8 1D 71 00 00 - call nwmain.exe+453248
"nwmain.exe"+44C12B: E8 0D 00 00 00 - call nwmain.exe+44C13D
"nwmain.exe"+44C130: 83 C4 08 - add esp,08
"nwmain.exe"+44C133: C3 - ret
"nwmain.exe"+44C134: 8D 54 24 04 - lea edx,[esp+04]
}
</AssemblerScript>
</CheatEntry>
</CheatEntries>
<CheatCodes>
<CodeEntry>
<Description>Change of test ebp,ebp</Description>
<Address>0064A295</Address>
<ModuleName>nwmain.exe</ModuleName>
<ModuleNameOffset>24A295</ModuleNameOffset>
<Before>
<Byte>6C</Byte>
<Byte>24</Byte>
<Byte>40</Byte>
<Byte>75</Byte>
<Byte>3D</Byte>
</Before>
<Actual>
<Byte>85</Byte>
<Byte>ED</Byte>
</Actual>
<After>
<Byte>74</Byte>
<Byte>39</Byte>
<Byte>66</Byte>
<Byte>8B</Byte>
<Byte>45</Byte>
</After>
</CodeEntry>
<CodeEntry>
<Description>Change of jne nwmain.exe+24A2B9</Description>
<Address>0064A2AC</Address>
<ModuleName>nwmain.exe</ModuleName>
<ModuleNameOffset>24A2AC</ModuleNameOffset>
<Before>
<Byte>FF</Byte>
<Byte>00</Byte>
<Byte>00</Byte>
<Byte>3B</Byte>
<Byte>C1</Byte>
</Before>
<Actual>
<Byte>75</Byte>
<Byte>0B</Byte>
</Actual>
<After>
<Byte>BF</Byte>
<Byte>01</Byte>
<Byte>00</Byte>
<Byte>00</Byte>
<Byte>00</Byte>
</After>
</CodeEntry>
<CodeEntry>
<Description>Change of call dword ptr [edx+7C]</Description>
<Address>006BF170</Address>
<ModuleName>nwmain.exe</ModuleName>
<ModuleNameOffset>2BF170</ModuleNameOffset>
<Before>
<Byte>56</Byte>
<Byte>55</Byte>
<Byte>57</Byte>
<Byte>8B</Byte>
<Byte>C8</Byte>
</Before>
<Actual>
<Byte>FF</Byte>
<Byte>52</Byte>
<Byte>7C</Byte>
</Actual>
<After>
<Byte>E9</Byte>
<Byte>CB</Byte>
<Byte>FE</Byte>
<Byte>FF</Byte>
<Byte>FF</Byte>
</After>
</CodeEntry>
<CodeEntry>
<Description>Change of mov eax,[esp+10]</Description>
<Address>7754DEC0</Address>
<ModuleName>ntdll.dll</ModuleName>
<ModuleNameOffset>2DEC0</ModuleNameOffset>
<Before>
<Byte>35</Byte>
<Byte>00</Byte>
<Byte>00</Byte>
<Byte>00</Byte>
<Byte>00</Byte>
</Before>
<Actual>
<Byte>8B</Byte>
<Byte>44</Byte>
<Byte>24</Byte>
<Byte>10</Byte>
</Actual>
<After>
<Byte>89</Byte>
<Byte>6C</Byte>
<Byte>24</Byte>
<Byte>10</Byte>
<Byte>8D</Byte>
</After>
</CodeEntry>
<CodeEntry>
<Description>Change of call nwmain.exe+44FDB3</Description>
<Address>0084C0FC</Address>
<ModuleName>nwmain.exe</ModuleName>
<ModuleNameOffset>44C0FC</ModuleNameOffset>
<Before>
<Byte>04</Byte>
<Byte>89</Byte>
<Byte>48</Byte>
<Byte>14</Byte>
<Byte>C3</Byte>
</Before>
<Actual>
<Byte>E8</Byte>
<Byte>B2</Byte>
<Byte>3C</Byte>
<Byte>00</Byte>
<Byte>00</Byte>
</Actual>
<After>
<Byte>8B</Byte>
<Byte>48</Byte>
<Byte>14</Byte>
<Byte>69</Byte>
<Byte>C9</Byte>
</After>
</CodeEntry>
</CheatCodes>
<UserdefinedSymbols/>
<Structures StructVersion="2">
<Structure Name="unnamed structure" AutoFill="0" AutoCreate="1" DefaultHex="0" AutoDestroy="0" DoNotSaveLocal="0" RLECompression="1" AutoCreateStructsize="4096">
<Elements>
<Element Offset="0" Vartype="4 Bytes" Bytesize="4" RLECount="404" DisplayMethod="Unsigned Integer"/>
</Elements>
</Structure>
</Structures>
<Comments>Info about this table:
</Comments>
</CheatTable>
 

deama

Prophet
Joined
May 13, 2013
Messages
4,417
Location
UK

As an Amazon Associate, rpgcodex.net earns from qualifying purchases.
Back
Top Bottom