  | 
				
				Cheat Engine The Official Site of Cheat Engine   
				
 
				 | 
			 
		 
		 
	
		| View previous topic :: View next topic   | 
	 
	
	
		| Author | 
		Message | 
	 
	
		Gear2ndGandalf Cheater
  Reputation: 0
  Joined: 22 Jan 2018 Posts: 36 Location: USA
  | 
		
			
				 Posted: Tue Feb 06, 2024 9:10 pm    Post subject: Assembler: How Can I Divide Directly From r8d Register? | 
				       | 
			 
			
				
  | 
			 
			
				This address executes when an enemy hits player, and the damage output varies by enemy type and action. Instead of mov r8d,#1, where all enemies do 1 damage to the player, I want to divide the general damgae done by 2 as to keep in line with the variable damage output from a variety of enemies and attacks.
 
 
Google searched up and down just to find examples regarding eax, ah, bl, ebx, ax, bx. Though I fail to implement the code properly and keep crashing the game as an enemy attack lands.
 
 
Please view photo for code.
 
 	  | Code: | 	 		  push eax
 
push ebx
 
mov ebx,2
 
movsx r8d,word ptr [r10+000019A2]
 
div ebx
 
mov r8d,eax
 
pop ebx
 
pop eax | 	  
 
Clearly what I'm doing doesn't make sense.
	
  
	 
	
	
		
	 
	
		|  Description: | 
		
			
			
				| movsx r8d,word ptr [r10+000019A2] | 
			 
			 
		 | 
	 
	
		|  Filesize: | 
		 55.63 KB | 
	 
	
		|  Viewed: | 
		 16189 Time(s) | 
	 
	
		
  
 
  | 
	 
	 
	 
  Last edited by Gear2ndGandalf on Sat Feb 17, 2024 8:12 am; edited 1 time in total | 
			 
		  | 
	 
	
		| Back to top | 
		 | 
	 
	
		  | 
	 
	
		ParkourPenguin I post too much
  Reputation: 152
  Joined: 06 Jul 2014 Posts: 4706
 
  | 
		
			
				 Posted: Tue Feb 06, 2024 11:35 pm    Post subject:  | 
				       | 
			 
			
				
  | 
			 
			
				https://www.felixcloutier.com/x86/div
 
 
The numerator is always rdx:rax (rdx is the more significant half; edx:eax for 32-bit div). The denominator is some generic register or memory location- you're free to use whatever you want (probably not edx / eax obviously).
 
 
If you're dividing by 2, just shift the bits to the right by 1:
 
 	  | Code: | 	 		  newmem:
 
code:
 
  movsx r8d,word ptr[r10+19A2]
 
  sar r8d,1
 
  jmp return | 	  
 
Some generic divisor:
 
 	  | Code: | 	 		  alloc(damageDiv,4)
 
 
newmem:
 
code:
 
  // no need to backup rax: game overwrites it immediately after this
 
  push rdx
 
  movsx eax,word ptr[r10+19A2]   // eax b/c `idiv` uses edx:eax
 
  cdq                            // sign-extend to edx:eax
 
  idiv dword ptr[damageDiv]      // divide edx:eax by the specified 4-byte value
 
  mov r8d,eax
 
  pop rdx
 
  jmp return
 
 
damageDiv:
 
  dd 7 | 	  
 
If you want some user-configurable divisor, I'd really recommend using floating point arithmetic. This allows you to use divisors like 1.5 for example if 2 is too much.
 
 	  | Code: | 	 		  alloc(damageDiv,8)
 
 
newmem:
 
code:
 
  movsx r8d,word ptr[r10+19A2]
 
  cvtsi2sd xmm0,r8d       // convert int to double
 
  divsd xmm0,[damageDiv]
 
  cvttsd2si r8d,xmm0      // convert double to int (truncation)
 
  jmp return
 
 
damageDiv:
 
  dq (double)1.5 | 	  xmm0 probably isn't in use, so no need to back it up
 _________________
 I don't know where I'm going, but I'll figure it out when I get there.  | 
			 
		  | 
	 
	
		| Back to top | 
		 | 
	 
	
		  | 
	 
	
		Dark Byte Site Admin
  Reputation: 470
  Joined: 09 May 2003 Posts: 25807 Location: The netherlands
  | 
		
			
				 Posted: Wed Feb 07, 2024 12:54 am    Post subject:  | 
				       | 
			 
			
				
  | 
			 
			
				you don't need to use floats if you don't want to use floats
 
 
you can also multiply the value by 10 and then divide by 15 (divisor * 10) to get a divide by 1.5 with decent accuracy
 
 
(10 is just for accuracy. you can also multiply by 2 and then divide by 3(divisor * 2) depending on how accurate the input is)
 _________________
 Do not ask me about online cheats. I don't know any and wont help finding them.
 
 
Like my help? Join me on Patreon so i can keep helping  | 
			 
		  | 
	 
	
		| Back to top | 
		 | 
	 
	
		  | 
	 
	
		Gear2ndGandalf Cheater
  Reputation: 0
  Joined: 22 Jan 2018 Posts: 36 Location: USA
  | 
		
			
				 Posted: Wed Feb 07, 2024 1:00 pm    Post subject:  | 
				       | 
			 
			
				
  | 
			 
			
				| Thanks that code actually works! And thanks for the explanation as well.
 | 
			 
		  | 
	 
	
		| Back to top | 
		 | 
	 
	
		  | 
	 
	
		Gear2ndGandalf Cheater
  Reputation: 0
  Joined: 22 Jan 2018 Posts: 36 Location: USA
  | 
		
			
				 Posted: Sat Feb 17, 2024 8:11 am    Post subject:  | 
				       | 
			 
			
				
  | 
			 
			
				@ParkourPenguin
 
 
I have another one I'm struggling with.
 
 
Dante only goes into Majin Form devil trigger when his base HP is below 350. Starting max HP is 5000; Upgradable to 20000. I want to write a script that will allow us to set a percentage of Max HP needed to trigger the Majin Form.
 
 
Original code is:  	  | Code: | 	 		  | mov eax,0000015E // (350) | 	  
 
 
My code is:  	  | Code: | 	 		  aobscanmodule(majinDT,dmc2.exe,B8 5E 01 00 00 66 39 83)
 
alloc(newmem,$1000,majinDT)
 
alloc(percent,$1000)
 
 
label(code)
 
label(exit)
 
label(return)
 
 
percent:
 
  dd (float)100
 
 
newmem:
 
  push rdx
 
  push ecx
 
  mov edx,64 // 100 int
 
  mov eax,[rdi+144]  // 5000 int (Is Max HP Address)
 
  mov ecx,[percent]  // 100 float
 
  div ecx
 
  mov eax,edx
 
  pop ecx
 
  pop rdx
 
 
code:
 
  // mov eax,0000015E // Original Code!
 
 
exit:
 
  jmp return
 
 
majinDT:
 
  jmp newmem
 
return:
 
registersymbol(majinDT)
 
registersymbol(percent)
 
 | 	  
 
 
Please see attachment for total code in disassembler. I keep getting improper results as changing my variable [percent] to 1 does not output 1% of 5000 to eax!
 
 
If [percent = 1] eax should = 50. If [percent = 100] eax should = 5000
	
  
	 
	
	
		
	 
	
		|  Description: | 
		
			
		 | 
	 
	
		|  Filesize: | 
		 155.46 KB | 
	 
	
		|  Viewed: | 
		 15847 Time(s) | 
	 
	
		
  
 
  | 
	 
	 
	 
 | 
			 
		  | 
	 
	
		| Back to top | 
		 | 
	 
	
		  | 
	 
	
		ParkourPenguin I post too much
  Reputation: 152
  Joined: 06 Jul 2014 Posts: 4706
 
  | 
		
			
				 Posted: Sat Feb 17, 2024 12:31 pm    Post subject:  | 
				       | 
			 
			
				
  | 
			 
			
				`div` is for integers. If you want floating point arithmetic, use SSE instructions.
 
 
Push `rcx`, not `ecx`. There might be something important in the upper 32 bits (e.g. a 64-bit pointer).
 
 
You don't need to allocate a full page (4096 bytes) of memory for a single variable.
 
 
There's no good reason to use floats instead of doubles.
 
 
Why move 100 into edx before the `div`? edx is the upper 32 bits of the numerator.
 
After `div`, eax is the result and edx is the remainder (i.e. modulus operation). You want eax and not edx.
 
 
I'm guessing the user input should be a number between 0 and 100. Floating point arithmetic:
 
 	  | Code: | 	 		  aobscanmodule(majinDT,dmc2.exe,B8 5E 01 00 00 66 39 83)
 
alloc(newmem,1024,majinDT)
 
alloc(percent,8,majinDT)
 
alloc(hundred,8,majinDT)
 
 
label(return)
 
 
percent:
 
  dq (double)100
 
hundred:
 
  dq (double)100
 
 
newmem:
 
  cvtsi2sd xmm0,[rdi+144] // max hp
 
  mulsd xmm0,[percent]
 
  divsd xmm0,[hundred]
 
  cvttsd2si eax,xmm0
 
  jmp return
 
 
majinDT:
 
  jmp newmem
 
return:
 
 
registersymbol(majinDT)
 
registersymbol(percent) | 	  
 
 
I'd prefer floating point arithmetic, but if you want integer arithmetic, use integers instead of floats. Multiply by the percentage first, then divide by 100 to avoid loss of precision.
 
 	  | Code: | 	 		  ...
 
percent:
 
  dd (int)100
 
 
newmem:
 
  push rdx
 
  push rcx
 
 
  mov eax,[rdi+144]  // max HP
 
  imul [percent]  // edx:eax = maxHP * percent
 
  mov ecx,(int)100
 
  idiv ecx  // eax = edx:eax / ecx
 
 
  pop rcx
 
  pop rdx 
 
 
  jmp return
 
...
 
 | 	  
 _________________
 I don't know where I'm going, but I'll figure it out when I get there.  | 
			 
		  | 
	 
	
		| Back to top | 
		 | 
	 
	
		  | 
	 
	
		Gear2ndGandalf Cheater
  Reputation: 0
  Joined: 22 Jan 2018 Posts: 36 Location: USA
  | 
		
			
				 Posted: Tue Feb 20, 2024 11:14 pm    Post subject:  | 
				       | 
			 
			
				
  | 
			 
			
				| Really appreciate it! Thanks for all your help ParkourPenguin and Dark Byte! Now I'm going to open another topic with a CE question regarding how to make a pop up warning happen when enabling a script.
 | 
			 
		  | 
	 
	
		| Back to top | 
		 | 
	 
	
		  | 
	 
	
		 | 
	 
 
  
	 
	    
	   | 
	
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You can download files in this forum
  | 
   
 
		 |