1-- Initialize hero behavior specific to this quest. 2 3require("scripts/multi_events") 4require("scripts/utils") 5local all = require("scripts/meta/all") 6 7local hero_meta = sol.main.get_metatable("hero") 8 9local function initialize_hero_features(game) 10 11 local hero = game:get_hero() 12 -- In this game you can never die 13 hero:set_invincible() 14 hero:set_walking_speed(80) 15 -- Set max level of stamina 16 game:set_max_magic(20) 17 18 function silence_music() 19 -- silence music for brandish SFX 20 local volume = sol.audio.get_music_volume() 21 sol.audio.set_music_volume(0) 22 log("Music volume: 0") 23 local timer = sol.timer.start(2600, function() 24 log("Music volume: 100") 25 sol.audio.set_music_volume(volume) 26 end) 27 timer:set_suspended_with_map(false) 28 end 29 30 -- The hero can only swing the sword, nothing else 31 function hero:on_state_changed(state) 32 if state == "sword loading" 33 or state == "sword tapping" 34 or state == "sword spin attack" then 35 hero:freeze() 36 hero:unfreeze() 37 end 38 end 39 40 -- Return the hero's position relative to the screen. 41 function hero:get_screen_position() 42 local camera = self:get_map():get_camera() 43 local hero_x, hero_y = self:get_position() 44 local camera_x, camera_y = camera:get_position() 45 return hero_x-camera_x, hero_y-camera_y 46 end 47 48 -- Tracks the position of the hero and updates the callback every frame 49 function hero:track(callback) 50 hero:register_event("on_position_changed", function(self, x, y, z) 51 callback(x, y, z) 52 end) 53 end 54 55 -- The hero will brandish an item without obtaining it. 56 -- Reimplementation of hero:start_treasure() except you don't get the item. 57 function hero:brandish(item_key, variant) 58 self:freeze() 59 silence_music() 60 sol.audio.play_sound("treasure") 61 62 -- Set some variables 63 if not variant then variant = 1 end 64 local x, y, z = self:get_position() 65 local item = hero:get_game():get_item(item_key) 66 assert(item) 67 68 -- Set the hero's sprite 69 local hero_sprite = hero:get_sprite() 70 hero_sprite:set_animation("brandish") 71 72 -- Create a map entity for the item to show during brandishing 73 local map = item:get_map() 74 local item_entity = map:create_custom_entity({ 75 sprite = "entities/items", 76 direction = variant - 1, 77 x=0, y=0, layer=0, width=16, height=16 78 }) 79 local item_sprite = item_entity:get_sprite() 80 item_sprite:set_animation(item_key) 81 local ox, oy = item_sprite:get_origin() 82 item_entity:set_position(x, y-28+oy, z+1) 83 84 -- Start item dialog 85 local game = item:get_game() 86 game:start_dialog("_treasure." .. item_key .. "." .. variant, function() 87 -- End 88 self:unfreeze() 89 hero_sprite:set_animation("stopped") 90 item_entity:remove() 91 end) 92 end 93 94 -- Make the hero blink and update 95 function hero:on_created() 96 -- Make the hero blink her eyes every 6 seconds 97 sol.timer.start(self, 6000, function() 98 99 local sprite = self:get_sprite() 100 -- Blink conditions 101 local is_stopped = sprite:get_animation() == "stopped" 102 local is_climbing = self:get_tunic_sprite_id() == "hero/tunic1-climbing" 103 104 if is_stopped and not is_climbing then 105 sprite:set_animation("blink", "stopped") 106 end 107 108 return true -- loop forever 109 end) 110 111 -- Make the hero be updated every 10 ms 112 sol.timer.start(self, 10, function() 113 self:update() 114 return true 115 end) 116 end 117 118 function hero:on_state_changed(new_state_name) 119 if new_state_name == "treasure" then 120 local item_star = self:create_sprite("menus/item_star", "item_star") 121 item_star:set_ignore_suspend() 122 self:bring_sprite_to_back(item_star) 123 124 -- HACK: Layer the tunic sprite on again because 125 -- setting the sprite order doesn't affect the hero 126 -- https://gitlab.com/solarus-games/solarus/issues/1348#note_142442035 127 local tunic_sprite = hero:get_sprite("tunic") 128 local tunic_top = hero:create_sprite(tunic_sprite:get_animation_set(), "tunic_top") 129 tunic_top:set_direction(tunic_sprite:get_direction()) 130 tunic_top:set_animation("brandish") 131 -- END HACK 132 133 force_animation(item_star, true) 134 silence_music() 135 end 136 end 137 138 function hero:on_state_changing(state_name, next_state_name) 139 local item_star = self:get_sprite("item_star") 140 local tunic_top = self:get_sprite("tunic_top") -- HACK 141 if state_name == "treasure" then 142 if item_star then self:remove_sprite(item_star) end 143 if tunic_top then self:remove_sprite(tunic_top) end -- HACK 144 end 145 end 146 147 -- Rachel has a thought bubble animation 148 function hero:think() 149 all.think(self) 150 force_animation(self:get_sprite("thought_bubble")) 151 end 152 153 -- Check if Rachel changed its ground below 154 function hero:update() 155 local current_ground = hero:get_ground_below() 156 if self.previous_ground and self.previous_ground ~= current_ground then 157 self:on_ground_below_changed(current_ground) 158 end 159 self.previous_ground = current_ground 160 end 161 162 -- Make Rachel change its tunic if she is climbing 163 function hero:on_ground_below_changed(ground_below) 164 if ground_below == "ladder" then 165 self:set_tunic_sprite_id("hero/tunic1-climbing") 166 else 167 self:set_tunic_sprite_id("hero/tunic1") 168 end 169 end 170end 171 172-- Set up Eldran hero sprite on any game that starts. 173local game_meta = sol.main.get_metatable("game") 174game_meta:register_event("on_started", initialize_hero_features) 175return true 176