OXYGENHUB
◆ main openmsx / share / scripts / _cheat.tcl
4.0 KiB · Tcl · last changed chore(): initial commit 1 month ago source blame history raw
1
package provide cheatfinder 0.5
2
3
set_help_text findcheat \
4
{Cheat finder version 0.5
5
6
Welcome to the openMSX cheat finder. Please visit
7
  http://forum.vampier.net/viewtopic.php?t=32 and
8
  http://www.youtube.com/watch?v=F11ltfkCtKo
9
for a quick tutorial
10
11
Usage:
12
  findcheat [-start] [-max n] [expression]
13
     -start     :  restart search, discard previously found addresses
14
     -max n     :  show max n results
15
     expression :  TODO
16
17
Examples:
18
  findcheat 42                 search for specific value
19
  findcheat bigger             search for increased values
20
  findcheat new == (2 * old)   search for doubled values
21
  findcheat new == (old - 1)   search for values decreased by 1
22
  findcheat                    repeat the results from the previous operation
23
  findcheat -start new < 10    restart and search for values less than 10
24
  findcheat -max 40 smaller    search for smaller values, show max 40 results
25
  findcheat -start addr>0xe000 && addr<0xefff search in defined memory locations
26
}
27
28
namespace eval cheat_finder {
29
30
variable max_num_results 15 ;# maximum to display cheats
31
variable mem
32
33
# build translation dictionary for convenience expressions
34
variable translate [dict create \
35
	""         "true"       \
36
	                        \
37
	"smaller"  "new < old"  \
38
	"less"     "new < old"  \
39
	"bigger"   "new > old"  \
40
	"more"     "new > old"  \
41
	"greater"  "new > old"  \
42
	                        \
43
	"le"       "new <= old" \
44
	"loe"      "new <= old" \
45
	"ge"       "new >= old" \
46
	"goe"      "new >= old" \
47
	"moe"      "new >= old" \
48
	                        \
49
	"equal"    "new == old" \
50
	"eq"       "new == old" \
51
	"notequal" "new != old" \
52
	"ne"       "new != old" \
53
	                        \
54
	"<="       "new <= old" \
55
	">="       "new >= old" \
56
	"<"        "new <  old" \
57
	">"        "new >  old" \
58
	"=="       "new == old" \
59
	"!="       "new != old"]
60
61
set_tabcompletion_proc findcheat [namespace code tab_cheat_type]
62
63
proc tab_cheat_type {args} {
64
	variable translate
65
66
	set result [dict keys $translate]
67
	lappend result "-start" "-max"
68
	return $result
69
}
70
71
# Restart cheat finder.
72
proc start {} {
73
	variable mem [dict create]
74
75
	set mymem [debug read_block memory 0 0x10000]
76
	binary scan $mymem c* values
77
	set addr 0
78
	foreach val $values {
79
		dict append mem $addr $val
80
		incr addr
81
	}
82
}
83
84
# Helper function to do the actual search.
85
# Returns a list of triplets (addr, old, new)
86
proc search {expression} {
87
	variable mem
88
89
	set result [list]
90
	dict for {addr old} $mem {
91
		set new [debug read memory $addr]
92
		#note: NO braces around $expression
93
		if $expression {
94
			dict set mem $addr $new
95
			lappend result [list $addr $old $new]
96
		} else {
97
			dict unset mem $addr
98
		}
99
	}
100
	return $result
101
}
102
103
# main routine
104
proc findcheat {args} {
105
	variable mem
106
	variable max_num_results
107
	variable translate
108
109
	# create mem dictionary
110
	if {![info exists mem]} start
111
112
	# parse options
113
	while (1) {
114
		switch -- [lindex $args 0] {
115
		"-max" {
116
			  set max_num_results [lindex $args 1]
117
			  set args [lrange $args 2 end]
118
		}
119
		"-start" {
120
			start
121
			set args [lrange $args 1 end]
122
		}
123
		"default" break
124
		}
125
	}
126
127
	# all remaining arguments form the expression
128
	set expression [join $args]
129
130
	if {[dict exists $translate $expression]} {
131
		# translate a convenience expression into a real expression
132
		set expression [dict get $translate $expression]
133
	} elseif {[string is integer $expression]} {
134
		# search for a specific value
135
		set expression "new == $expression"
136
	}
137
138
	# prefix 'old', 'new' and 'addr' with '$'
139
	set expression [string map {old $old new $new addr $addr} $expression]
140
141
	# search memory
142
	set result [search $expression]
143
144
	# display the result
145
	set num [llength $result]
146
	if {$num == 0} {
147
		return "No results left"
148
	} elseif {$num <= $max_num_results} {
149
		set output ""
150
		set sorted [lsort -integer -index 0 $result]
151
		foreach {addr old new} [join $sorted] {
152
			append output [format "0x%04X : %d -> %d\n" $addr $old $new]
153
		}
154
		return $output
155
	} else {
156
		return "$num results found -> Maximum result to display set to $max_num_results "
157
	}
158
}
159
160
namespace export findcheat
161
162
} ;# namespace cheat_finder
163
164
namespace import cheat_finder::*