SpeakerType = { NONE = 0, MAN = 1, WOMAN = 2, BOY = 3, GIRL = 4, NONHUMAN = 5 } Direction = { UP = 0, UP_RIGHT = 1, RIGHT = 2, DOWN_RIGHT = 3, DOWN = 4, DOWN_LEFT = 5, LEFT = 6, UP_LEFT = 7 } CharacterState = { STILL = 0, WALKING = 1, CROUCHING = 2, RUNNING = 3 } SpriteLayer = { MASK = 0, NORMAL = 1, ABOVE = 2 } BehaviourType = { NONE = 0, WANDER = 1, PATH = 2, FOLLOW = 3 } CutsceneOptions = { DO_NOT_CHANGE_ANIMATION = 1 -- Prevents player party animation being set to "frozen" at the start of a cutscene or "still" at the end } ChangeMapOptions = { DO_NOT_FADE = 1, -- Prevents fading to and from black DO_NOT_CHANGE_MUSIC = 2 -- Prevents stopping or starting music as part of the map change } PathfindingOptions = { CARDINAL_DIRECTIONS_ONLY = 1 } gamestate = {} --- Yields until the specified amount of time has passed. -- @param time in milliseconds function Delay(time) while time > 0 do time = time - coroutine.yield() end end --- Starts a cutscene. -- This takes care of showing the cutscene bars, as well as halting character -- movement. It does not block. See CutsceneOptions for modifiers. function StartCutscene(options) options = options or 0 local playerId = getPlayerSprite() local playerSprite = getSprite(playerId) playerSprite.controllable = false character():halt(playerId) if (options & CutsceneOptions.DO_NOT_CHANGE_ANIMATION == 0) then SetPartyAnimation(playerId, "frozen") end message():displayCutsceneBars() local allSprites = getAllSprites() for k,v in pairs(allSprites) do getSprite(v).paused = true end end --- Queues a message for display. -- Non-blocking! If you want to block until the message has been fully -- revealed, use WaitForEndOfMessage(). -- @param msg the text of the message -- @param name the name of the character speaking (leave blank to not show a character name) -- @param type the SpeakerType for the character, which determines which beep sound is played, if any function DisplayMessage(msg, name, type) message():displayMessage(msg, name, type) end --- Queues a choice prompt for the player. -- This should be called after DisplayMessage(), as it is not valid for a choice -- prompt to be the first line of the text box. This also does not block. You -- should use WaitForEndOfMessage() after this. -- @param one the text of the first option -- @param two the text of the second option function ShowChoice(one, two) message():showChoice(one, two) end --- Gets the result of the last choice prompt. -- @return 0 for the left choice, 1 for the right choice function GetChoiceSelection() return message():getChoiceSelection() end --- Yields until all queued messages / choice prompts have been dismissed. -- This does not hide the cutscene bars, nor does it wait for them to hide. function WaitForEndOfMessage() while (message().isMessageActive) do coroutine.yield() end end --- Hides the cutscene bars. -- This also re-enables player movement. See CutsceneOptions for modifiers. function HideCutsceneBars(options) options = options or 0 WaitForEndOfMessage() message():hideCutsceneBars() local playerId = getPlayerSprite() local playerSprite = getSprite(playerId) playerSprite.controllable = true if (options & CutsceneOptions.DO_NOT_CHANGE_ANIMATION == 0) then SetPartyAnimation(playerId, "still") end local allSprites = getAllSprites() for k,v in pairs(allSprites) do getSprite(v).paused = false end end --- Unpauses a sprite's movement. -- Use this during cutscenes to allow the sprite's movement to be controlled -- either by the InputSystem or the BehaviourSystem. function UnpauseSprite(spriteName) local spriteId = getSpriteByAlias(spriteName) local sprite = getSprite(spriteId) sprite.paused = false end --- Re-pauses a sprite's movement. -- Use this after UnpauseSprite() when you are done moving the sprite. function PauseSprite(spriteName) local spriteId = getSpriteByAlias(spriteName) local sprite = getSprite(spriteId) sprite.paused = true end function GetPosition(spriteName) local spriteId = getSpriteByAlias(spriteName) local sprite = getSprite(spriteId) return sprite.loc end function SetPosition(spriteName, x, y) local spriteId = getSpriteByAlias(spriteName) transform():moveSprite(spriteId, vec2i.new(x, y)) end --- Moves a sprite to the specified warp point. function MoveSpriteToWarp(spriteName, warp) local spriteId = getSpriteByAlias(spriteName) local warpPos = getMap():getWarpPoint(warp) transform():moveSprite(spriteId, warpPos) end function SetDirection(spriteName, dir) local spriteId = getSpriteByAlias(spriteName) animation():setSpriteDirection(spriteId, dir) end function SetAnimation(spriteName, animName) local spriteId = getSpriteByAlias(spriteName) animation():setSpriteAnimation(spriteId, animName) end function WaitForAnimation(spriteName) local spriteId = getSpriteByAlias(spriteName) local sprite = getSprite(spriteId) repeat coroutine.yield() until sprite.animFinished end function Halt(spriteName) local spriteId = getSpriteByAlias(spriteName) character():halt(spriteId) end function PlaySound(filename) mixer():playSound("../res/sfx/" .. filename) end function LoopSound(filename) return mixer():loopSound("../res/sfx/" .. filename) end function StopSound(soundId) mixer():stopChannel(soundId) end function FadeToBlack(length) effect():fadeScreen(length, 1.0) repeat coroutine.yield() until effect():isScreenFadeComplete() end function RemoveFadeout(length) effect():fadeScreen(length, 0.0) repeat coroutine.yield() until effect():isScreenFadeComplete() end function FadeMap(length, amount) effect():fadeMap(length, amount) end function WaitForMapFade() while not effect():isMapFadeComplete() do coroutine.yield() end end function ShakeCamera(period) effect():shakeCamera(period) end function StopShakingCamera() effect():stopShakingCamera() end function PanToSprite(spriteName, length) local spriteId = getSpriteByAlias(spriteName) camera():panToSprite(spriteId, length) end function WaitForPan() while camera():isPanning() do coroutine.yield() end end function CameraFollowSprite(spriteName) local spriteId = getSpriteByAlias(spriteName) camera():setFollowingSprite(spriteId) camera():unlockCamera() end function ReturnCamera(length) local playerId = getPlayerSprite() camera():panToSprite(playerId, length) while camera():isPanning() do coroutine.yield() end camera():setFollowingSprite(playerId) camera():unlockCamera() end function SetPartyDirection(spriteId, direction) animation():setSpriteDirection(spriteId, direction) local sprite = getSprite(spriteId) for i=1,#sprite.followers do animation():setSpriteDirection(sprite.followers[i], direction) end end function SetPartyAnimation(spriteId, animName) animation():setSpriteAnimation(spriteId, animName) local sprite = getSprite(spriteId) for i=1,#sprite.followers do animation():setSpriteAnimation(sprite.followers[i], animName) end end function ChangeMap(map, warp, options) options = options or 0 local playerId = getPlayerSprite() local playerSprite = getSprite(playerId) local direction = playerSprite.dir DisablePlayerControl() if (options & ChangeMapOptions.DO_NOT_FADE == 0) then FadeToBlack(150) end loadMap(map) character():transplantParty(playerId, getMap():getWarpPoint(warp), direction) if (options & ChangeMapOptions.DO_NOT_CHANGE_MUSIC == 0) then if (mixer():isPlayingMusic() and not getMap():hasMusic()) then mixer():fadeoutMusic(150) elseif (getMap():hasMusic() and (not mixer():isPlayingMusic() or not (mixer():getPlayingTrack() == getMap():getMusic()))) then mixer():playMusic(getMap():getMusic(), 150) end end coroutine.yield() if (options & ChangeMapOptions.DO_NOT_FADE == 0) then RemoveFadeout(150) end EnablePlayerControl() end function CreateAnimatedSpriteAtPosition(alias, character, x, y, animName, direction, layer) local spriteId = emplaceSprite(alias) transform():initSprite(spriteId, x, y, layer) animation():initSprite(spriteId, "../res/sprites/" .. character .. "_anim.txt") animation():setSpriteDirection(spriteId, direction) animation():setSpriteAnimation(spriteId, animName) end function CreateAnimatedSpriteAtWarpPoint(alias, character, warp, animName, direction, layer) local spriteId = emplaceSprite(alias) local loc = getMap():getWarpPoint(warp) transform():initSprite(spriteId, loc:x(), loc:y(), layer) animation():initSprite(spriteId, "../res/sprites/" .. character .. "_anim.txt") animation():setSpriteDirection(spriteId, direction) animation():setSpriteAnimation(spriteId, animName) end function DestroyNamedSprite(alias) local spriteId = getSpriteByAlias(alias) destroySprite(spriteId) end function AliasForSpriteExpression(spriteName) return "expression (" .. spriteName .. ")" end function ShowExpression(spriteName, expression) local spriteId = getSpriteByAlias(spriteName) local sprite = getSprite(spriteId) local animFrame = sprite:getCurrentFrame() local x = sprite.loc:x() local y = sprite.loc:y() - animFrame.center:y() CreateAnimatedSpriteAtPosition(AliasForSpriteExpression(spriteName), "expression", x, y, expression, Direction.DOWN, SpriteLayer.ABOVE) end function RemoveExpression(spriteName) DestroyNamedSprite(AliasForSpriteExpression(spriteName)) end --- Turns on clipping for the player. -- This allows walking through solid objects. For debug only! function StartClipping() local playerId = getPlayerSprite() local playerSprite = getSprite(playerId) playerSprite.clipping = true end --- Turns off clipping for the player. -- For debug only! function StopClipping() local playerId = getPlayerSprite() local playerSprite = getSprite(playerId) playerSprite.clipping = false end --- Turns off crouching (and thus running) for the player. function PreventCrouching() local playerId = getPlayerSprite() local playerSprite = getSprite(playerId) playerSprite.cantCrouch = true end --- Undoes the effect of PreventCrouching(). function AllowCrouching() local playerId = getPlayerSprite() local playerSprite = getSprite(playerId) playerSprite.cantCrouch = false end --- Makes a sprite start bobbing up and down (for underwater). -- This only applies when the sprite is on a normal medium (so, not on ladders). function StartBobbing(spriteName) local spriteId = getSpriteByAlias(spriteName) local sprite = getSprite(spriteId) sprite.bobsWhenNormal = true end --- Makes a sprite stop bobbing up and down. function StopBobbing(spriteName) local spriteId = getSpriteByAlias(spriteName) local sprite = getSprite(spriteId) sprite.bobsWhenNormal = false end --- Sets the animation slowdown for a sprite. -- @param spriteName the alias of the sprite to modify -- @param amount the number of animation frames needed to advance the sprite's animation (1 means the effect is disabled) function SetAnimationSlowdown(spriteName, amount) local spriteId = getSpriteByAlias(spriteName) local sprite = getSprite(spriteId) sprite.animSlowdown = amount end --- Sets the opacity of the sprite when it is rendered. -- @param spriteName the alias of the sprite to modify -- @param amount a value from 0.0 to 1.0 function SetOpacity(spriteName, amount) local spriteId = getSpriteByAlias(spriteName) local sprite = getSprite(spriteId) sprite.opacity = amount end --- Fades out the given sprite. function FadeOutSprite(spriteName) local spriteId = getSpriteByAlias(spriteName) local sprite = getSprite(spriteId) sprite.shouldBeFadedIn = false end --- Fades out the given sprite. function FadeInSprite(spriteName) local spriteId = getSpriteByAlias(spriteName) local sprite = getSprite(spriteId) sprite.shouldBeFadedIn = true end --- Sets the enclosure zone for a sprite. -- The sprite will be prevented from exiting the area defined by that zone. function AddEnclosureZone(spriteName, zone) local spriteId = getSpriteByAlias(spriteName) local sprite = getSprite(spriteId) sprite.enclosureZone = zone end --- Removes the enclosure zone for the specified sprite. -- This allows the sprite to move outside of the confines of the zone. function RemoveEnclosureZone(spriteName) local spriteId = getSpriteByAlias(spriteName) local sprite = getSprite(spriteId) sprite.enclosureZone = "" end --- Set a sprite on a path to the specified location. function DirectSpriteToLocation(spriteName, warpPoint, options) options = options or 0 local spriteId = getSpriteByAlias(spriteName) local dest = getMap():getWarpPoint(warpPoint) behaviour():directSpriteToLocation(spriteId, dest, options) end --- Blocks until the specified sprite has completed their path. function WaitForSpritePath(spriteName) local spriteId = getSpriteByAlias(spriteName) while (behaviour():isFollowingPath(spriteId)) do coroutine.yield() end end --- Sets a sprite to wander. function StartWandering(spriteName) local spriteId = getSpriteByAlias(spriteName) local sprite = getSprite(spriteId) sprite.behaviourType = BehaviourType.WANDER end --- Turns off the sprite's behaviour. function DisableBehaviour(spriteName) local spriteId = getSpriteByAlias(spriteName) local sprite = getSprite(spriteId) sprite.behaviourType = BehaviourType.NONE end --- Directs a sprite to start following a target sprite. function FollowSprite(spriteName, targetName) local spriteId = getSpriteByAlias(spriteName) local targetId = getSpriteByAlias(targetName) local sprite = getSprite(spriteId) sprite.followSpriteId = targetId sprite.behaviourType = BehaviourType.FOLLOW end --- Makes a sprite stop following whatever sprite it was following. function StopFollowingSprite(spriteName) local spriteId = getSpriteByAlias(spriteName) local sprite = getSprite(spriteId) sprite.followSpriteId = -1 sprite.behaviourType = BehaviourType.NONE end --- Fades out the currently playing music. -- This does not block. If you want it to block, call Delay for the same amount -- of time. -- @param length the fadeout time in milliseconds function FadeoutMusic(length) mixer():fadeoutMusic(length) end --- Plays the specified track. -- @param song the name of the song to play -- @param length the time in milliseconds to fade in. if left blank, the track starts immediately function PlayMusic(song, length) length = length or 0 mixer():playMusic(song, length) end --- Makes the player sprite non-controllable. function DisablePlayerControl() local playerId = getPlayerSprite() local playerSprite = getSprite(playerId) playerSprite.controllable = false end --- Makes the player sprite controllable again. function EnablePlayerControl() local playerId = getPlayerSprite() local playerSprite = getSprite(playerId) playerSprite.controllable = true end --- Makes the specified sprite face toward the †arget sprite. -- This version of the function uses any of the eight directions. -- @param spriteName the name of the sprite to change the direction of -- @param targetName the name of the sprite to face toward function FaceTowardSprite(spriteName, targetName) local spriteId = getSpriteByAlias(spriteName) local targetId = getSpriteByAlias(targetName) local sprite = getSprite(spriteId) local target = getSprite(targetId) local diff = vec2i.new(target.loc:x() - sprite.loc:x(), target.loc:y() - sprite.loc:y()) local dir = directionFacingPoint(diff) SetDirection(spriteName, dir) end --- Makes the specified sprite's entire party face toward the †arget sprite. -- This version of the function uses any of the eight directions. -- @param spriteName the name of the sprite to change the direction of -- @param targetName the name of the sprite to face toward function FacePartyTowardSprite(spriteName, targetName) FaceTowardSprite(spriteName, targetName) local sprite = getSprite(getSpriteByAlias(spriteName)) for i=1,#sprite.followers do local follower = getSprite(sprite.followers[i]) FaceTowardSprite(follower.alias, targetName) end end --- Makes the specified sprite face toward the †arget sprite. -- This version of the function uses the closest cardinal direction. -- @param spriteName the name of the sprite to change the direction of -- @param targetName the name of the sprite to face toward function FaceTowardSpriteCardinally(spriteName, targetName) local spriteId = getSpriteByAlias(spriteName) local targetId = getSpriteByAlias(targetName) local sprite = getSprite(spriteId) local target = getSprite(targetId) local diff = vec2i.new(target.loc:x() - sprite.loc:x(), target.loc:y() - sprite.loc:y()) local dir = cardinalDirectionFacingPoint(diff) SetDirection(spriteName, dir) end --- Detaches the sprite's followers and erases their following trails. function BreakUpParty(spriteName) local spriteId = getSpriteByAlias(spriteName) character():breakUpParty(spriteId) end --- Makes the specified sprite solid. -- This means that other sprites will be blocked if they collide with this one. function MakeSpriteSolid(spriteName) local spriteId = getSpriteByAlias(spriteName) local sprite = getSprite(spriteId) sprite.solid = true end --- Makes the specified sprite not solid. -- This means that other sprites will not be blocked if they collide with this -- one. function MakeSpriteNotSolid(spriteName) local spriteId = getSpriteByAlias(spriteName) local sprite = getSprite(spriteId) sprite.solid = false end --- Sets the sprite's movement speed. -- As a reference: 1 is slow (good for NPCs), 2 is Lucas's default walking speed function SetMovementSpeed(spriteName, speed) local spriteId = getSpriteByAlias(spriteName) local sprite = getSprite(spriteId) sprite.movementSpeed = speed end --- Performs the beginning of the exit area transition. -- This does the circle effect and plays the sound effect. The circle effect -- then gets removed and replaced with a screen fade. function ExitAreaTransition() DisablePlayerControl() --character():halt(getPlayerSprite()) coroutine.yield() PlaySound("exit_area.wav") FadeoutMusic(679) effect():circleTransition(679, 1.0) while not effect():isCircleTransitionComplete() do coroutine.yield() end character():halt(getPlayerSprite()) FadeToBlack(1) effect():circleTransition(1, 0.0) Delay(1000) end --- Checks whether a sprite is in a zone. -- @param spriteName the name of the sprite to locate -- @param zoneName the name of the zone on the current map to use as a boundary function IsSpriteInZone(spriteName, zoneName) local pos = GetPosition(spriteName) local zone = getMap():getZone(zoneName) return (pos:x() >= zone.ul:x()) and (pos:x() <= zone.dr:x()) and (pos:y() >= zone.ul:y()) and (pos:y() <= zone.dr:y()) end --- Sets the name of the script on the current map that will be executed when the player interacts with this sprite. function SetInteractionScript(spriteName, scriptName) local spriteId = getSpriteByAlias(spriteName) local sprite = getSprite(spriteId) sprite.interactionScript = scriptName end