<?xml version="1.0" encoding="utf-8"?>
<CheatTable CheatEngineTableVersion="52">
  <Files>
    <File Name="launchgame.dat" Encoding="Ascii85">t6@YZD9K1wNGr-r%{Xg)$WK!!%FIj8SI8^R$jnYGPt.4TNab=2igEXMS8z_vO*ZWIK}*_ER[,N@9z*nL1,KKjoZ=gn2;/</File>
  </Files>
  <CheatEntries>
    <CheatEntry>
      <ID>25</ID>
      <Description>"Check Table Extras For Instructions"</Description>
      <Color>008000</Color>
      <GroupHeader>1</GroupHeader>
    </CheatEntry>
    <CheatEntry>
      <ID>3</ID>
      <Description>"Find Value (uses On Access Function)"</Description>
      <Options moHideChildren="1" moDeactivateChildrenAsWell="1"/>
      <VariableType>Auto Assembler Script</VariableType>
      <AssemblerScript>[ENABLE]
aobScanModule(hackingPoint, the friends of ringo ishikawa.exe, 48 8B 03 48 89 07 EB ?? 41 8B 40 ??)

label(cheat)
label(nopInstruction)
label(code)
label(exit)

alloc(newmem, 2048, hackingPoint)
alloc(searchForThisValue, 8)

registersymbol(hackingPoint)
registersymbol(searchForThisValue)
registersymbol(nopInstruction)

newmem:

code:
mov rax,[rbx]
mov [rdi],rax

cheat:
cmp rax, [searchForThisValue]
jne exit

nopInstruction:
nop [rbx]
jmp exit

hackingPoint:
jmp newmem
nop
exit:
[DISABLE]
hackingPoint:
  db 48 8B 03 48 89 07

dealloc(*)
unregistersymbol(*)
</AssemblerScript>
      <CheatEntries>
        <CheatEntry>
          <ID>4</ID>
          <Description>"Value to Search For"</Description>
          <ShowAsSigned>0</ShowAsSigned>
          <VariableType>Double</VariableType>
          <Address>searchForThisValue</Address>
        </CheatEntry>
        <CheatEntry>
          <ID>5</ID>
          <Description>"Generate Entries"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>{$LUA}
if syntaxcheck then return end

[ENABLE]
-- Prevent print() from changing focus
getLuaEngine().cbShowOnPrint.Checked = false
-- Clear the console output
getLuaEngine().mOutput.clear()

local breakpoint = getAddressSafe('nopInstruction')
if not breakpoint then
  print('nopInstruction not found!')
  return
end

local search = getAddressSafe("searchForThisValue")
if not search then
  print("Error: searchForThisValue not defined!")
  return
end

writeDouble(search, inputQuery("Search", "Value to Search For: ", "0"))

local found = {}
local count = 1
local function createRecord(address)
  local record = AddressList.createMemoryRecord()

  record.Description = string.format('%X', address)
  record.Type = vtDouble
  record.Address = address

  record.appendToEntry(memrec)
end

local function on_found()
  local address = RBX

  if not found[address] then
    found[address] = true
    createRecord(address)
  end

  debug_continueFromBreakpoint()
end

debug_setBreakpoint(breakpoint, on_found)
registerSymbol('breakpoint', breakpoint, false)
[DISABLE]
local breakpoint = getAddressSafe('breakpoint')
if breakpoint then
  debug_removeBreakpoint(breakpoint)
  unregisterSymbol('breakpoint')
end

while memrec.Count &gt; 0 do
  memrec.Child[0].destroy()
end
</AssemblerScript>
        </CheatEntry>
      </CheatEntries>
    </CheatEntry>
    <CheatEntry>
      <ID>6</ID>
      <Description>"On Access Function"</Description>
      <Options moHideChildren="1"/>
      <VariableType>Auto Assembler Script</VariableType>
      <AssemblerScript>[ENABLE]
aobScanModule(hackingPoint, the friends of ringo ishikawa.exe, 48 8B 03 48 89 07 EB ?? 41 8B 40 ??)

label(cheat)
label(code)
label(exit)
label(found)

alloc(newmem, 2048, hackingPoint)
alloc(health, 8)
alloc(maxHealth, 8)
alloc(money, 8)
alloc(cigars, 8)
alloc(experience, 8)

registersymbol(hackingPoint)
registersymbol(health)
registersymbol(maxHealth)
registersymbol(money)
registersymbol(cigars)
registersymbol(experience)

newmem:

code:
mov rax,[rbx]
mov [rdi],rax

cheat:
cmp rsi, 9 // Health
jne @f
cmp r9, 1
jne @f
mov qword ptr [health], rbx
jmp found

@@:
cmp rsi, 8 // Max Health
jne @f
cmp r9, 1
jne @f
mov qword ptr [maxHealth], rbx
jmp found

@@:
cmp rsi, 5 // Money
jne @f
mov qword ptr [money], rbx
jmp found

@@:
cmp rsi, 3 // Cigars
jne @f
cmp r9, 1
jne @f
cmp r14, E
jne @f
mov qword ptr [cigars], rbx
jmp found

@@:
cmp rsi, 6 // Experience
jne exit
mov qword ptr [experience], rbx

found:
nop [rbx]
jmp exit

hackingPoint:
jmp newmem
nop
exit:
[DISABLE]
hackingPoint:
  db 48 8B 03 48 89 07

dealloc(*)
unregistersymbol(*)

</AssemblerScript>
      <CheatEntries>
        <CheatEntry>
          <ID>7</ID>
          <Description>"Health"</Description>
          <ShowAsSigned>0</ShowAsSigned>
          <VariableType>Double</VariableType>
          <Address>health</Address>
          <Offsets>
            <Offset>0</Offset>
          </Offsets>
        </CheatEntry>
        <CheatEntry>
          <ID>11</ID>
          <Description>"Max Health"</Description>
          <ShowAsSigned>0</ShowAsSigned>
          <VariableType>Double</VariableType>
          <Address>maxHealth</Address>
          <Offsets>
            <Offset>0</Offset>
          </Offsets>
        </CheatEntry>
        <CheatEntry>
          <ID>8</ID>
          <Description>"Money"</Description>
          <ShowAsSigned>0</ShowAsSigned>
          <VariableType>Double</VariableType>
          <Address>money</Address>
          <Offsets>
            <Offset>0</Offset>
          </Offsets>
        </CheatEntry>
        <CheatEntry>
          <ID>9</ID>
          <Description>"Cigars"</Description>
          <ShowAsSigned>0</ShowAsSigned>
          <VariableType>Double</VariableType>
          <Address>0C1D45A0</Address>
        </CheatEntry>
        <CheatEntry>
          <ID>10</ID>
          <Description>"Experience"</Description>
          <ShowAsSigned>0</ShowAsSigned>
          <VariableType>Double</VariableType>
          <Address>0C1A0370</Address>
        </CheatEntry>
      </CheatEntries>
    </CheatEntry>
    <CheatEntry>
      <ID>13</ID>
      <Description>"On Write Function"</Description>
      <Options moHideChildren="1"/>
      <VariableType>Auto Assembler Script</VariableType>
      <AssemblerScript>[ENABLE]
aobscanModule(hackingPointWrite, the friends of ringo ishikawa.exe, 49 8B 47 ?? 48 89 07)

label(code)
label(exit)
label(nopInstructionWrite)

alloc(newmem, 2048, hackingPointWrite)
alloc(copyhackingPointWrite, 7)

registersymbol(hackingPointWrite)
registersymbol(copyhackingPointWrite)
registersymbol(nopInstructionWrite)

copyhackingPointWrite:
  readmem(hackingPointWrite, 7)


newmem:
mov rax,[r15+30] // Changed value

cmp rdx, 1 // Player ID ?
jne code

cmp rsi, 3 // Cigar ID
je nopInstructionWrite

cmp rsi, 6 // Experience
je nopInstructionWrite

cmp rsi, 2 // Grades
je @f
jmp code

@@:
cmp [rsp+10], 15EBA0
je nopInstructionWrite

jmp code
nopInstructionWrite:
nop [rdi]

code:
// mov rax,[r15+30]
mov [rdi],rax

jmp exit
hackingPointWrite:
jmp newmem
nop 2

exit:
[DISABLE]
hackingPointWrite:
  readmem(copyhackingPointWrite, 7)

dealloc(*)
unregistersymbol(*)

</AssemblerScript>
      <CheatEntries>
        <CheatEntry>
          <ID>22</ID>
          <Description>"Generate Entries"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>{$LUA}
if syntaxcheck then return end

[ENABLE]
-- Get the nop instruction defined in the ASM script
local debugPoint = getAddressSafe('nopInstructionWrite')
if not debugPoint then
  print('Error: "nopInstructionWrite" not set')
  return
end

-- Create a new Record or Update an existing one
local function createRecord(name, address)
  local record = AddressList.getMemoryRecordByDescription(name)

  if not record or (record.Parent and record.Parent ~= memrec) then
    record = AddressList.createMemoryRecord()
    record.Type = vtDouble
    record.Description = name
    record.appendToEntry(memrec)
  end

  record.Address = address
end

local grades = {[1]="Literature", [2]="Physics", [3]="History", [4]="Mathematics", [5]="Chemistry"}
local nameList = {[3]="Cigars", [6]="Experience"}

local function onWrite()
  -- RSI is being used as the ID to diffentiate addresses
  if RSI == 2 then
    -- RBP is being used as ID for each Grade
    if grades[RBP] ~= nil then
       -- RDI is the address where the value you want to cheat is stored
       createRecord(grades[RBP], RDI)
    end
  else
    if nameList[RSI] ~= nil then
       createRecord(nameList[RSI], RDI)
    else
       createRecord(RDI, RDI)
    end
  end

  debug_continueFromBreakpoint()
end

-- When the nopInstructionWrite instruction is run, a breakpoint is triggered
-- and the onWrite cheat function is executed
debug_setBreakpoint(debugPoint, onWrite)
[DISABLE]
local debugPoint = getAddressSafe('nopInstructionWrite')
if debugPoint then
  debug_removeBreakpoint(debugPoint)
end

-- Destroy all the children of memrec
-- Addresses can be saved by simply moving them out of memrec
while memrec.Count &gt; 0 do
  memrec.Child[0].destroy()
end
</AssemblerScript>
        </CheatEntry>
      </CheatEntries>
    </CheatEntry>
    <CheatEntry>
      <ID>18</ID>
      <Description>"Infinite Health"</Description>
      <VariableType>Auto Assembler Script</VariableType>
      <AssemblerScript>[ENABLE]
aobscanModule(hackingPointGod, the friends of ringo ishikawa.exe, 48 89 03 48 8B 9C 24 ?? 00 00 00)
alloc(newmem,2048,hackingPointGod)
label(code)
label(cheat)
label(exit)

alloc(copyhackingPointGod, 11)

registersymbol(hackingPointGod)
registersymbol(copyhackingPointGod)

copyhackingPointGod:
 readmem(hackingPointGod, 11)

newmem:
cmp qword ptr [rbx], rax // Compared old with new
jle code // If lower, there's nothing to do

cheat:
cmp rsi, 1
jne code
cmp [rsp+8], 0
je code
cmp [rsp+28], "the friends of ringo ishikawa.exe"+6B900
jne code
cmp [rsp+40], 0
je code
cmp [rsp+A0], 5
jne code
cmp [rsp+E0], 0
jne code
cmp [rsp+118], 0
jne code
cmp [rsp+80], 00000000000186D2
jne code
cmp [rsp+e8], "the friends of ringo ishikawa.exe"+AF5CE
jne code

nop [rbx]
mov rbx,[rsp+00000090]
jmp exit

code:
mov [rbx],rax
mov rbx,[rsp+00000090]

jmp exit

hackingPointGod:
jmp newmem
nop 6

exit:
[DISABLE]
hackingPointGod:
 readmem(copyhackingPointGod, 11)

dealloc(*)
unregistersymbol(*)

</AssemblerScript>
    </CheatEntry>
    <CheatEntry>
      <ID>21</ID>
      <Description>"Fast Level Up"</Description>
      <VariableType>Auto Assembler Script</VariableType>
      <AssemblerScript>[ENABLE]
alloc(newmem,2048,the friends of ringo ishikawa.exe+1B9F04)
label(returnhere)
label(originalcode)
label(exit)

alloc(setRequiredExp, 8)

setRequiredExp:
dq (double)0

newmem:
cmp [rsp], 15E960
jne originalcode

cmp [rsp+10], 15EE50
jne originalcode

cmp [rsp+18], 0
jne originalcode

sub rsp, 10             // Make 16 bytes of room on the stack
movdqu [rsp], xmm0        // Save the entire XMM0 register (unaligned safe)

movsd xmm0, [setRequiredExp]
movsd [rdi], xmm0 // Changes required Exp to Level Up to Zero

movdqu xmm0, [rsp]        // Restore original XMM0 data
add rsp, 10             // Clean up the stack space

originalcode:
mov rax,[rdi]
mov [rbx],rax

exit:
jmp returnhere

the friends of ringo ishikawa.exe+1B9F04:
jmp newmem
nop
returnhere:
[DISABLE]
dealloc(newmem)
the friends of ringo ishikawa.exe+1B9F04:
db 48 8B 07 48 89 03

</AssemblerScript>
    </CheatEntry>
  </CheatEntries>
  <UserdefinedSymbols/>
  <Comments>-&gt; Find Value:
This game uses a few instructions to access and write to a lot of different addresses. This script compared the value stored at an address with an user defined value, greatly filtering the amount of addresses.

It can be used, for example, to find address for money, cigars, strength, grades, among many other things, many of which I haven't discovered yet.

-&gt; On Access Function:
This is one of the functions that access most of the interesting values in the game. It can be used to get useful pointers, but it's less reliable than the write function, at least until better IDs are found.

-&gt; On Write Function:
As the name implies, this refers to the function used to write a value into an address, like money, cigars, grades, etc. It only updates when the value changes in-game.

Currently, the following IDs have been found:
.Cigars
.Experience
.Grades

-&gt; Infinite Health:
This is the function that writes to the Health address. The script identifies when it's the player's health that's being changed, and if the health value is being decreased, it skips the code.

-&gt; Fast Level Up:
Because changing experience was causing bugs, I changed my approach for this cheat. By changing the experience required for level up, the same effect is achieved, without causing any bugs. Every time you gain experience, you'll level up.

This can be changed by modifying the setRequiredExp value inside the script, in case you don't want to level up instantly for some reason.

-&gt; General tips for creating hacks for this game:
. Start by finding the address for an in-game value.
. Find what access of writes to it.
. Check the stacktrace (more information -&gt; S button)
. Try using one of the [rsp+offset] values to identify the address and filter other addresses out, by using the cmp instruction.
. If the comparison succeeds, then use a nop [address], else jump to original code.
. Find what the nop [address] instruction access. This will greatly filter the addresses, allowing you to compare their stacktraces to find better IDs.
. Close and Relaunch the game to make sure the IDs remain consistent.</Comments>
</CheatTable>
