-- object_openable - Attach to smart objects to extend them to be openable and closeable -- Requires an animstrip sprite beginning closed, ending open, and ping-pongs between the two states -- Created by: Patrick Ferland -- Created on: 08/26/2008 -- Revisions -- 08/26/2008 P.Ferland - New Script -- 08/28/2008 P.Ferland - Revisions and release -- 09/03/2008 P.Ferland - Added persistence (ignore reset), detect config changes, correct reset(caller_id) trigger -- 09/09/2008 P.Ferland - Updated messages to be more user-friendly -- Listens for these triggers -- use -- attach -- open -- close -- lock -- unlock -- opened (from self) -- closed (from self) -- die -- openable_end_transition (from self) -- set_script_param -- Broadcasts these triggers: -- openable_end_transition (to self) -- open (to self) -- close (to self) -- Constants OPENABLE_SCRIPT = '12071:41' -- Script Properties Define Properties() script_description = 'Openable' openable_open_sound_id = '12071:2' ExposeProperty('openable_open_sound_id', 'Sound to play when this thing opens?', 'soundId') PersistProperty('openable_open_sound_id') openable_close_sound_id = '12071:4' ExposeProperty('openable_close_sound_id', 'Sound to play when this thing closes?', 'soundId') PersistProperty('openable_close_sound_id') openable_unlock_sound_id = '12071:3' ExposeProperty('openable_unlock_sound_id', 'Sound to play when this thing is unlocked?', 'soundId') PersistProperty('openable_unlock_sound_id') openable_sound_volume = 100 ExposeProperty('openable_sound_volume', 'Volume for open and close sounds? (0-255)') SetPropRange('openable_sound_volume', 0, 255) PersistProperty('openable_sound_volume') openable_sound_radius = 15.0 ExposeProperty('openable_sound_radius', 'How far, in tiles, can open and close sounds be heard? (0-100, 0 for whole place)') SetPropRange('openable_sound_radius', 0, 100) PersistProperty('openable_sound_radius') openable_open_default = 0 ExposeProperty('openable_open_default', 'Is this thing open by default?', 'checkbox') PersistProperty('openable_open_default') openable_object_closeable = 1 ExposeProperty('openable_object_closeable', 'Can this thing be closed again after opening?', 'checkbox') PersistProperty('openable_object_closeable') openable_locked_default = 0 ExposeProperty('openable_locked_default', 'Is this thing locked by default?', 'checkbox') PersistProperty('openable_locked_default') openable_block_toggle = 1 ExposeProperty('openable_block_toggle', 'Toggle blocking when opened or closed (like a door)?', 'checkbox') PersistProperty('openable_block_toggle') openable_persist_state = 1 ExposeProperty('openable_persist_state', 'Does thing persist between server restarts?', 'checkbox') PersistProperty('openable_persist_state') -- Runtime Properties openable_open = 0 openable_locked = 0 openable_transition_trigger = 0 end -- Commands -- no commands -- Triggers -- Settings are changed Trigger set_script_param(caller, user_id, script_id, name, value) if (script_id == OPENABLE_SCRIPT) then if ( (name == 'openable_open_default') or (name == 'openable_locked_default') ) then reset_openable(self) end else set_openable_sprite(self) set_blocking(self) end end -- Object is used (by a player or other object) Trigger use(object) if (self.openable_open == 0) then SendTo(self, 'open', 0, object.id) else SendTo(self, 'close', 0, object.id) end end -- Set runtime properties to defaults when entering a Place (unless state persists) Trigger enter() if (self.openable_persist_state ~= 1) then reset_openable(self) else set_openable_sprite(self) set_blocking(self) end end -- Set runtime propertes to defaults when a reset() is received (unless state persists) Trigger reset(caller_id) if (type(caller_id) ~= 'number') then return end if (self.openable_persist_state ~= 1) then reset_openable(self) end end -- Lock the openable Trigger lock(object_id) local object = GetObjectById(object_id) if (object == nil) then return end self.openable_locked = 1 end -- Unlock the openable Trigger unlock(object_id) local object = GetObjectById(object_id) if (object == nil) then return end self.openable_locked = 0 play_sound(self, self.openable_unlock_sound_id) end -- End an open/close animation Trigger openable_end_transition(state, object_id) self.openable_open = state set_blocking(self) set_openable_sprite(self) self.openable_transition_trigger = 0 if (self.openable_open == 0) then SendTo(self, 'closed', 0, object_id) else SendTo(self, 'opened', 0, object_id) end end -- Attempt to open an openable object Trigger open(object_id) local object = GetObjectById(object_id) if (object == nil) then return end -- If a transition is playing, don't allow opening if (self.openable_transition_trigger ~= 0) then return end if (self.openable_locked == 0) then open_openable(self, object_id) else SendTo(object, 'request_unlock', 0, self.id) end end -- Attempt to close an openable object Trigger close(object_id) local object = GetObjectById(object_id) if (object == nil) then return end -- If a transition is playing, don't allow closing if (self.openable_transition_trigger ~= 0) then return end if (self.openable_object_closeable == 1) then if (self.openable_locked == 0) then close_openable(self, object_id) else SendTo(object, 'request_unlock', 0, self.id) end end end -- Local Functions - -- Open an openable object function open_openable(self, object_id) self.openable_open = 0 animate_openable(self, object_id) end -- Close an openable object function close_openable(self, object_id) self.openable_open = 1 animate_openable(self, object_id) end -- Play an object's open or close animation, as appropriate, and send the end_animation trigger function animate_openable(self, object_id) local direction = self.openable_open local sprite_id = '' local frames = 1 local anim_time = 0 sprite_id, frames, anim_time = get_sprite_info(self) if (direction == 0) then play_sound(self, self.openable_open_sound_id) else play_sound(self, self.openable_close_sound_id) end PlaySpriteAnim(self, 1, frames, direction, 'play_once', anim_time) self.openable_transition_trigger = SendTo(self, 'openable_end_transition', anim_time, 1 - direction, object_id) end -- Set a single sprite frame based on open/closed state function set_openable_sprite(self) local sprite_id = '' local frames = 1 local anim_time = 0 sprite_id, frames, anim_time = get_sprite_info(self) local strip_index = 1 if (self.openable_open ~= 0) then strip_index = frames end self.spriteFrame = strip_index end -- Get sprite ID, number of frames, and total animation time for current sprite function get_sprite_info(self) local sprite_id = self.spriteId local sprite = stylesheet.sprites[sprite_id] local frames = sprite.frames local anim_time = sprite.frames * sprite.interval return sprite_id, frames, anim_time end -- Play a sound based on current radial sound settings function play_sound(self, sound_id) if (self.openable_sound_radius == 0) then PlaySoundPlace(sound_id, self.openable_sound_volume, 0) else PlaySoundRadius(self, self.openable_sound_radius, sound_id, self.openable_sound_volume, 0) end end -- Reset runtime properties to default state function reset_openable(self) self.openable_open = self.openable_open_default self.openable_locked = self.openable_locked_default set_blocking(self) set_openable_sprite(self) end -- Toggle openable's blocking state, if configured to do so function set_blocking(self) if (self.openable_block_toggle == 1) then self.blocking = 1 - self.openable_open end end