Initial commit
This commit is contained in:
commit
31f9808a93
6 changed files with 308 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
main.lua
|
36
README.md
Normal file
36
README.md
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# ootAI
|
||||||
|
|
||||||
|
An experiment to create an AI that plays OoT Randomizers automatically, getting
|
||||||
|
as many checks as possible in an efficient manner.
|
||||||
|
|
||||||
|
## how does it work
|
||||||
|
|
||||||
|
This runs using the Lua Core fork of the Dolphin Emulator project. As of right
|
||||||
|
now it only works on ROMs generated by the OoT Randomizer.
|
||||||
|
|
||||||
|
Eventually I'll have an explanation here on how it does pathfinding and memory
|
||||||
|
reading, but I don't know how to do enough of that yet.
|
||||||
|
|
||||||
|
## how to build
|
||||||
|
|
||||||
|
1. Install [AmuletML](https://amulet.works/).
|
||||||
|
2. Run `amc compile main.ml -o main.lua --lib /path/to/amulet/lib`
|
||||||
|
3. Copy everything between the first `do` and the last `end` from `main.lua`
|
||||||
|
4. Create a new script in the Dolphin Lua Core Scripts directory:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function onScriptStart() end
|
||||||
|
|
||||||
|
function onScriptCancel() end
|
||||||
|
|
||||||
|
function onScriptUpdate()
|
||||||
|
-- paste what you copied here
|
||||||
|
end
|
||||||
|
|
||||||
|
function onStateLoaded() end
|
||||||
|
|
||||||
|
function onStateSaved() end
|
||||||
|
```
|
||||||
|
|
||||||
|
This script should now run properly when you start it from the Dolphin scripts
|
||||||
|
menu.
|
103
dolphin.ml
Normal file
103
dolphin.ml
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
open import "prelude.ml"
|
||||||
|
|
||||||
|
type u8 =
|
||||||
|
U8 of int
|
||||||
|
|
||||||
|
instance show u8 begin
|
||||||
|
let show (U8 x) = (show x) ^ "_u8"
|
||||||
|
end
|
||||||
|
|
||||||
|
type s8 =
|
||||||
|
S8 of int
|
||||||
|
|
||||||
|
instance show s8 begin
|
||||||
|
let show (S8 x) =
|
||||||
|
let signfix =
|
||||||
|
if x > 127 then
|
||||||
|
negate (256 - x)
|
||||||
|
else
|
||||||
|
x
|
||||||
|
(show signfix) ^ "_s8"
|
||||||
|
end
|
||||||
|
|
||||||
|
type u16 =
|
||||||
|
U16 of int
|
||||||
|
|
||||||
|
instance show u16 begin
|
||||||
|
let show (U16 x) = (show x) ^ "_u16"
|
||||||
|
end
|
||||||
|
|
||||||
|
type s16 =
|
||||||
|
S16 of int
|
||||||
|
|
||||||
|
instance show s16 begin
|
||||||
|
let show (S16 x) =
|
||||||
|
let signfix =
|
||||||
|
if x > 32767 then
|
||||||
|
negate (65536 - x)
|
||||||
|
else
|
||||||
|
x
|
||||||
|
(show signfix) ^ "_s16"
|
||||||
|
end
|
||||||
|
|
||||||
|
type u32 =
|
||||||
|
U32 of int
|
||||||
|
|
||||||
|
type s32 =
|
||||||
|
S32 of int
|
||||||
|
|
||||||
|
instance show s32 begin
|
||||||
|
let show (S32 x) =
|
||||||
|
let signfix =
|
||||||
|
if x > 2147483647 then
|
||||||
|
negate (4294967296 - x)
|
||||||
|
else
|
||||||
|
x
|
||||||
|
(show signfix) ^ "_s32"
|
||||||
|
end
|
||||||
|
|
||||||
|
module Dolphin = struct
|
||||||
|
external val read_value_8 : int -> () -> int =
|
||||||
|
"function(addr, n) return ReadValue8(addr) end"
|
||||||
|
external val read_value_16 : int -> () -> int =
|
||||||
|
"function(addr, n) return ReadValue16(addr) end"
|
||||||
|
external val read_value_32 : int -> () -> int =
|
||||||
|
"function(addr, n) return ReadValue32(addr) end"
|
||||||
|
external val read_value_float : int -> () -> float =
|
||||||
|
"function(addr, n) return ReadValueFloat(addr) end"
|
||||||
|
external val read_value_string : int -> int -> () -> string =
|
||||||
|
"function(addr, len, n) return ReadValueString(addr, len) end"
|
||||||
|
|
||||||
|
external val msg_box : string -> int -> () -> () =
|
||||||
|
"function(message, delay, n) MsgBox(message, delay) end"
|
||||||
|
external val set_screen_text : string -> () -> () =
|
||||||
|
"function(message, n) SetScreenText(message) end"
|
||||||
|
end
|
||||||
|
|
||||||
|
class decode 'a begin
|
||||||
|
val decode : int -> () -> 'a
|
||||||
|
end
|
||||||
|
|
||||||
|
instance decode u8 begin
|
||||||
|
let decode addr x = U8 (Dolphin.read_value_8 addr x)
|
||||||
|
end
|
||||||
|
|
||||||
|
instance decode s8 begin
|
||||||
|
let decode addr x = S8 (Dolphin.read_value_8 addr x)
|
||||||
|
end
|
||||||
|
|
||||||
|
instance decode u16 begin
|
||||||
|
let decode addr x = U16 (Dolphin.read_value_16 addr x)
|
||||||
|
end
|
||||||
|
|
||||||
|
instance decode s16 begin
|
||||||
|
let decode addr x = S16 (Dolphin.read_value_16 addr x)
|
||||||
|
end
|
||||||
|
|
||||||
|
instance decode u32 begin
|
||||||
|
let decode addr x = U32 (Dolphin.read_value_32 addr x)
|
||||||
|
end
|
||||||
|
|
||||||
|
instance decode s32 begin
|
||||||
|
let decode addr x = S32 (Dolphin.read_value_32 addr x)
|
||||||
|
end
|
20
main.ml
Normal file
20
main.ml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
open import "prelude.ml"
|
||||||
|
|
||||||
|
open import "./save_context.ml"
|
||||||
|
|
||||||
|
open import "./pretty.ml"
|
||||||
|
open import "./dolphin.ml"
|
||||||
|
|
||||||
|
let base_address = 0xf64120
|
||||||
|
|
||||||
|
let g_save_ctx_address = 0x11a5d0
|
||||||
|
|
||||||
|
let decode_save_ctx : () -> save_context = decode (base_address + g_save_ctx_address)
|
||||||
|
|
||||||
|
let main x =
|
||||||
|
let save_ctx = decode_save_ctx x
|
||||||
|
let display_save_ctx = "Save Context: " ^ (pretty save_ctx 0)
|
||||||
|
Dolphin.set_screen_text display_save_ctx x
|
||||||
|
|
||||||
|
let () =
|
||||||
|
main ()
|
5
pretty.ml
Normal file
5
pretty.ml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
open import "prelude.ml"
|
||||||
|
|
||||||
|
class pretty 'a begin
|
||||||
|
val pretty : 'a -> int -> string
|
||||||
|
end
|
143
save_context.ml
Normal file
143
save_context.ml
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
open import "prelude.ml"
|
||||||
|
|
||||||
|
open import "./pretty.ml"
|
||||||
|
|
||||||
|
open import "./dolphin.ml"
|
||||||
|
|
||||||
|
type item_equips = ItemEquips of {
|
||||||
|
button_item_b: u8,
|
||||||
|
button_item_c_left: u8,
|
||||||
|
button_item_c_down: u8,
|
||||||
|
button_item_c_right: u8,
|
||||||
|
button_slot_c_left: u8,
|
||||||
|
button_slot_c_down: u8,
|
||||||
|
button_slot_c_right: u8,
|
||||||
|
equipment: u16
|
||||||
|
}
|
||||||
|
|
||||||
|
instance decode item_equips begin
|
||||||
|
let decode addr x = ItemEquips {
|
||||||
|
button_item_b = decode (addr + 0x00) x,
|
||||||
|
button_item_c_left = decode (addr + 0x01) x,
|
||||||
|
button_item_c_down = decode (addr + 0x02) x,
|
||||||
|
button_item_c_right = decode (addr + 0x03) x,
|
||||||
|
button_slot_c_left = decode (addr + 0x04) x,
|
||||||
|
button_slot_c_down = decode (addr + 0x05) x,
|
||||||
|
button_slot_c_right = decode (addr + 0x06) x,
|
||||||
|
equipment = decode (addr + 0x08) x
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
instance pretty item_equips begin
|
||||||
|
let pretty (ItemEquips item_equips) w =
|
||||||
|
let rec smul s n =
|
||||||
|
if n <= 0 then
|
||||||
|
""
|
||||||
|
else
|
||||||
|
s ^ (smul s (n - 1))
|
||||||
|
let prep = smul " " w
|
||||||
|
let header = "ItemEquips {\n"
|
||||||
|
let button_item_b = header ^ prep ^ " button_item_b = " ^ (show item_equips.button_item_b) ^ ",\n"
|
||||||
|
let button_item_c_left = button_item_b ^ prep ^ " button_item_c_left = " ^ (show item_equips.button_item_c_left) ^ ",\n"
|
||||||
|
let button_item_c_down = button_item_c_left ^ prep ^ " button_item_c_down = " ^ (show item_equips.button_item_c_down) ^ ",\n"
|
||||||
|
let button_item_c_right = button_item_c_down ^ prep ^ " button_item_c_right = " ^ (show item_equips.button_item_c_right) ^ ",\n"
|
||||||
|
let button_slot_c_left = button_item_c_right ^ prep ^ " button_slot_c_left = " ^ (show item_equips.button_slot_c_left) ^ ",\n"
|
||||||
|
let button_slot_c_down = button_slot_c_left ^ prep ^ " button_slot_c_down = " ^ (show item_equips.button_slot_c_down) ^ ",\n"
|
||||||
|
let button_slot_c_right = button_slot_c_down ^ prep ^ " button_slot_c_right = " ^ (show item_equips.button_slot_c_right) ^ ",\n"
|
||||||
|
let equipment = button_slot_c_right ^ prep ^ " equipment = " ^ (show item_equips.equipment) ^ ",\n"
|
||||||
|
equipment ^ prep ^ "}"
|
||||||
|
end
|
||||||
|
|
||||||
|
type save_context = SaveContext of {
|
||||||
|
entrance_index: s32,
|
||||||
|
link_age: s32,
|
||||||
|
cutscene_index: s32,
|
||||||
|
day_time: u16,
|
||||||
|
night_flag: s32,
|
||||||
|
num_days: s32,
|
||||||
|
claim_days: s32,
|
||||||
|
(* char newf[6], *)
|
||||||
|
deaths: s16,
|
||||||
|
(* char playerName[8], *)
|
||||||
|
n64dd_flag: s16,
|
||||||
|
health_capacity: s16,
|
||||||
|
health: s16,
|
||||||
|
magic_level: s8,
|
||||||
|
magic: s8,
|
||||||
|
rupees: s16,
|
||||||
|
sword_health: u16,
|
||||||
|
navi_timer: u16,
|
||||||
|
magic_acquired: u8,
|
||||||
|
(* char unk_3B[0x01], *)
|
||||||
|
double_magic: u8,
|
||||||
|
double_defense: u8,
|
||||||
|
bgs_flag: u8,
|
||||||
|
ocarina_game_reward: u8,
|
||||||
|
child_equips: item_equips,
|
||||||
|
adult_equips: item_equips
|
||||||
|
}
|
||||||
|
|
||||||
|
instance decode save_context begin
|
||||||
|
let decode addr x = SaveContext {
|
||||||
|
entrance_index = decode (addr + 0x0000) x,
|
||||||
|
link_age = decode (addr + 0x0004) x,
|
||||||
|
cutscene_index = decode (addr + 0x0008) x,
|
||||||
|
day_time = decode (addr + 0x000C) x,
|
||||||
|
night_flag = decode (addr + 0x0010) x,
|
||||||
|
num_days = decode (addr + 0x0014) x,
|
||||||
|
claim_days = decode (addr + 0x0018) x,
|
||||||
|
(* newf, *)
|
||||||
|
deaths = decode (addr + 0x0022) x,
|
||||||
|
n64dd_flag = decode (addr + 0x002C) x,
|
||||||
|
health_capacity = decode (addr + 0x002E) x,
|
||||||
|
health = decode (addr + 0x0030) x,
|
||||||
|
magic_level = decode (addr + 0x0032) x,
|
||||||
|
magic = decode (addr + 0x0033) x,
|
||||||
|
rupees = decode (addr + 0x0034) x,
|
||||||
|
sword_health = decode (addr + 0x0036) x,
|
||||||
|
navi_timer = decode (addr + 0x0038) x,
|
||||||
|
magic_acquired = decode (addr + 0x003A) x,
|
||||||
|
double_magic = decode (addr + 0x003C) x,
|
||||||
|
double_defense = decode (addr + 0x003D) x,
|
||||||
|
bgs_flag = decode (addr + 0x003E) x,
|
||||||
|
ocarina_game_reward = decode (addr + 0x003F) x,
|
||||||
|
child_equips = decode (addr + 0x0040) x,
|
||||||
|
adult_equips = decode (addr + 0x004A) x
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
instance pretty save_context begin
|
||||||
|
let pretty (SaveContext save_context) w =
|
||||||
|
let rec smul s n =
|
||||||
|
if n <= 0 then
|
||||||
|
""
|
||||||
|
else
|
||||||
|
s ^ (smul s (n - 1))
|
||||||
|
let x = w + 2
|
||||||
|
let prep = smul " " w
|
||||||
|
let header = "SaveContext {\n"
|
||||||
|
let entrance_index = header ^ prep ^ " entrance_index = " ^ (show save_context.entrance_index) ^ ",\n"
|
||||||
|
let link_age = entrance_index ^ prep ^ " link_age = " ^ (show save_context.link_age) ^ ",\n"
|
||||||
|
let cutscene_index = link_age ^ prep ^ " cutscene_index = " ^ (show save_context.cutscene_index) ^ ",\n"
|
||||||
|
let day_time = cutscene_index ^ prep ^ " day_time = " ^ (show save_context.day_time) ^ ",\n"
|
||||||
|
let night_flag = day_time ^ prep ^ " night_flag = " ^ (show save_context.night_flag) ^ ",\n"
|
||||||
|
let num_days = night_flag ^ prep ^ " num_days = " ^ (show save_context.num_days) ^ ",\n"
|
||||||
|
let claim_days = num_days ^ prep ^ " claim_days = " ^ (show save_context.claim_days) ^ ",\n"
|
||||||
|
let deaths = claim_days ^ prep ^ " deaths = " ^ (show save_context.deaths) ^ ",\n"
|
||||||
|
let n64dd_flag = deaths ^ prep ^ " n64dd_flag = " ^ (show save_context.n64dd_flag) ^ ",\n"
|
||||||
|
let health_capacity = n64dd_flag ^ prep ^ " health_capacity = " ^ (show save_context.health_capacity) ^ ",\n"
|
||||||
|
let health = health_capacity ^ prep ^ " health = " ^ (show save_context.health) ^ ",\n"
|
||||||
|
let magic_level = health ^ prep ^ " magic_level = " ^ (show save_context.magic_level) ^ ",\n"
|
||||||
|
let magic = magic_level ^ prep ^ " magic = " ^ (show save_context.magic) ^ ",\n"
|
||||||
|
let rupees = magic ^ prep ^ " rupees = " ^ (show save_context.rupees) ^ ",\n"
|
||||||
|
let sword_health = rupees ^ prep ^ " sword_health = " ^ (show save_context.sword_health) ^ ",\n"
|
||||||
|
let navi_timer = sword_health ^ prep ^ " navi_timer = " ^ (show save_context.navi_timer) ^ ",\n"
|
||||||
|
let magic_acquired = navi_timer ^ prep ^ " magic_acquired = " ^ (show save_context.magic_acquired) ^ ",\n"
|
||||||
|
let double_magic = magic_acquired ^ prep ^ " double_magic = " ^ (show save_context.double_magic) ^ ",\n"
|
||||||
|
let double_defense = double_magic ^ prep ^ " double_defense = " ^ (show save_context.double_defense) ^ ",\n"
|
||||||
|
let bgs_flag = double_defense ^ prep ^ " bgs_flag = " ^ (show save_context.bgs_flag) ^ ",\n"
|
||||||
|
let ocarina_game_reward = bgs_flag ^ prep ^ " ocarina_game_reward = " ^ (show save_context.ocarina_game_reward) ^ ",\n"
|
||||||
|
let child_equips = ocarina_game_reward ^ prep ^ " child_equips = " ^ (pretty save_context.child_equips x) ^ ",\n"
|
||||||
|
let adult_equips = child_equips ^ prep ^ " adult_equips = " ^ (pretty save_context.adult_equips x) ^ ", \n"
|
||||||
|
adult_equips ^ prep ^ "}"
|
||||||
|
end
|
Loading…
Reference in a new issue