_cheat.tcl 4.0 KB

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