_mog-overlay.tcl 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. namespace eval mog_overlay {
  2. variable num_enemies 16
  3. variable num_rocks 8
  4. variable mog_overlay_active false
  5. variable mog_editor_active false
  6. variable item_cache
  7. variable tomb_cache
  8. variable ladder_cache
  9. variable wall_cache
  10. variable demon_cache
  11. variable ep
  12. variable mouse1_pressed
  13. # Demon summon spells
  14. variable spell [list \
  15. "" "YOMAR" "ELOHIM" "HAHAKLA" "BARECHET" "HEOTYMEO" \
  16. "LEPHA" "NAWABRA" "ASCHER" "XYWOLEH" "HAMALECH"]
  17. # Demon Max Power
  18. variable demon_power [list -1 -1 24 40 64 112 72 56 64 80 80 248]
  19. # Item names
  20. variable items [list \
  21. "" "Arrow" "Ceramic Arrow" "Rolling Fire" "Fire" "Mine" \
  22. "Magnifying Glass" "Holy Water" "Cape" "Magical Rod" "World Map" \
  23. "Cross" "Great Key" "Necklace" "Crown" "Helm" "Oar" "Boots" "Doll" \
  24. "Robe" "Bell" "Halo" "Candle" "Armor" "Carpet" "Helmet" "Lamp" "Vase" \
  25. "Pendant" "Earrings" "Bracelet" "Ring" "Bible" "Harp" "Triangle" \
  26. "Trumpet Shell" "Pitcher" "Sabre" "Dagger" "Feather" "Bronze Shield" \
  27. "Bread and Water" "Salt" "Silver Shield" "Gold Shield" \
  28. "Quiver of Arrows" "Coins" "Keys"]
  29. variable enemy_names [list \
  30. "" "Gorilla" "Twinkle" "HorBlob" "Gate" "Fire Snake" "06" "Ring Worm" \
  31. "08" "09" "Knight" "Water Strider" "Sparky" "Fish" "Bat" "Pacman" \
  32. "Insect" "Hedgehog" "Rockman" "Cloud Demon" "Mudman" "Ill" \
  33. "Bird Dragon" "Egg Bird" "Worm" "Butterfly" "Snake's Fire" "Fireball" \
  34. "1C" "1D" "1E" "Goblin" "20" "Crawler" "Pea Shooter" "Trapwall" "Swine" \
  35. "Bones" "Living Helmet" "Owl" "Ectoplasm" "29" "Poltergeist" "Wizard" \
  36. "Shoe 1" "Frost Demon" "Bamboo Shoot" "Frog Plant" "Seahorse Demon" \
  37. "31" "32" "Armor's Dart" "Bally" "35" "36" "Great Butterfly" "VerBlob" \
  38. "39" "3A" "Moai Head Projectile" "Trickster Ghost" "Star" \
  39. "Flocking Bird" "3F" "Cyclop's Ghost" "41" "Maner" "Gero" "44" "45" \
  40. "46" "47" "48" "Huge Bat" "4A" "4B" "Fuzzball" "4D" "4E" "4F" "50" "51" \
  41. "Middle Bat" "Mini Bat" "Bone" "Small Bone" "Small Fireball" "57" \
  42. "Crab's Breath" "Seed" "5A" "5B" "Spiral Ball " "5D" "5E" "5F" "Maner's Arm" "61" \
  43. "Gero's Tongue" "63" "Shoe 2" "Breath" "66" "Protectors"]
  44. set_help_text toggle_mog_overlay \
  45. "Shows OSD widgets that help you play The Maze of Galious. Only useful if you
  46. are actually running this game... If you are not, you may get a lot of weird
  47. stuff on your screen :) The script shows the Great Demon summon spells, ladders
  48. which will disappear, walls which will grow, hitpoints of enemies, hidden
  49. items, etc.\nSee also toggle_mog_editor."
  50. set_help_text toggle_mog_editor \
  51. "Gives you mouse bindings to fool around in The Maze of Galious. Only useful if
  52. you are actually running this game... If you are not, you may get a lot of
  53. weird stuff on your screen :) With this editor, you can draw walls with one
  54. mouse button and put Popolon on your position of choice with the other. Needs
  55. the MoG overlay to work, see toggle_mog_overlay."
  56. #Init Overlays
  57. proc init {} {
  58. variable num_enemies
  59. variable num_rocks
  60. variable label_color
  61. variable label_text_color
  62. variable item_cache
  63. variable tomb_cache
  64. variable ladder_cache
  65. variable wall_cache
  66. variable demon_cache
  67. variable max_ep
  68. osd_widgets::msx_init mog
  69. for {set i 0} {$i < $num_enemies} {incr i} {
  70. osd_widgets::create_power_bar mog.powerbar$i 14 2 0xff0000ff 0x00000080 0xffffffff
  71. }
  72. osd_widgets::create_power_bar mog.item 16 16 0x00000000 0xff770020 0xffffffff
  73. set item_cache 0
  74. osd create rectangle mog.tomb -rely 999 -w 16 -h 16 -rgba 0x00000080
  75. osd create text mog.tomb.text -x 1 -y 1 -size 5 -rgb 0xffffff
  76. set tomb_cache 0
  77. osd create rectangle mog.ladder -rely 999 -relw 16 -rgba 0xffffff80
  78. set ladder_cache 0
  79. osd create rectangle mog.wall -rely 999 -relw 8 -relh 24 -rgba 0x00ffff80
  80. set wall_cache 0
  81. osd create rectangle mog.wall2 -rely 999 -relw 32 -relh 24 -rgba 0x00000080
  82. osd create text mog.wall2.text -x 1 -y 1 -size 4 -rgb 0xffffff
  83. for {set i 0} {$i < $num_rocks} {incr i} {
  84. osd create rectangle mog.rock$i -rely 999 -w 24 -h 4 -rgba 0x0000ff80
  85. osd create text mog.rock$i.text -x 0 -y 0 -size 4 -rgb 0xffffff
  86. }
  87. osd_widgets::create_power_bar mog.demon 48 4 0x2bdd2bff 0x00000080 0xffffffff
  88. set demon_cache 0
  89. # Enemy Power
  90. for {set i 0} {$i < $num_enemies} {incr i} {set max_ep($i) 0}
  91. }
  92. # Update the overlays
  93. proc update_overlay {} {
  94. variable mog_overlay_active
  95. variable num_enemies
  96. variable num_rocks
  97. variable label_color
  98. variable label_text_color
  99. variable item_cache
  100. variable tomb_cache
  101. variable ladder_cache
  102. variable wall_cache
  103. variable demon_cache
  104. variable spell
  105. variable demon_power
  106. variable items
  107. variable enemy_names
  108. variable max_ep
  109. if {!$mog_overlay_active} return
  110. #see if not in demo
  111. if {[peek 0xe002] != 64} {osd configure mog -y 999} else {osd_widgets::msx_update mog}
  112. for {set i 0; set addr 0xe800} {$i < $num_enemies} {incr i; incr addr 0x20} {
  113. set enemy_type [peek $addr]
  114. set enemy_hp [peek [expr {$addr + 0x10}]]
  115. # If enemy's power is 0 set max power to 0
  116. if {$enemy_hp == 0 && $max_ep($i) > 0} {set max_ep($i) 0}
  117. if {$enemy_type > 0 && $enemy_hp > 0 && $enemy_hp < 200} {
  118. #Set Max Power Recorded for Enemy
  119. if {$max_ep($i) < $enemy_hp} {set max_ep($i) $enemy_hp}
  120. set pos_x [expr { 8 + [peek [expr {$addr + 7}]]}]
  121. set pos_y [expr {-6 + [peek [expr {$addr + 5}]]}]
  122. set power [expr {1.00 * $enemy_hp / $max_ep($i)}]
  123. set text [format "%s (%d): %d/%d" [lindex $enemy_names $enemy_type] $i $enemy_hp $max_ep($i)]
  124. osd_widgets::update_power_bar mog.powerbar$i $pos_x $pos_y $power $text
  125. } else {
  126. osd_widgets::hide_power_bar mog.powerbar$i
  127. }
  128. }
  129. set new_item [peek 0xe740]
  130. if {$new_item != $item_cache} {
  131. set item_cache $new_item
  132. if {$item_cache} {
  133. set height [expr {($item_cache < 7) ? 8 : 16}]
  134. osd configure mog.item -relh $height
  135. osd configure mog.item.text -text [lindex $items $item_cache]
  136. osd configure mog.item -relx [peek 0xe743] -rely [peek 0xe742]
  137. } else {
  138. osd configure mog.item -rely 999
  139. }
  140. }
  141. set new_tomb [peek 0xe678]
  142. if {$new_tomb != $tomb_cache} {
  143. set tomb_cache $new_tomb
  144. if {($tomb_cache > 0) && ($tomb_cache <= 10)} {
  145. osd configure mog.tomb.text -text "[lindex $spell $tomb_cache]"
  146. osd configure mog.tomb -relx [peek 0xe67a] -rely [peek 0xe679]
  147. } else {
  148. osd configure mog.tomb -rely 999
  149. }
  150. }
  151. #todo: see what the disappear trigger is (up, down, either)
  152. set new_ladder [expr {[peek 0xec00] | [peek 0xec07]}]
  153. if {$new_ladder != $ladder_cache} {
  154. set ladder_cache $new_ladder
  155. if {$ladder_cache != 0} {
  156. osd configure mog.ladder -relx [peek 0xec02] -rely [peek 0xec01] \
  157. -relh [expr {8 * ([peek 0xec03] & 31)}]
  158. } else {
  159. osd configure mog.ladder -rely 999
  160. }
  161. }
  162. set new_wall [peek 0xeaa0]
  163. if {$new_wall != $wall_cache} {
  164. set wall_cache $new_wall
  165. if {$wall_cache != 0} {
  166. osd configure mog.wall -relx [peek 0xeaa3] -rely [peek 0xeaa2]
  167. } else {
  168. osd configure mog.wall -rely 999
  169. }
  170. }
  171. if {[peek 0xea20] != 0} {
  172. set text [format "Wall (%02d)" [peek 0xea23]]
  173. osd configure mog.wall2 -relx [peek 0xea22] -rely [peek 0xea21]
  174. osd configure mog.wall2.text -text $text
  175. } else {
  176. osd configure mog.wall2 -rely 999
  177. }
  178. for {set i 0; set addr 0xec30} {$i < $num_rocks} {incr i; incr addr 8} {
  179. if {[peek $addr] > 0} {
  180. set pos_x [expr { 8 + [peek [expr {$addr + 3}]]}]
  181. set pos_y [expr {-6 + [peek [expr {$addr + 2}]]}]
  182. set rock_hp [peek [expr {$addr + 6}]]
  183. set text [format "Rock %d (%02d)" $i $rock_hp]
  184. osd configure mog.rock$i -relx $pos_x -rely $pos_y
  185. osd configure mog.rock$i.text -text $text
  186. } else {
  187. osd configure mog.rock$i -rely 999
  188. }
  189. }
  190. if {([peek 0xe0d2] != 0) && ([peek 0xe710] != 0)} {
  191. osd configure mog.demon -relx 112 -rely 26
  192. # let's not print text, it destroys a replay
  193. # print_mog_text 1 1 "Now Fighting [lindex $spell [expr {[peek 0xe041] - 1}]]"
  194. set new_demon [peek 0xe710]
  195. if {$new_demon != $demon_cache} {
  196. set demon_cache $new_demon
  197. set demon_max [lindex $demon_power [peek 0xe041]]
  198. if {$demon_max > 0} {
  199. set power [expr {$demon_cache * ([peek 0xe076] + 1.0) / $demon_max}]
  200. osd configure mog.demon.bar -relw $power
  201. }
  202. }
  203. } else {
  204. osd configure mog.demon -rely 999
  205. }
  206. after frame [namespace code update_overlay]
  207. }
  208. # better don't use this if you want to keep your replay OK
  209. proc print_mog_text {x y text} {
  210. set text [string tolower $text]
  211. for {set i 0} {$i < [string length $text]} {incr i} {
  212. scan [string range $text $i $i] "%c" ascii
  213. incr ascii -86
  214. if {$ascii >= -38 && $ascii <= -29} {incr ascii 39}
  215. if {$ascii < 0} {set ascii 0}
  216. poke [expr {0xed80 + $x + $y * 32 + $i}] $ascii
  217. }
  218. }
  219. proc toggle_mog_overlay {} {
  220. variable mog_overlay_active
  221. variable mog_editor_active
  222. set mog_overlay_active [expr {!$mog_overlay_active}]
  223. if {$mog_overlay_active} {
  224. init
  225. update_overlay
  226. osd::display_message "MoG overlay activated" info
  227. return "MoG overlay activated!"
  228. } else {
  229. set retval ""
  230. if {$mog_editor_active} {
  231. set retval "[toggle_mog_editor]\n"
  232. }
  233. osd destroy mog
  234. osd::display_message "MoG overlay deactivated" info
  235. return "${retval}MoG overlay deactivated."
  236. }
  237. }
  238. # MoG editor
  239. # Separated from MoG overlay, because the overlay is useful for TASing and the
  240. # editor will ruin your replay
  241. proc draw_block {} {
  242. osd_widgets::msx_update "mog"
  243. lassign [osd info "mog" -mousecoord] x y
  244. poke [expr {0xed80 + int($x / 8) + int(($y - 32) / 8) * 32}] 240
  245. if {$mog_overlay::mouse1_pressed} {after frame mog_overlay::draw_block}
  246. }
  247. proc put_popolon {} {
  248. osd_widgets::msx_update "mog"
  249. lassign [osd info "mog" -mousecoord] x y
  250. poke 0xe507 [utils::clip 0 255 [expr {int($x)}]]
  251. poke 0xe505 [utils::clip 0 212 [expr {int($y)}]]
  252. }
  253. proc toggle_mog_editor {} {
  254. variable mog_editor_active
  255. variable mog_overlay_active
  256. if {!$mog_editor_active && !$mog_overlay_active} {
  257. error "You need to have the MoG overlay active to use this editor!"
  258. }
  259. set mog_editor_active [expr {!$mog_editor_active}]
  260. if {$mog_editor_active} {
  261. bind -layer mog_editor "mouse button1 down" {
  262. set mog_overlay::mouse1_pressed true
  263. mog_overlay::draw_block
  264. }
  265. bind -layer mog_editor "mouse button1 up" {
  266. set mog_overlay::mouse1_pressed false
  267. }
  268. bind -layer mog_editor "mouse button3 down" {
  269. mog_overlay::put_popolon
  270. }
  271. activate_input_layer mog_editor
  272. return "MoG editor activated!"
  273. } else {
  274. deactivate_input_layer mog_editor
  275. return "MoG editor deactivated."
  276. }
  277. return ""
  278. }
  279. namespace export toggle_mog_overlay
  280. namespace export toggle_mog_editor
  281. };# namespace mog_overlay
  282. namespace import mog_overlay::*