## Reference I: RGB Color Reference

Source: Rapidtables

RGB REFERENCE LIST:

Color/Colour RGB
maroon (128,0,0)
dark red (139,0,0)
brown (165,42,42)
firebrick (178,34,34)
crimson (220,20,60)
red (255,0,0)
tomato (255,99,71)
coral (255,127,80)
indian red (205,92,92)
light coral (240,128,128)
dark salmon (233,150,122)
salmon (250,128,114)
light salmon (255,160,122)
orange red (255,69,0)
dark orange (255,140,0)
orange (255,165,0)
gold (255,215,0)
dark golden rod (184,134,11)
golden rod (218,165,32)
pale golden rod (238,232,170)
dark khaki (189,183,107)
khaki (240,230,140)
olive (128,128,0)
yellow (255,255,0)
yellow green (154,205,50)
dark olive green (85,107,47)
olive drab (107,142,35)
lawn green (124,252,0)
chart reuse (127,255,0)
green yellow (173,255,47)
dark green (0,100,0)
green (0,128,0)
forest green (34,139,34)
lime (0,255,0)
lime green (50,205,50)
light green (144,238,144)
pale green (152,251,152)
dark sea green (143,188,143)
medium spring green (0,250,154)
spring green (0,255,127)
sea green (46,139,87)
medium aqua marine (102,205,170)
medium sea green (60,179,113)
light sea green (32,178,170)
dark slate gray (47,79,79)
teal 0,128,128)
dark cyan (0,139,139)
aqua (0,255,255)
cyan (0,255,255)
light cyan (224,255,255)
dark turquoise (0,206,209)
turquoise (64,224,208)
medium turquoise (72,209,204)
pale turquoise (175,238,238)
aqua marine (127,255,212)
powder blue (176,224,230)
steel blue (70,130,180)
corn flower blue (100,149,237)
deep sky blue (0,191,255)
dodger blue (30,144,255)
light blue (173,216,230)
sky blue (135,206,235)
light sky blue (135,206,250)
midnight blue (25,25,112)
navy (0,0,128)
dark blue (0,0,139)
medium blue (0,0,205)
blue (0,0,255)
royal blue (65,105,225)
blue violet (138,43,226)
indigo (75,0,130)
dark slate blue (72,61,139)
slate blue (106,90,205)
medium slate blue (123,104,238)
medium purple (147,112,219)
dark magenta (139,0,139)
dark violet (148,0,211)
dark orchid (153,50,204)
medium orchid (186,85,211)
purple (128,0,128)
thistle (216,191,216)
plum (221,160,221)
violet (238,130,238)
magenta / fuchsia (255,0,255)
orchid (218,112,214)
medium violet red (199,21,133)
pale violet red (219,112,147)
deep pink (255,20,147)
hot pink (255,105,180)
light pink (255,182,193)
pink (255,192,203)
antique white (250,235,215)
beige (245,245,220)
bisque (255,228,196)
blanched almond (255,235,205)
wheat (245,222,179)
corn silk (255,248,220)
lemon chiffon (255,250,205)
light golden rod yellow (250,250,210)
light yellow (255,255,224)
sienna (160,82,45)
chocolate (210,105,30)
peru (205,133,63)
sandy brown (244,164,96)
burly wood (222,184,135)
tan (210,180,140)
rosy brown (188,143,143)
moccasin (255,228,181)
navajo white (255,222,173)
peach puff (255,218,185)
misty rose (255,228,225)
lavender blush (255,240,245)
linen (250,240,230)
old lace (253,245,230)
papaya whip (255,239,213)
sea shell (255,245,238)
mint cream (245,255,250)
slate gray (112,128,144)
light slate gray (119,136,153)
light steel blue (176,196,222)
lavender (230,230,250)
floral white (255,250,240)
alice blue (240,248,255)
ghost white (248,248,255)
honeydew (240,255,240)
ivory (255,255,240)
azure (240,255,255)
snow (255,250,250)
black (0,0,0)
dim gray / dim grey (105,105,105)
gray / grey (128,128,128)
dark gray / dark grey (169,169,169)
silver (192,192,192)
light gray / light grey (211,211,211)
gainsboro (220,220,220)
white smoke (245,245,245)
white (255,255,255)

## Glossary: Game Terms

Glossary Description
1-up In games where players have a number of “lives” to complete a game or level, an object or the act of gaining an extra life. The term “1-UP” also commonly referred to Player number 1. Two player games scores were displayed as “1-UP” and “2-UP”.
1v1 Abbreviation of 1 versus 1, which means two players battling against each other.
Console A video game hardware unit that typically offers connects to a video screen and controllers, along with other hardware. Unlike personal computers, a console typically has a fixed hardware configuration defined by its manufacturer and cannot be customized.
8-bit A descriptor for hardware or software that arose during the third generation of video game consoles, targeting 8-bit computer architecture.
16-bit A descriptor for hardware or software that arose during the fourth generation of video game consoles, targeting 16-bit computer architecture.
32-bit A descriptor for hardware or software that arose during the fifth generation of video game consoles, targeting 32-bit computer architecture.
2D graphics The game features 2-dimensional objects.
2.5D graphics A game consisting of 3D graphics set in a 2D plane of movement, where objects outside of this 2D plane can have an effect on the gameplay.
Mode 7 is a graphics mode on the Super NES video game console that allows a background layer to be rotated and scaled on a scanline-by-scanline basis to create many different effects.Thus, an impression of three-dimensional graphics is achieved.
Action role-playing game (ARPG) A genre of role-playing video games where battle actions are performed in real-time instead of a turn-based mechanic.
ARPG Abbreviation of Action role-playing game.
Alpha release An initial, incomplete version of a game (compare ‘beta version’); alpha versions are usually released early in the development process to test a game’s most critical functionality and prototype design concepts.
Beta release An early release of a video game, following its alpha release, where typically the game developer seeks to remove bugs prior to the released product through feedback from players and testers.
Closed beta A beta period where only specific people have access to the game
Open beta The opposite of a ‘closed beta’; the players are not bound by non-disclosure agreements and are free to show the game to others.
Bonus stage A level that is usually unlocked and not normally on the level choose screen until unlocked.
Campaign mode A campaign mode, story mode, or simply campaign refers to one of several possible operating modes of a game in which levels are specifically encountered in a linear or branching fashion, often with more story elements present compared to other modes (such as a skirmish mode or sound test).
Challenge mode A mode of gameplay offered beyond the game’s normal play mode that tasks the player(s) to replay parts of the game or special levels under specific conditions that are not normally present or required in the main game, such as finishing a level within a specific time, or using only one type of weapon. If a game doesn’t feature a ‘challenge mode’, players will often create self-imposed challenges by forbidding or restricting the use of certain game mechanics.
Character class A character type with distinct abilities and attributes both positive and negative, such as a warrior, thief, wizard, or priest.
Saved game (game save, savegame, savefile) A file or similar data storage method that stores the state of the game in non-temporary memory, enabling the player to shut down the gaming system and then later restart the system and load the game state from the game file to continuing playing where they left off. Saved games may also be used to store the game’s state before a difficult area that, should the player-character die, the player can restart from that save point. Known a lot as a checkpoint.
Save point A place in the game world of a video game where a game save can be made. Some games do not have specific save points, instead allowing the player to save at any point.
Chiptune Music composed for the microchip-based audio hardware of early home computers and gaming consoles. Due to the technical limitations of earlier video game hardware, chiptune came to define a style of its own, known for its “soaring flutelike melodies, buzzing square wave bass, rapid arpeggios, and noisy gated percussion.”
Combo Combinations of attacks in a fighting game, during which an opponent is helpless to defend themselves. To correctly execute a combo, a player needs to learn complex series of joystick and button combinations.
Continue A common term in video games for the option to continue the game after all of the player’s lives have been lost, rather than ending the game and restarting from the very beginning. There may or may not be a penalty for doing this, such as losing a certain number of points or being unable to access bonus stages.
Controller A means of control over the console or PC you are playing the game on.
PC(s) Player Character(s)
Cutscene A (usually) short video which provides detail and exposition to the story. These videos, usually in much higher graphical resolution and detail than the basic game, are used extensively in MMOs and RPGs to move the story forward.
D-pad A 4-directional rocker button that allows the player to direct game action in eight different directions: up, down, left, right, and the diagonals involving these.
Damage over time (DoT) An effect, such as poison or catching on fire, that reduces a player’s health over the course of time or turns.
Damage per second (DPS) Used as a metric in some games to allow the player to determine their offensive power.
Difficulty The level of difficulty that a player wishes to face while playing a game; at higher difficulty levels, the player usually faces stronger NPCs, limited resources, or tighter time-limits.
Double jump An additional jump that follows the first in quick succession
DPM Abbreviation of “damage per minute”, used as a metric in some games to allow the player to determine their offensive power.
DPS Abbreviation of Damage per second
DRM Abbreviation of Digital rights management
Emulator A software program that is designed to replicate the software and hardware of a video game console on more modern computers and other devices. Emulators typically include the ability to load in software images of cartridges and other similar hardware-based game distribution methods from the earlier hardware generations, in addition to more traditional software images.
Experience point In games that feature the ability for the player character(s) to gain levels such as CRPGs and JRPGs, experience points are used to denote progress towards the next level.
Farming Repeating a battle, quest or a similar part of the game in order to receive either experience points, money, or specific items that can be gained through that battle or quest.
First-person shooter (FPS) A genre of video games where the player experiences the game from the first person perspective, and where the primary mechanic is the use of guns and other ranged weapons to defeat enemies.
FPS An abbreviation for either First-person shooter or Frames per second.
Frame rate A measure of the rendering speed of a video game, typically in frames per second (FPS).
Fog of war A ‘fog’ that covers unexplored areas of the map, hiding enemy units in that area. Common in strategy games.
Game over The end of the game (failure screen).
Game port When a game is ported from one platform to another; cross-platform ports are often criticized for their quality, particularly if platform-specific design elements (such as input methods) are not updated for the target platform.
God mode (infinite health/life, invincibility, invulnerability) A cheat that makes player-characters invulnerable. Occasionally adds invincibility, where the player can hurt enemies by touching them (e.g., the Super Mario Super Star) The effect can also be temporary.
Graphic content filter A setting that controls whether the game displays graphic violence.
Griefer A player in a multiplayer video game who deliberately irritates and harasses other players within the game. Many online multiplayer games enforce rules that forbid griefing.
Health The remaining amount of metered damage that a character or player can take before dying or losing a life.
Indie game (independent video game) Loosely defined as a game made by a person or studio without any financial, development, marketing, or distribution support from a large publisher, though there are indie games that are exceptions to this definition.
Inventory A menu or area of the screen where items collected by the player during the game are stored. This interface allows the player to retrieve any item to use it as an instant effect, or to equip the player character with the item.
Joystick Note: Do not confuse this with “an Analog stick.” An input device consisting of a stick that pivots on a base and reports its angle or direction to the device it is controlling, such as a plane.
JRPG Abbreviation of Japanese role-playing game, typically referring to a subgenre of RPGs that originated from Japan.
Jump A basic move where the player jumps vertically upon pressing the action button.
Kill screen A stage or level in a video game (often an arcade game) that stops the player’s progress due to a software bug.[26] Kill screens can result in unpredictable gameplay and bizarre glitches.
Lag The delay between an action and its corresponding result, most commonly in an online environment. Often the result of delayed network traffic.
Let’s Play A type of video game run-through done by players, through screenshots or video, where the player provides commentary about the game as they work through it.
Level A stage in a game. Level may also represent experience levels or difficulty levels, depending on context.
Level editor A program, either provided within the game software or as an additional program, that allows players to create new levels for video games.
Life In video games, if a player character loses all of its health points, it loses a life. Losing all of one’s lives is usually a loss condition and may force the player to start over. It is common in action games for the player character to have multiple lives and chances to earn more during the game. This way, a player can recover from making a disastrous mistake.
Loot system Methods used in multiplayer games to distribute treasure among cooperating players for finishing a quest. While early MMOs distributed loot on a ‘first come, first served’ basis, it was quickly discovered that such a system was easily abused, and later games instead used a ‘need-or-greed’ system, in which the participating players roll virtual ‘dice’ and the loot is distributed according to the results.
Magic Any of a variety of systems in games to render fantastical or otherwise unnatural effects utilizing a game mechanic, either accessories (scrolls, potions, artifacts) or a pool of resources inherent to the character (“mana”, magic points, etc).
Main A term meaning to focus on playing a certain character, sometimes exclusively.
Main Quest In games with multiple quests, the ‘main quest’ is a chain of quests that comprise the game’s storyline and must be completed to finish the game. The opposite is side quest which still offer rewards but don’t advance the main quest.
Massively multiplayer online game (MMO) A game that involves a large community of players co-existing in an online world, in cooporation or competition with one another.
Massively multiplayer online role-playing game (MMORPG) An MMO that utilizes traditional role-playing game game mechanics into its gameplay. Classic games such as EverQuest and Dark Age of Camelot were progenitors of the genre. The most popular and most well-known game of this type is Blizzard Entertainment’s World of Warcraft.
MMO Abbreviation of Massively multiplayer online game
MMORPG Abbreviation of Massively multiplayer online role-playing game
MMR Abbreviation of Matchmaking rating
Mob Mob is a term for an in-game enemy who roams a specific area. It is an abbreviation of “mobile”, and came into prevalence with the explosion of MMOs and the greater computing power available to these games. In older games, enemies you encountered were stationary, only occupying a specific location within the game and were therefore not “mobs”.
MOBA Abbreviation of Multiplayer online battle arena
Mod A third-party addition or alteration to a game. Mods may take the form of new character skins, altered gameplay mechanics or the creation of a new story or an entirely new game-world. Some games (such as Fallout 4 and Skyrim) provide tools to create game mods, while other games that don’t officially support game modifications can be altered or extended with the use of third-party tools.
Minigame A ‘game-within-a-game’, often provided as a diversion from the game’s plot. Minigames are usually one-screen affairs with limited replay value, though some games have provided an entire commercial release as a ‘mini-game’ within the primary game-world.
Multiplatform A game which can be played on multiple platforms. Also called cross-platform
Multiplayer A game that allows multiple players to play at once.
MP Abbreviation of ‘Magic Points. Abbreviation of Multiplayer.
Nerf A change intended to weaken a particular item, tactic, ability, or character, ostensibly for balancing purposes.
New Game Plus A mode typically offered in games with campaign modes that allows the player to replay the campaign and carry over characters, attributes, or equipment from a prior run-through.
Newbie Someone new to the game, generally used as a pejorative, although usually light-heartedly. See also, “Noob” (below).
Noob A pejorative used to insult a player who is making mistakes that an experienced player would be expected to avoid; by far the most common insult in any gaming community.
Non-player character (NPC) A computer controlled character, or any character that is not under the player’s direct control.
NPC Abbreviation of Non-player character
Patch The process by which a developer of a video game creates an update to an already released game with the intention of possibly adding new content, fixing any bugs/glitches currently residing in the game, balancing character issues (especially prevalent in online multi-player games with competitive focuses), or updating the game to be compatible with DLC releases.
Physical release A version of a video game released on an optical disc or other storage device, as opposed to a digital download.
Player-character A Player Character, or PC, is the main protagonist controlled and played by the human player in a video game. Tidus from Final Fantasy X, Doomguy from the Doom series, and Commander Shepard from the Mass Effect series are all “player characters” developed by their game studios. Your characters you create in MMOs and MMORPGs are also “player characters”.
Player versus environment (PvE) Refers to fighting computer-controlled enemies (non-playing characters), as opposed to PvP (player versus player).
Player versus player (PvP) Refers to competing against other players, as opposed to PvE (player versus environment).
PvE Abbreviation of Player versus Environment
PvP Abbreviation of Player versus Player
Playthrough The act of playing a game from start to finish, in one or several sessions.
Power-up Objects that instantly benefit or add extra abilities to the game character, usually as a temporary effect. Persistent power-ups are called perks.
Quest A “quest” is any objective-based activity created in-game for the purpose of either story or character level advancement. Quests follow many common types, such as “Kill X number of Y monster”, “Gather X number of Y item”, or “Escort this person from point A to point B and keep them safe”. Some quests involve more detailed information and mechanics and are either greatly enjoyed by players as a break from the above common monotony, or are reviled as uselessly more complicated than necessary to the game.
Quicksave/Quickload A mechanism in a video game where progress to or from a saved game can be done by pressing a single controller button or keystroke, instead of opening a file dialog to locate the save file. Typically, quicksaving will overwrite any previous saved state.
Rage Game A video game which is designed to be extremely difficult and frustrating, with elements that intentionally try to ‘cheat’ in some way or form, with the intent of causing a player to become extremely angry and rage quit.
Rage Quit Quitting a game in an act of anger; rage-quitting in an online game is widely considered poor sportsmanship.
Real-time strategy (RTS) A genre of video games where the player controls one or more units in real-time combat with human or computer opponents.
Retrogaming The playing or collecting of older personal computer, console, and arcade video games in contemporary times.
Roguelike A genre of video games featuring procedurally-generated level generation and permanent death.
RPG Abbreviation of Role-playing video game
Role-playing video game (RPG) An RPG is a game where in the human player takes on the role of a specific character “class” and advances the skills and abilities of that character within the game environment. RPG characters generally have a wide variety of skills and abilities available to them, and much theorycrafting (the art of developing a specific character type to its highest in-game potential) is involved in creating the best possible form of each of these character classes.

This is different from games such as First Person Shooters (FPS), wherein the “player character” in those games are all standardized forms and the physical skills of the player involved are the determining factor in their success or failure within the game. In an RPG, a human player can be the best player in the world at the game, but if they are using a character build that is substandard, they can be significantly outplayed by a lesser player running a more optimal character build.
Rush (or Zerg rush) A tactic in strategy games where the player sacrifices economic development in favour of using many low-cost fast/weak units to rush and overwhelm an enemy by attrition or sheer numbers.
Sandbox game A game wherein the player has been freed from the traditional structure and direction typically found in video games, and is instead given the ability to choose what, when, and how they want to approach the available choices in content. The term is in reference to a child’s sandbox in which no rules are present and play is derived from open-ended choice. While some sandbox games may have building and creation aspects to their gameplay, those activities are not required. Sandbox games usually take place in an open-world setting as to facilitate the freedom of choice a player is given.
Side quest A quest that is optional, completing these won’t advance the main story line (Main quest).
Simulation game (Sim) A video game that simulates some aspect of reality, though the degree of realism may vary. They are usually open-ended and have no intrinsic goals to be met. Inclusive definitions allow for any video game that models reality, such as sports games, while exclusive definitions generally focus on city-building games, vehicle simulation games, or both.
Single-player A game that can only have one player at a time. Contrasted with multiplayer.
Skill tree A character development gaming mechanic typically seen in role-playing games. A skill tree consists of a series of skills (sometimes known as perks or by other names) which can be earned by the player as he or she levels up or otherwise progresses his or her player character. These skills grant gameplay benefits to the player; for example, giving the character the ability to perform a new action, or giving a boost to one of the character’s stats. A skill tree is called a “tree” because it uses a tiered system and typically branches out into multiple paths.
Split-screen multiplayer A game that presents 2 or more views seen by different players in a multiplayer game on the same display unit.
Stat point A discrete amount of points for the player to distribute among their character’s attributes, e.g., to choose their player’s trade-offs between strength, charisma, and stamina.
Status effect This is an overarching term that covers both “buffs” and “debuffs”. Essentially, any effect to a character that is outside of the normal baseline is a “status effect”. Common negative status effects are poisoning (damage over time), petrification/paralysis (inability to move), or armor/damage reduction (lowering of defensive/offensive abilities). Common positive status effects include a heal-over-time (a small, pulsing heal that triggers multiple times over a set period), armor/damage increases, or speed increases.
Title screen The initial screen of a computer, video, or arcade game after the credits and logos of the game developer and the publisher are displayed. Earlier title screens often included all the game options available (single player, multiplayer, configuration of controls, etc.) while modern games have opted for the title screen to serve as a splash screen. This can be attributed to the use of the title screen as a loading screen, in which to cache all the graphical elements of the main menu. Older computer and video games had relatively simple menu screens, that often featured pre-rendered artwork.
Touchscreen When the screen of the console can be touched and get a response.
Turn-based game When a game consists of multiple turns. When one player’s turn is up, they must wait until everyone else has finished their turn.
Upgrade A way to make the given item, character, etc. more powerful.
World A series of levels that share a similar environment or theme. A boss fight will typically happen once all or most of these levels are completed rather than after each individual level.
XP Abbreviation of Experience Point
Zero-day patch A software patch that is set to be released on the day of the game’s official release (“the 0th day”), reflecting updates and fixes that were added after the final release candidate was prepared.
Sprite (computer graphics) In computer graphics, a sprite is a two-dimensional bitmap that is integrated into a larger scene.
Pixel In digital imaging, a pixel, pel, dots, or picture element is a physical point in a raster image, or the smallest addressable element in an all points addressable display device; so it is the smallest controllable element of a picture represented on the screen.
Source: https://en.wikipedia.org/wiki/Glossary_of_video_game_terms#Retrogaming
Source: https://en.wikipedia.org/wiki/Mode_7
Source: https://en.wikipedia.org/wiki/Sprite_%28computer_graphics%29
Source: https://en.wikipedia.org/wiki/Pixel
Sound Novel A Sound Novel is a type of visual novel. The term is a trademark by Chunsoft and emphasizes the sound aspects as opposed to visual aspects. Sound novels are actually older than visual novels but because of the trademark the term “visual novel” is the one that’s stuck in the long term. For older games the distinction between the two is somewhat notable, but for most modern games there’s basically no difference between the meaning of the two terms.
Kinetic Novel A Kinetic Novel is a type of visual novel without any gameplay at all. That includes things like making decisions for the protagonist. Because of the lack of any player input, the story is entirely preset and the player just reads through it without any input. These are quite close to ordinary novels with added graphics, sound, and typically more focus on dialogue. Planetarian would be an example of such a game. Kinetic novels are usually shorter than other visual novels, though there are exceptions to this like Higurashi.
Dating Sims Dating Sims are a different category of game from Visual Novels. These games do feature gameplay, but the object of the gameplay is to get into a romantic relationship with a character from the game. The most familiar example is probably the Tokimeki Memorial series, though there are many other highly successful examples such as Love Plus. Unlike visual novels, the gameplay here can be fairly complex.
Visual novel Visual Novel (ビジュアルノベル), often shortened to VN, is a general type of game with a lot of dialogue and minimal gameplay (usually the gameplay is reduced to just making choices at a few plot points to determine what route one enters). It may or may not involve any romance or sexual encounters. For example, Danganronpa could qualify as a visual novel, but probably not for any of the other categories here. A more canonical example would be Higurashi no Naku Koro ni, though purists will sometimes insist on calling it a “Sound Novel” as this is the official description. More on this in the related terms section. Calling something a visual novel emphasizes the “novel” aspect and suggests that there is at least some semblance of a story. It would not usually be used to describe eroge which are solely sex scenes.

Visual novel can also be used in a more technical way to describe games where the text is overlayed over the background as opposed to being presented in dialogue boxes. This distinction is more common among Japanese speakers than English speakers. In English usually people will abbreviate this as NVL, and games where the dialogue is in a box at the bottom of the screen are called ADV. Fate/Stay Night is an example of this style.
Eroge Eroge (エロゲ) is a Japanese shortening of “erotic game”. These can also be called H-games. Native Japanese speakers sometimes use the term to describe games without any sexual content (e.g. Clannad), but in English this isn’t really a correct use of the term. Eroge can be any game with sex scenes (also called H-scenes). This includes some games that are not traditionally included as visual novels or dating sims. For example, Kamidori Alchemy Meister is an example of a game without a great deal of visual novel content but which still qualifies as an eroge.
Logan M: http://anime.stackexchange.com/questions/4926/what-are-the-differences-between-visual-novel-eroge-gal-game-and-a-dating-sim (CC-BY-SA 3.0)
Artificial intelligence (AI) Artificial intelligence is used to generate intelligent behaviors primarily in non-player characters (NPCs), often simulating human-like intelligence. The techniques used typically draw upon existing methods from the field of artificial intelligence (AI).
Beat ‘em up Beat ‘em up (also known as brawler) is a video game genre featuring hand-to-hand combat between the protagonist and an improbably large number of opponents. These games typically take place in urban settings and feature crime-fighting and revenge-based plots, though some games may employ historical, sci-fi or fantasy themes. Traditional beat ‘em ups take place in scrolling, two-dimensional (2D) levels
Central processing unit (CPU) A central processing unit (CPU) is the electronic circuitry within a computer that carries out the instructions of a computer program by performing the basic arithmetic, logical, control and input/output (I/O) operations specified by the instructions.
Camera: The camera is what follows the character around. It causes the screen to scroll with the player character.
Cheats Codes: Special codes that allow you bypass the normal limitations of a game.
Spawning Spawning is the live creation of a character, item or mob. Respawning is the recreation of an entity after its death or destruction, perhaps after losing one of its lives.
Shoulder buttons: (Triggers) Shoulder buttons are found on the back of modern controllers.
Source: https://en.wikipedia.org/wiki/Artificial_intelligence_(video_games)
Source: https://en.wikipedia.org/wiki/Beat_%27em_up
Source: https://en.wikipedia.org/wiki/Central_processing_unit
Source: https://en.wikipedia.org/wiki/Spawning_%28video_gaming%29
Chipset Commonly know now as tileset. This word is kinda old school now. This is the file that holds most graphics. Normally, it does not contain character graphics.
Charset Short for character sets. Charsets hold character graphics.
Layer Think of a layer like a sandwich. Cheese layer goes on the mean layer. Layers are basically images layered on top of each other. You can normally change the layers in some way.
Entity An entity is something that exists separately from other things and has a clear identity or purpose. For example, a door entity would be used for only door like functions.
Map A map in game development is the place where you put together the tiles from the tileset. Your map is the world you create with the tile graphics.
Cursor The cursor is the black arrow (normally a black arrow) that you move around on the screen.

Solarus is a free GPLv3 2D ARPG game engine. ARPG stands for action role playing game. That means it for making games like Secret of Mana or Zelda, but you can do anything in Solarus if you code it. Visual novels, sidescrollers, and all those good game types are possible as well. There is already code in the community for most of it. The coding language used for making games is Lua and it is a super easy programming language. The easiest part is that Solarus’s creator, “Christopho”, has put together many functions to make tasks even easier.

##### Basic Solarus History

Solarus began as a Zelda-like RPG Maker 2000 game. Due to limitations in RPG Maker 2000, the creator Christopho created a Java Engine called Solarus. The Solarus engine was named after the game made with RPG maker. The engine was scripted in Java, but later rewritten in C++ for speed.

Solarus has advanced greatly since being rewritten in C++, but that is greatly due to Christopho and his team. Their hard efforts keep the Solarus Community growing. The future of Solarus is getting brighter by each passing day.

Scroll down to the bottom and choose the version that fits your OS. Ubuntu, Archlinux, Gentoo, OpenBSD / FreeBSD, OpenSUSE, Mac OS X, Microsoft Windows, and ReactOS Windows.

##### Shortcuts
New project CTRL + N
Close tab CTRL + F4
Close all tabs CTRL + W
Save project CTRL + S
Save all CTRL + SHIFT + S
Quest properties CTRL + P
Undo CTRL + Z
Redo CTRL + Y
Cut CTRL + X
Copy CTRL + C
Paste CTRL + V
Select all CTRL + A
Find CTRL + F
Show grid CTRL + G
Show console F12
Run quest F3
Edit tile details Enter or return key
Resize tile R
Tile up one layer SHIFT +
Tile down one layer minus key (-)
Bring tile to back T
Bring tile to front B
Delete DEL
Rename F2
Show/hide Tile CTRL + E, CTRL + 1
Show/hide Destination CTRL + E, CTRL + I
Show/hide Teletransporter CTRL + E, CTRL + T
Show/hide Pickable Treasure CTRL + E, CTRL + P
Show/hide Destructible Object CTRL + E, CTRL + D
Show/hide Chest CTRL + E, CTRL + C
Show/hide Jumper CTRL + E, CTRL + J
Show/hide Enemy CTRL + E, CTRL + E
Show/hide NPC CTRL + E, CTRL + N
Show/hide Block CTRL + E, CTRL + B
Show/hide Dynamic Tile CTRL + E, CTRL + 2
Show/hide Switch CTRL + E, CTRL + H
Show/hide Wall CTRL + E, CTRL + W
Show/hide Sensor CTRL + E, CTRL + S
Show/hide Crystal CTRL + E, CTRL + L
Show/hide Crystal Block CTRL + E, CTRL + K
Show/hide Treasure CTRL + E, CTRL + U
Show/hide Stream CTRL + E, CTRL + M
Show/hide Door CTRL + E, CTRL + O
Show/hide Stairs CTRL + E, CTRL + R
Show/hide Separator CTRL + E, CTRL + A
Show/hide Custom Entity CTRL + E, CTRL + Y

This section is an attempt to help basic understanding of the documentation.

You will be looking at the documentation a lot.

##### Normal Functions

Normal functions are related to sol. Most of the time, a variable can be assigned to the sol functions.

Example:

local map_metatable = sol.main.get_metatable("map")

##### Method Functions

Method functions are attachment functions. They attach to an entity name or other functions. For example, the variable name assigned, like the movement example below.

Movement:

local move_straight = sol.movement.create("straight")

move_straight:set_ignore_obstacles(true)


Hero:

Hero methods would logically use the name “hero”. If no name can be given to the entity, then most likely you will just get and use the variable name you want.

local game = map:get_game()
local hero = map:get_hero()

hero:freeze()


Camera:

Camera methods would logically use the name “camera”. If no name can be given to the entity, then most likely you will just get and use the variable name you want.

local camera = map:get_camera()
camera:start_tracking(entity)


Enemy:

Enemy functions use the name “enemy”, but one can get the name of the entity from the map and use it.

local map = enemy:get_map()
enemy:get_life()


or

local map = enemy:get_map()
local name = map:get_entity("name")

name:get_life()


Custom Entity:

Custom entity functions use the name “entity”, but one can get the name of the entity from the map and use it.

local game = entity:get_game()
local map = entity:get_map()
entity:remove()

local name = map:get_entity("name")

name:remove()


Other Entties:

Entities like NPC will just use the name you give it.

name:remove()


##### Event Functions

Event functions are setup up by putting the name function in front of them and having an end after it.

The function event custom_entity:on_update() would be setup like this:

function entity:on_update()
--code here
end


## Chapter 2: Free Graphics, Audio, Scripts, and Basic Free License Information

### Free Graphics & Audio

##### Sample Quest

Inside the Solarus Engine Download contains many free graphics, scripts, and audio in the sample quest. You can thank Diarandor for that because he is constantly adding resources to the sample quest.

https://gitlab.com/solarus-games/solarus-sample-quest

https://gitlab.com/solarus-games/diarandor-art

##### Children of Solarus

This opensource project contains opensource graphics.

https://gitlab.com/solarus-games/children-of-solarus

##### Faryolica World

This is an outside world tileset I put together with opensource art. I did make a few things, but that does not really matter.

##### OpenGameArt

OpenGameArt has a ton of free graphics and sounds.

https://opengameart.org/

### Scripts

##### Solarus Fan Games

You can get a lot of free enemy scripts and more.

http://www.solarus-games.org/games/solarus-team/

Script Section

Script Post

### Solarus Help Guide

The Solarus Help Guide is just a big chunk of useful information that I have gathered. It is on a post in the Solarus forum.

http://forum.solarus-games.org/index.php/topic,611.0.html

Refer to this link for the most up to date information. I will provide a pdf in this GitHub as well.

## Chapter 3: Moving Around The Solarus Editor

### First Appearance

The Solarus editor looks like this when one first opens it. This is before any quests are loaded or made.

### File

You will notice file at the upper left corner of the Solarus Editor. This is where one would make a new quest, load a quest, close a quest, check recently loaded quests, close tabs, save game, and check the quest properties.

##### File > Quest Properties

The quest properties is about the quest information. The name of the save directory, quest title, summary, description, author, quest version, release date, website, and quest size.

Example of filled in Quest Properties:

One can undo, redo, copy, paste, cut, select all, deselect all, and find text (In the Solarus text editor). The edit menu is located at the upper left corner next to file.

One can zoom, show grid, show console, show/hide layers, show/hide entities, and show/hide entity types in the view menu next to edit.

One can run the game from the run menu or press F5. This menu is right next to the view menu.

One can play selected audio files from this menu. This menu is right next to the run menu.

This menu is a bit more complex than all the others. The tools menu has a lot of options that makes the Solarus experience even better.

##### Tools > Options

There are many tabs. At the Options menu. The options in the tabs are General, Text editor, Map editor, Sprite editor, and tileset editor.

##### Tools > Options > General Tab

1.The General tab contained the working directory this is where our projects will be located.

2.There is an option to restore opened tabs at startup.

3.Another option is to Save modified file before running the quest.

4.One can disable the audio

5.An ability to disable and enable video acceleration.

6.Change the default quest size.

7.At the very bottom of the window you can restore default settings.

##### Tools > Options > Text Editor Tab

The Text editor options are very simple.

1.Able to change the font.

2.An option to change the font size.

3.Tabulation option — which is the space length when one hit the tab key.

##### Tools > Options > Map Editor Tab

The map editor has a lot of useful options.

1.One can change the background color of the map.

2.One can change the grid options. Have the grid open at start, change the default grid size, change the grid color, and change the grid style.

3.Change the default zoom percentage for the map.

4.Change the zoom and background color for the tileset view.

##### Tools > Options > Sprite Editor Tab

The sprite editor has almost the same options as the map editor.

1.One can change the background color of the sprite editor.

2.One can change the grid options. Have the grid open at start, change the default grid size, change the grid color, and change the grid style.

3.Change the default zoom percentage for the map.

4.Change the zoom and background color for the graphic view.

5.Make the origin show at opening and change the origin color

##### Tools > Options > Tileset Editor Tab

The sprite editor has almost the same options as the map editor and sprite editor.

1.One can change the background color of the tileset editor.

2.One can change the grid options. Have the grid open at start, change the default grid size, change the grid color, and change the grid style.

3.Change the default zoom percentage for the tileset.

The help menu links one to the Solarus Website or the Solarus Documentation Website.

### Icon Shortcut Bar

The icon bar has a bunch of shortcuts. This is how it looks when a quest is not loaded.

The main difference for the icon bar from not having a quest open is color and layers. See the following image.

### Resource Manager List

The resource list appears at the left side of the editor when a quest is loaded from file > load quest.

##### Resource Manager List > Tileset Editor

The tileset editor appears when a tileset is selected from the tileset folder. I will not get too much into the tileset editor this chapter.

##### Resource Manager List > Sprite Editor

The sprite editor appears when a sprite character is selected from the sprites folder. I will not get too much into the sprite editor this chapter.

##### Resource Manager List > Sound Player

When a sound is selected from the sound folder and the right mouse button is clicked, the option to play audio shows up.

##### Resource Manager List > Text Editor

A script editing window will open if one were to right click on a script and open it. Also, one can rename the script from that window as well. Also, if the left mouse button is double clicked on the script, then script editor will appear.

##### Resource Manager List > Music Player

When a music is selected from the music folder and the right mouse button is clicked, the option to play audio appears.

##### Resource Manager List > Map Editor

When a map is selected from the map folder and the left mouse button is double clicked, the map editor activates.

##### Resource Manager List > Map Editor > Entities

There are many entities for the map.

Entity Description
Destination The starting point.
Teletransporter Where the character appears on another map
Pickable An item that is picked up, like a coin or rupee.
Destructible Something that can be destroyed
Chest A container for items. You normally find chests in dungeons.
Jumper This makes it so the player can jump over cliff edges and so on.
Enemy A character that tries to harm or kill you.
NPC A player that does not harm you and normally gives you advice or a quest.
Movable block A block the player can move around or push.
Switch Once activated on something occurs. Ex: Flip a light switch and a light comes on.
Wall A custom wall. Maybe it can vanish.
Sensor Once stepped on something occurs. Ex: Step on a mine and boom!
Crystal The crystal is related to the crystal block. When it is hit, the crystal blocks go under ground or block the player’s path.
Crystal block Crystal blocks go under ground or block the player’s path.
Shop A simple shop that can be set up.
Stream A stream. Possibly can be used for current.
Door A door that can be opened and closed.
Stairs Used for a walking up stair animation.
Separator Blocks the camera or player from seeing parts of the dungeon or room.
Custom Entity Make your own entity!
##### Resource Manager List > Map Editor > Drag

One can drag the edges of the Solarus Editor to have a better view of the tileset for mapping the game.

##### Resource Manager List > Language > en > Dialog Editor

When the language type en is double click on with the left mouse button inside the language folder, the dialog editor appears.

## Chapter 4: Using The Sprite Editor

### Resource Manager > Sprites > Sprite Editor

You can add a sprite character by putting a sprite image in the sprites folder directory and add it by right clicking in the Solarus Editor resource manager.

For example, old_woman.dat for old_woman.png.

You can right click on the sprites folder in the resource manager to add as well.

The sprite editor appears when one double clicks on a sprite name.

##### Sprite Properties

You can add various different types of movements in the sprite editor. You can use the green plus(+) sign to add new ones. The other options allow duplicating an animation, deleting(x) an animation, and renaming them.

You can right click the mouse to do the same task.

##### Animation Properties

There are many options when it comes to the animation properties.

1. Setting an animation as default

2. Selecting a source image

1. Frame delay

2. Loop on a certain frame number. Ex: Loop on frame 0

It can be used for the preview if checked. Also, if this is checks on the walking animation for a sprite, then the sprite will walk in place. It will not move.

##### Direction Order

The direction numbers represent the animation direction.

EX:
Direction 1 would be walking to the right.

Number Direction
Direction 1 Right
Direction 2 Up
Direction 3 Left
Direction 4 Down
##### Direction Properties

The direction properties contains dimension options that allows one to easily set up a sprite.

1. Size

2. Position

3. Origin

4. Number of frames

5. Number of columns

##### Size

This is what it looks like when the size is changed. I changed the size from 24 x 24 to 12 x 12.

The result:

##### Position

This is what it looks like when the position is changed from 0 x 0 to 20 x 20 .

The result:

##### Origin

The origin is the center of the player character. One would normally have it y centered and x lowered down to the sprites feet. This helps with proper collision with tileset objects. For this sprite the x is 12 and y is 23. (12 x 23)

I will change the origin from 12 x 23 to 6 x 12.

The result:

The player will not collide with objects properly this way.

EX: A tree. No one wants to bump into a tree 4 steps before it is reached.

Switch Origin

The origin is different for switches and some other sprites. The origin needs to be centered to the upper left corner for a switch. You check the sample in chapter 15. The samples are in the directory Lessons/Chapter_15/Chapter_15_Sample.zip.

##### Frames

This is what it looks like when the frames are set to 8.

Now this is what it looks like when the frames are changed from 8 to 3.

##### Columns

This is what it looks like when the column is changed from 8 to 2.

### Setting up a Sprite

Everyone needs to know how to setup a sprite. The Solarus Sprite editor is super amazing and makes this task easy as pie!

##### Making a Sprite

Making a new sprite is first thing that needs to be done.

##### Name Animation

Click the pencil to load an image from the sprite directory.

##### Making Directions - Drag Click Release

Click one of the sprite image frames and add it as a new direction. This can be done by holding down the left mouse button and dragging to highlight one of the red slime sprites. The first sprite at the upper left corner would be best.

That creates a direction called, “Direction 0.”

Repeat this process until you get 4 frames.

##### Set Columns, Rows, & Origin

We are using 4 frames, so column and rows are 4.

Origin should be fine at 8x8.

##### Show Origin

Click the check box to show the origin.

##### Zoom On Sprite Animation Direction Setup Area

You can use CTRL + Scroll Wheel to zoom in and out of the animation direction setup area.

##### Last & First Frame + Play & Stop

Previous and next are the arrows.

Stop is the button with the square and play is the triangle that is on its side.

##### Dat File Editing

.dat file editing is useful. If the dat file is going to be almost the same for every sprite, then the filenames just need to be changed. This would be faster than creating everything over and over again in the editor.

Example:

Blue_female.dat

  src_image = "Erbarlow/Bard/Female/Blue_female.png",


Green_female.dat

  src_image = "Erbarlow/Bard/Female/green_female.png",


Another Example:

Dat format is useful for trading animation to another sprite. Some animations can take a lot of time to setup.

animation{
name = "stopped",
src_image = "Erbarlow/Bard/Female/green_female.png",
directions = {
{ x = 0, y = 64, frame_width = 32, frame_height = 32, origin_x = 16, origin_y = 32 },
{ x = 0, y = 96, frame_width = 32, frame_height = 32, origin_x = 16, origin_y = 32 },
{ x = 0, y = 32, frame_width = 32, frame_height = 32, origin_x = 16, origin_y = 32 },
{ x = 0, y = 0, frame_width = 32, frame_height = 32, origin_x = 16, origin_y = 32 },
},
}

##### Bounding box or Hitbox

The default size value is 16x16 pixels. This is the effective size used to detect obstacles when moving, but the sprite(s) of the custom entity and enemy may be bigger than 16x16.

The functions custom_entity:set_size(width, height) for the custom entity and enemy:set_size(width, height) can be used for enemies.

### Basic Sprite Information

Solarus has a sprite editor to set up animations and you can make as many as you want. You can activate your custom animations for the hero with hero:set_animation("name_of_animation") and entities with entity:get_sprite():set_animation("name_of_animation").

Solarus goes by 8x8 formatting and it would be best to make a grid for proper positioning. The sprite can be any size, but only the bounding box size can be changed for the entities “enemy” and “custom entity.” The other entities bounding box is 16x16. A hero, NPC, etc.

You can make more animations and code them using the sprite drawable functions, but I will cover most of the default animations built into the engine. You can make any sword attack for the hero. As far as I know.

##### Sword

You will need to create a file called “sword1“ and it can contain the following animations.

Animations
spin_attack
super_spin_attack
sword
sword_running
sword_tapping
victory
##### Shield

It is the similar for the file “shield1“.

Animations
stopped
walking
sword
sword_running
sword_tapping
##### NPC

A NPC needs two animations:

Animations
stopped
walking
##### Enemy

You honestly only need animations “hurt” and “walking”.

Animations
hurt
walking
immobilized
shaking
##### Hero

The hero file is called, “tunic1“.

This is a list of most default hero animations, but there are more. You do not need them all. For example, the hero can still work without swimming, the spin attack can be disabled with code, and so on.

Animations
boomerang1
boomerang2
bow
carrying_stopped
carrying_walking
falling
grabbing
hookshot
hurt
jumping
lifting
plunging_water
pulling
pushing
running
spin_attack
super_spin_attack
stopped
swimming_fast
swimming_slow
swimming_stopped
sword
sword_tapping
throw
walking
walking_with_shield
Animations
destroy
on_ground
stopped
walking
##### bomb
Animations
stopped
stopped_explosion_soon
walking
walking_explosion_soon
Animation
block
Animations
closed
open
Animation
explosion
Animations
big
small
Animations
blue_lowered
blue_raised
orange_lowered
orange_raised
Animations
blue_lowered
orange_lowered
Animations
activated
inactivated
Animations
flying
reached_obstacle
##### star
Animation Description
normal stars or other animation for spin attack
##### ground1
Animation
Stopped
walking
Sound
walk_on_grass.ogg

##### ground2
Animation
Stopped
Sound
walk_on_water.ogg

## Chapter 5: Using The Tileset Editor

### Resource Manager > Tileset > Tileset Editor

You can add a tileset by putting an image with the following extension file_name.tiles.png and making a file_name.dat in the tileset directory and add it by right clicking.

For example, Fairyolica World.png to Fairyolica World.tiles.png. You will need a Fairyolica World.dat as well.

Also, one can make a .dat file or new tileset by right clicking the tilesets folder in the editor.

When one double clicks on a tileset, the tileset editor appears.

##### Selection Properties

Properties appear in the selection properties section when one selects a pattern image id in a tileset.

##### Rename ID

A pattern id can be changed by clicking the pencil icon:

A pattern ID is important because if you have two tilesets that are exactly the same except one is a different color, then you can simply give the same patterns to the other tileset and the map will be changed to that different color when you switch tilesets. Also, it is good with tasks that need certain tiles. For example, a shovel to only work on specific dirt tile.

Example:

A forest can become an instant desert once tilesets are changed. The patterns must be the same or similar enough for a decent change without much editing. This could be useful for different dimensions or terrain changes due to some cause.

You can use map:set_tileset("tileset_name") to change tilesets.

##### Ground

You can select different grounds to fit your tile. For example, the tile would be traversable if the player character can walk on it.

##### Repeatable

A repeatable tile is normally a tile that looks the same while it is being duplicated or by being set right next to the same tile. Grass ground tiles normally look the same in games. They are repeated or duplicated over and over again.

You can set a direction. For example, in the case that the tile only repeats in the horizontal direction.

##### Animation

Animation can make moving flowers or waterfalls. You can set different frame patterns to fit your needs.

##### Making Tile Patterns

The tilesets in Solarus follow an 8 x 8 pattern per block. That means you will have to set up your tileset in a grid to make it work properly.

For example, if you overlay Fairyolica World tileset with an 8x8 grid, then you will see that mostly everything fits a 8x8 pattern.

To make a pattern you just click and drag to make a box.

You can also select the pattern option for the tile.

##### 8x8 Formatting

I will use Gimp as an example for 8x8 formatting. In edit > preferences menu go down to grid.

Now you may have to restart Gimp after saving your new grid preferences.

Afterward, go to view > show grid, you will notice black lined boxes. Each box is an 8x8 block as you can see in the image below. In this example image each tile is in an 8x8 block.

Your graphics do not have to be in a single 8x8 block, but they will have to be in the same range. For example, the whirlpool and larger sand tile below. They are 16 x 16 blocks.

## Chapter 6: Very Basic Lua Scripting, Tutorial Point Lua PDF, ways to load script, and Lua console

### Very Basic Lua Scripting

The files for the very basic programming knowledge are added the Github.

Lessons > Chapter_6 > Chapter_6_Lua_Quick_Basics

##### ZeroBrane IDE

For the basic lessons I recommend ZeroBrane IDE or you can skip to “ways to load scripts in Solarus.”

##### Using ZeroBrane

1.Install and open ZeroBrane.

2.Open a Lua file or add the following code and save it somewhere.

--Hello_Solarus.lua
print("Hello Solarus!")


3.Click the first green arrow to compile and run the script. You can press the key F6 as well.

4.When you run the script with F6, the console at the bottom will show the text.

5.ZeroBrane has a bunch of free basic lessons.

That is all!

##### Whitespace

Blank lines and spaces that are ignored.

##### Variables

Variables are just names that can be manipulated. Global variables are not marked with local or global.

Three types:

1. Local
2. Global
3. Tables can hold anything, but a nil.
name50 -- No local before it makes it global.

local name = 20

local name2 = 10

name + name2

##### Identifiers

When making a variable name, there are some rules.

Unacceptable:

1. Punctuation characters: @#$% 2. Cannot start with a number 3. No spaces between variables. EX: local the variable should be: local the_variable.  Acceptable: 1. A - Z EX: SHE 2. a - z EX: she 3. Underscore followed by numbers and letters _8Wn 4. Case-sensitive EX: She and she are different  Examples of the acceptable identifiers: yodz zata abcd number_five z_456 sefra34 _ten x f2359y2 SpiritBlast ##### Keywords Reserved words in Lua. You cannot name them as variables. for break false true and or not in else elseif local if nil repeat return function while end then until do ##### Data Types Type: About Number: Represents real numbers. String: Represents array of characters. Boolean: True and false as values. Used for checking a condition. Nil: Has no data. Function: A method and most of the time it does a task for you. EX: Drawing images. print(type(true)) ---> boolean print(type(2.1*z)) ---> number print(type(nil)) ---> nil print(type(type(XYZ))) ---> string print(type(print)) ---> function print(type(false)) ---> boolean print(type(type)) ---> function  ##### Relational Operators Operator: About == Checks if they are equal. ~= Checks if they are not equal > Checks if one is greater than the other < Checks if one is less than the other >= Checks if one is greater or equal to each other <= Checks if one is less or equal to each other ##### Logical Operators Operator: About and If both are true, then it activates. or If one of them are true, the it activates. not If it is true, then it will be false. ##### Arithmetic Operators Operator Math Examples + Adds Three + three = 6 - Subtracts Three - three = 0 * Multiplies Three * three = 9 / Divides Three / three = 1 % Remainder Three % five = 2 ^ Exponent three^2 = 9 - Can act as a negative -Three * three = -9 ##### Other Operators Misc: About .. Concatenates or combines text/string. aa..5 = aa5 # Length of text/string. #text = 4 (“text” is equal to 4 letters.) ##### Escape Sequences Escape Task \n New line \t Tab \’ Single quotes \” Double quotes \ Backslash \b Backspace \f Formfeed \a Bell \r Carriage return \v Vertical tab [ Left square bracket ] Right square bracket ##### Repetitions Pattern Modifiers Modifier About + 1 or more repetitions * 0 or more repetitions - also 0 or more repetitions ? optional (0 or 1 occurrence) ##### Character Pattern Classes Pattern About . all characters %a letters %c control characters %d digits %l lower case letters %p punctuation characters %s space characters %u upper case letters %w alphanumeric characters %x hexadecimal digits %z the character with representation 0 ### Common Variable Naming Rules This is not a Lua naming rule and one can completely ignore this because everyone can program the way they want, but this will help people read your code. This is standard in most programming languages. ##### Clear Variable Name Variable yellow is easier to understand than var2. ##### Variable Length The variable name can be of any length, but do not get make too long. One will have to type this name. local the_bunny_crossed_the_road_at_street_number = 50 --The street number that the bunny crosses the road on. local bunny_crossed = 50  ##### UPPERCASE vs lowercase Variables Constants are normally uppercased. This variable will always stay the same. local SPEED = 50  Deciding on StudlyCaps vs. camelCase vs SCREAMING_CAPS is worth maybe 90 seconds discussion with a programming team one is working with, but I always see ALL_CAPS. Lowercase variables are mostly normal variables. local color = "yellow" color = "green"  ### Lua Programming ##### Comments --[[ Lua is a very simple programming language, but very powerful. This is a quick start for the "very" basics of Lua and more will be added later based on examples in scripts. Read this book for more information and detail. https://www.tutorialspoint.com/lua/lua_tutorial.pdf Comments: You can make comments in a few ways in Lua. These are ignored by the code and one uses them to help themselves or others to understand the code. Single comment: You must put "--" before the text. Example: --Hello Multiple line comments: You must use two dashes and opening plus closing brackets. -- [ [ ] ] ]] --Example: --[[ Write all the text you want between here. --]]  --[[ Lua is a very simple programming language, but very powerful. This is a quick start for the "very" basics of Lua and more will be added later based on examples in scripts. Read this book for more information and detail. https://www.tutorialspoint.com/lua/lua_tutorial.pdf --]] --Ways to print text in the terminal. Printing text is very useful for testing your code. print "Hello Solarus World! - Method 1 without ()" print ("Hello Solarus World! - Method 2 with ()")  ##### Declaring variables --[[ Lua is a very simple programming language, but very powerful. This is a quick start for the "very" basics of Lua and more will be added later based on examples in scripts. Read this book for more information and detail. https://www.tutorialspoint.com/lua/lua_tutorial.pdf --]] --Declaring a variable. A variable is just storing a name. They can be global or local. One will normally always use local. --Pie is local because it is not everywhere on earth local pie = 0 --Air is global because it is everywhere on earth. air = 0 --String is basically text in double quotes. local pie_type = "pumpkin pie." --For testing, it is good to print a value or string to know it is working. A simple comma after the quotes. print ("My favorite pie is", pie_type) --Concatenation is used to combine. A simple ".." print ("My favorite pie is "..pie_type) --Value is basically numbers. local pie_number = 5 --Separate two different pieces of text and a single variable. print ("I have", pie_number, "pies.") --Concatenation is used to combine. A simple ".." print ("I have "..pie_number.." pies.") --adding variables or names local add = 5 local pie = 3 print (pie + add)  ##### Tables --[[ Lua is a very simple programming language, but very powerful. This is a quick start for the "very" basics of Lua and more will be added later based on examples in scripts. Read this book for more information and detail. https://www.tutorialspoint.com/lua/lua_tutorial.pdf --]] --Tables. You need tables if you plan to have a many variables or you will get an upvalue error. They can help you identify and organize your variables better too. Declare or add as many names as you want in the table, but remember the comma after the name. local muffin = { chocolate, blueberry, } muffin.chocolate = 5 muffin.blueberry = 2 print ("I have "..muffin.chocolate.." chocolate muffins and "..muffin.blueberry.." blueberry muffins.")  ##### Arrays --[[ Lua is a very simple programming language, but very powerful. This is a quick start for the "very" basics of Lua and more will be added later based on examples in scripts. Read this book for more information and detail. https://www.tutorialspoint.com/lua/lua_tutorial.pdf --]] --Arrays and for loops. --Arrays are not scary. They help with repetition. They can be used in tables too. --Declare an array. local array = {} -- that is it. local pie = {} -- Simple to declare -- All you have to do with arrays is to add a number in square brackets after each new variable. [number] pie[1] = "Chocolate" pie[2] = "Apple" --Easier that doing this chocolate_pie = "Chocolate" apple_pie = "Apple" --Using arrays to print many variables with a "for loop" --rep stands for repetition. You do not have to use rep. 1,2 is basically 1 through 2, so only print variable 1 and 2. for rep = 1,2 do print(pie[rep]) end --You can use variable names for this as well. 1,2 pie[4] = 1 pie[5] = 2 for rep = pie[4],pie[5] do print(pie[rep]) end --Making variables equal to a variable. You need this with calculations or you will get a "nil error", so make them zero at least. This is better than declaring a hundred variables to '0' one by one. That would be a pain! for rep = 1, 10 do array[rep] = 0 print("Array "..rep..":"..array[rep]) end --Math in lua is pretty simple. for rep = 11, 21 do array[rep] = 5 print("Array "..rep..":"..array[rep] + 5 * rep - 10 / 2) end --A string in the square brackets of an array. This can be good for an inventory. local cake = {} cake["chocolate"] = 5 print (cake["chocolate"]) --Increment cake["chocolate"] = cake["chocolate"] + 1 print (cake["chocolate"]) --Decrement (Declare again or it will be 5) cake["chocolate"] = 5 cake["chocolate"] = cake["chocolate"] - 1 print (cake["chocolate"]) --Multidimensional array --This is array type is important in cases where one wants to keep the code basically the same and not duplicate it or copy and paste it over, over, and over again. --Lets pretend you want 3 rows for each array number block. -- Initializing the array row = {} -- Initializing the multidimensional array for rep_d1=1,3 do row[rep_d1] = {} for rep_d2=1,3 do row[rep_d1][rep_d2] = 0 end end --row 1 row[1][1] = 5 row[1][2] = 3 row[1][3] = 2 for rep = 1,3 do print("Row 1: "..row[1][rep]) end --row 2 row[2][1] = 7 + 2 row[2][2] = 3 * 4 row[2][3] = 1 - 3 for rep = 1,3 do print("Row 2: "..row[2][rep]) end --row 3 row[3][1] = "pie" row[3][2] = "cake" row[3][3] = "muffin" for rep = 1,3 do print("Row 3: "..row[3][rep]) end  ##### If Statement & Operators --[[ Lua is a very simple programming language, but very powerful. This is a quick start for the "very" basics of Lua and more will be added later based on examples in scripts. Read this book for more information and detail. https://www.tutorialspoint.com/lua/lua_tutorial.pdf --]] --if statement local frog = 4 -- use "==" instead of "=". You use "==" for reach points. if frog == 4 then print("You do not see "..frog.." frogs everyday!") end --if else statement local frog = 5 if frog == 4 then print("You do not see "..frog.." frogs everyday!") else print("I see no frog.") end --Greater than local frog = 10 local bat = 9 if frog > bat then print("I see more frogs.") end --Less than local frog = 10 local bat = 11 if frog < bat then print("I see more bats.") end --Greater than or equal to --Logical Operators: and local frog = 10 local bat = 9 if frog > bat and frog >= 11 then print("I see 10 frogs.") else print("I do not see 11 frogs.") end --Less than or equal to --Logical Operators: and local frog = 10 local bat = 9 if frog > bat and frog <= 11 then print("I see 10 frogs.") else print("I do not see 11 frogs.") end --if does not equal ~= local frog = 3 if frog ~= 2 then print("There are more than 10 frogs!") end --Logical Operators: or --As long as one is true, then it wil be true. --As long as one of the variables are equal to something other than "nil" local a = 5 local z = nil if a or z then print("It is true." ) end local a = 5 local z = 1 if a or z then print("It is true." ) end --Logical Operators: not --Remember a and z are equal to a value. That names them true, but "not" will make that true into false. It makes the opposite happen. --Changing the values. local a = 1 local z = 1 if not (a and z) then print("It is true." ) else print("It is false." ) end local a = 1 local z = nil if not (a and z) then print("It is true." ) else print("It is false." ) end --elseif statement local frog = 3 if frog ~= 3 then print("There are more than 10 frogs!") elseif frog < 2 then print("There are 2 frogs!") elseif frog == 3 then print("There are 3 frogs!") end --Nested if statement. That means an if statement inside an if statement --Example 1 local a = 10 local b = 5 --If 'a' is greater than 'b' if a > b then --if 'a' is greater than 9 if a > 9 then print ("a is greater than 9!") end end --Example 2 local a = 8 local b = 5 --If 'a' is greater than 'b' if a > b then --if 'a' is greater than 9 if a > 9 then print ("a is greater than 9!") else print ("a is less than 9!") end end  ##### Goto Statement --Use goto as a nested break statement local a = 1 local b = 6 for z=1,10 do if a < b then a = a + 1 print("a is less than b") else goto done end end ::done::  ##### Loops Types --While loop: Repeats a statement a given condition is true. local z = 7 while( z < 18 ) do print("value of z:", z) z = z*3 end print("End of while loop") --For loop: Executes statements multiple times simplifies the code --[[ for init or start value,max or min value, increment or decrement do statement(s) end --]] for start = 10,1,-1 do print(start) end print("End of for loop part 1") for start = 1,10 do print(start) end print("End of for loop part 2") --Repeat...until loop: Repeats till the until condition is met. local z = 3 repeat print("value of z:", z) z = z + 5 until( z > 15 ) print("End of Repeat...until loop") --Nested loops: You can use one or more loop inside any another while, for or do..while loop. for i=1,10 do for s = 1,2 do print("Nested loop.") end end print("End of nested loop") --break statement: This stops a loop. for i=1,10 do for s = 1,2 do print("break loop.") break print("Muffin loop.") end end print("End of break loop") --The Infinite Loop: Keeps going forever. Normally causes a crash. --[[ while( true ) do print("Print this F-O-R-E-V-E-R.") end --]]  ##### Math --[[ Math Library List: Check the following link for more information: http://lua-users.org/wiki/MathLibraryTutorial math.acos math.cos math.asin math.sin math.atan math.tan math.ceil math.deg math.exp math.fmod math.huge math.log math.min math.mininteger math.max math.maxinteger math.modf math.random math.randomseed math.abs math.sqrt math.pi math.rad math.floor math.tointeger math.type math.ult --]] print("") --math.abs --Return the absolute value. Basically, the non-negative value. print("The absolute vale is: "..math.abs(-50)) print("The absolute vale is: "..math.abs(19.37)) print("The absolute vale is: "..math.abs(0)) print("") --math.deg --Angle degrees print("The angle degree is: "..math.deg(math.pi * 2)) print("The angle degree is: "..math.deg(math.pi)) print("The angle degree is: "..math.deg(math.pi / 2)) print("The angle degree is: "..math.deg(math.pi / 4)) print("") --math.min , math.max --Minimum or maximum value print("The min is: "..math.min(3,6)) print("The min is: "..math.min(2.2, 3.6, 8)) print("The min is: "..math.min(1.4, -6, 4)) print("The max is: "..math.max(1.9, -12, 4)) print("The max is: "..math.max(1.22, 5, 2)) print("") --math.sqrt --Square root of a number. Only non-negative values are allowed. print("The square root is: "..math.sqrt(25)) print("The square root is: "..math.sqrt(9)) print("The square root is: "..math.sqrt(200)) print("") --math.random --math.random() Generates a number between 0 and 1. print("The random number is: "..math.random()) print("The random number is: "..math.random()) print("The random number is: "..math.random()) print("") --math.random(upper) generates a number between 1 and upper. print("The random upper number is: "..math.random(120)) print("The random upper number is: "..math.random(110)) print("") --math.random(lower, upper) generates numbers between lower and upper. print("The random lower to upper number is: "..math.random(75,80)) print("The random lower to upper number is: "..math.random(81,85)) print("") --math.randomseed --The "seed" is a starting point. Basically, you will always get the same random numbers no matter how many times you run your script. math.randomseed(12) print("The randomseed number is: "..math.random(15)) print("The randomseed number is: "..math.random(17)) print("The randomseed number is: "..math.random(19)) print("The randomseed number is: "..math.random(22)) print("") --math.pi print("pi is: "..math.pi) print("") --math.floor is for rounding down and math.ceil is for rounding up print ("1.5 rounded down: "..math.floor(1.5)) print ("1.5 rounded up: "..math.ceil(1.5)) print ("-1.5 rounded down: "..math.floor(-1.5)) print ("-1.5 rounded up: "..math.ceil(-1.5))  ##### Strings --String Examples --Escape Sequence example: print ("What do you want\n with\r me\n\t? \nYou \"mushroom\" \'woman\' mutated monster!") --Replacing a string local name = "Zeta Ataria" print("Her old name was "..name) -- replacing strings local replace_name = string.gsub(name,"Ataria","Setrita") print("Her new name is",replace_name) --Case Manipulation print(string.lower(replace_name)) print(string.upper(replace_name)) -- Length of string print("Length of replace_name is ",string.len(replace_name)) -- String Concatenations with .. print("Concatenated:",replace_name..name) -- Repeating strings local repeating = string.rep(replace_name,4) print(repeating) --Formatting Strings local name = "zeta" local rules = "rules" -- Basic string formatting print(string.format("Basic %s format %s",name,rules)) -- Decimal formatting print(string.format("%.0f",1/3)) print(string.format("%.1f",1/3)) print(string.format("%.2f",1/3)) print(string.format("%.3f",1/3)) print(string.format("%.4f",1/3)) print(string.format("%.5f",1/3)) -- Date format + wacky local month = 2; local day = 1; local year = 2014; local wacky = 2 print(string.format("Date %02d/%02d/%03d/%09d", month, day, year,wacky)) --Find and Reverse local name = "zerta galxeria" print("Her name was:"..name) print(string.find(name,"zerta")) reverse_text = string.reverse(name) print("The new name is now:"..reverse_text) --Calculate te length with # print ("The length is: "..#"Length")  ##### tonumber() --A string of numbers. These would need to be converted in order to do math. local string = "5678" local number = tonumber(string) print("End of tonumber(): "..number - 178)  ##### string.format() local number = 3300 --converts varible 'number' into a string with 4 digits. --Digit about can be changed. %0(number)d EX: %09d local number_string = string.format("%07d", number) print("End of string.format(): "..number_string)  ##### string.len() or :len() local string = "What" print("The string length is: "..string.len(string)) print("The string length is: "..string:len())  ##### string.reverse() or :reverse() local string = "Programming" print("Reversing programming: "..string.reverse(string)) print("Reversing programming: "..string:reverse())  ##### string.sub() or :sub() --Print 7 until the end. "Print " = 6 characters (with space), so they are not included print(string.sub("Print seven characters", 7)) --Print 7 until 9. "Print " = 6 characters (with space), so they are not included print(string.sub("Print seven characters", 7, 9)) --Print -7 until the end. "Print " = 6 characters (with space), so they are not included print(string.sub("Print seven characters", -7)) --Print -7 until -9. "Print " = 6 characters (with space), so they are not included print(string.sub("Print seven characters", 7, -9))  ##### string.gmatch(string, pattern) or string:gmatch(pattern) local word --"%a" is a "letters" character class. Check at the start of the programming lesson for all of them. The "+" means one or more words. Otherwise, without the plus...one will just get one letter per character. for word in string.gmatch("Hello Lua user", "%a+") do print("%a+: "..word) end for word in string.gmatch("Hello Lua user", "%a") do print("%a: "..word) end for word in string.gmatch("Hello Lua user", "%a*") do print("%a*: "..word) end for word in string.gmatch("Hello Lua user", "%a?") do print("%a?: "..word) end --[[ Repetitions pattern Modifiers: + 1 or more repetitions * 0 or more repetitions - also 0 or more repetitions ? Optional (0 or 1 occurrence) --]] --[[ Character pattern classes: . all characters %a letters %c control characters %d digits %l lower case letters %p punctuation characters %s space characters %u upper case letters %w alphanumeric characters %x hexadecimal digits %z the character with representation 0 --]]  ##### Clear Table --Makes a table with 2 and 5 in it. local vars = {"2", "5"} --prints the table above print("Table before clearing: "..vars[1]..vars[2]) --clears the table and this makes vars[2] = nil vars = {} vars[1] = 6 print("Table after clearing: "..vars[1],vars[2])  ##### Math/Arithmetic in an if statement local test = 2 local test2 = 1 local limit = 5 -- If variable 'test' added to variable 'test 2' are less than limit, then print, "Cannot go beyond limit!" if test + test2 < limit then print("If/math:Cannot go beyond limit!") end local test = 4 local test2 = 2 local limit = 5 -- If variable 'test' added to variable 'test 2' are greater than limit, then print, "Going beyond the limit!" if test + test2 > limit then print("If/math:Going beyond the limit!") end  ##### Simple table.concat() local char ={} char[3] = "g" char[2] = "p" char[1] = "h" --adds the char in the table together. local foo = table.concat(char) print("Table concat: "..foo)  ##### table.concat() and table.insert() local multiple ={} local character_num = {} local character = {} local char = {} local j = 1 multiple[1] = true for i = 1,15 do char[i] = "q" char[15] = "g" --Variable j = 1 above and multiple[1] is true above, so it activates. if multiple[j] == true then --inserts 'q' into 'character_num' until char[15] because it equals 'g' table.insert(character_num, char[i]) --concat combines each 'q' from the array table character[i] = table.concat(character_num) --print each character concat line print("Concat insert: "..character[i]) end end  ##### table.sort local test_table = {"b", "a", "c", "e", "d"} -- Sort the table from a to z. table.sort(test_table) for i = 1,5 do print(test_table[i]) end print("") --sort the table from z to a. local test_table2 = {"b", "a", "c", "e", "d"} table.sort(test_table2, function(a, b) return a > b end) -- Sort our table, but this time lets make it sort backwards. for i = 1,5 do print(test_table2[i]) end print("") -- Randomly shuffles the table. table.sort(test_table2, function(a, b) return math.random(0,0) < 0 end) for i = 1,5 do print(test_table2[i]) end print("")  ##### Defining a function The local scope, aruguments, and return are optional for functions. --[[ scope_optional function name( arg1, arg2, arg3....., arg[num]) function_body return something end --]] --If number1 is less number 2 then 1 will be added to number 2 --local scope is optional. It will be global without it. local function increase(number1, number2) if number1 < number2 then result = number2 + 1 end --Result is what is printed. return result; end print ("The result: "..increase(2,3)) print("") --You do not have to return it in this case. function thetruth() print("You were a mutant!") end print(thetruth())  Functions can be declared in a straignt line, in a table, and assigned to variables. x = {pos_x = function(x,y) return x end, pos_y = function(x,y) return y end, } print("Dot: ",x.pos_x(3,4)) print("Dot: ",x.pos_y(3,4))  Result: Dot: 3 Dot: 4  ##### pairs() and ipairs() --for key, variable in pairs() (no particular order) --for key, variable in ipairs() (in order) --pairs() and ipairs() loop through a table local itemList = { {bName = "Candy ", bCountry = "Gestra ", bType = "50HP"}, {bName = "Chocolate ", bCountry = "Fragrath ", bType = "100HP"}, {bName = "Sword ", bCountry = "Nerzarta ", bType = "90ATK"}, {bName = "Shield ", bCountry = "kelboax ", bType = "100DEF"}, } local sort_func = function( a,b ) return a.bName < b.bName end table.sort( itemList, sort_func ) for i, record in ipairs( itemList ) do print(record.bName..record.bCountry..record.bType) end  ##### Associative table --[[ Sorting an Associative table - not possible. You can only sort a table of keys which has a number index ]] Assosciative = {muffin = "strawberry", tree = "oak", cake = "oreo", seed = "apple", pie = "chocolate", fruit = "orange"} print ("\nMethod 1 - sort an array of keys") list = {} for name,value in pairs(Assosciative) do list[#list+1] = name end print ("****************by key") table.sort(list) for key=1,#list do print (list[key] .. " is " .. Assosciative[list[key]]) end print ("****************by value") function byvalue(a,b) return Assosciative[a] < Assosciative[b] end table.sort(list,byvalue) for k=1,#list do print (list[k] .. " is " .. Assosciative[list[k]]) end print ("\nMethod 2 - create an array of pairs") arraypairs = {} for name,value in pairs(Assosciative) do table.insert(arraypairs,{name=name, value=value}) end table.sort(arraypairs,function(a,b) return a.name < b.name end) --The variable consisting of only an underscore "_" is commonly used as a placeholder when you want to ignore the variable for _,line in ipairs(arraypairs) do print (line.name .. " is " .. line.value) end  ##### Error Handling --Common errors people make in lua --Forgetting do for rep = 1,3 print(rep) end --13_error_handling.lua:6: 'do' expected near 'print' --Forgetting to assign a number value to be. Be should equal at least zero.EX local b = 0 local b local c = 5 print(b + c) --13_error_handling.lua:20: attempt to perform arithmetic on local 'b' (a nil value) --This should be a single equal. "=" local d == 5 print(d) --13_error_handling.lua:25: unexpected symbol near '==' --For getting to add "then" local b = 5 if b == 5 print(5) end --13_error_handling.lua:38: 'then' expected near 'print' --------------------------------------------------------------------------------- --[[ Some other common errors. That happen when people do not use tables and arrays. 1. Function at line has more than 60 upvalues for local variables, arrays, & 200 Local Variables Limit 2.Control structure too long near --]]  ##### Declaring Multiple Variables On One Line --One can use a comma to declare many variables at one time. local a,b,c,d = 5,6,7,8 print(a) print(b) print(c) print(d) print(a + b + c + d)  #### Coroutine A coroutine can stop (yield) and restart (resume) a task. ##### Make a Coroutine It is quite simple to create a coroutine. variable = coroutine.create(function() --code here end))  ##### Coroutine Yield The coroutine.yield() function stops the coroutine. co = coroutine.create(function() for i = 1, 5 do print(i) coroutine.yield() end end)  ##### Coroutine Resume The function coroutine.resume() needs to be called to start a coroutine. co = coroutine.create(function() for i = 1, 5 do print(i) coroutine.yield() end end) coroutine.resume(co) coroutine.resume(co)  Result: 1 2  ##### Tasks Between Resume One can do other things between coroutine.resume(). --[[ co = coroutine.create(function() for i = 1, 5 do print(i) coroutine.yield() end end) coroutine.resume(co) print("do something") coroutine.resume(co) print("do something") coroutine.resume(co) print("do something")  Result: 1 do something 2 do something 3 do something  ##### Coroutine Status The function coroutine.status() tells you if the coroutine is dead, running, and suspended. A coroutine dies if it exceeds the limit. In this case, the limit is 5 times according to the for loop. co = coroutine.create(function() for i = 1, 5 do print(i) coroutine.yield() print(coroutine.resume(co)) -- Resume in a function print(coroutine.status(co)) end end) coroutine.resume(co) print("do something") coroutine.resume(co) print("do something") coroutine.resume(co) print("do something") print(coroutine.resume(co)) print(coroutine.status(co)) coroutine.resume(co) coroutine.resume(co) print(coroutine.resume(co)) print(coroutine.status(co))  Result: 1 do something false cannot resume running coroutine running 2 do something false cannot resume running coroutine running 3 do something false cannot resume running coroutine running 4 true suspended false cannot resume running coroutine running 5 false cannot resume running coroutine running false cannot resume dead coroutine dead  Another example: Above I showed the output if print(coroutine.resume(co)) was in the function. I will demonstrate the result of it not being there. co = coroutine.create(function() for i = 1, 5 do print(i) coroutine.yield() print(coroutine.status(co)) end end) coroutine.resume(co) print("do something") coroutine.resume(co) print("do something") coroutine.resume(co) print("do something") print(coroutine.resume(co)) print(coroutine.status(co)) coroutine.resume(co) coroutine.resume(co) print(coroutine.resume(co)) print(coroutine.status(co))  Result: 1 do something running 2 do something running 3 do something running 4 true suspended running 5 running false cannot resume dead coroutine dead  ##### Coroutine Callback Calls can be added to coroutine.resume(). coroutine.resume(co, call, call)  co = coroutine.create(function() for i = 1, 5 do print(coroutine.yield(i)) -- true or flase end end) local three = 3 print(coroutine.resume(co)) print(coroutine.resume(co, three, 4)) print(coroutine.resume(co, 5, 6)) print(coroutine.resume(co, 7, 8)) print(coroutine.resume(co, 9, 10)) print(coroutine.resume(co, 11, 12)) print(coroutine.resume(co, 13, 14)) print(coroutine.resume(co, 15, 16))  Result: true 1 3 4 true 2 5 6 true 3 7 8 true 4 9 10 true 5 11 12 true false cannot resume dead coroutine false cannot resume dead coroutine  ##### Coroutine Wrap Shortcut One can use the function coroutine.wrap to shorten the coroutine process. c = coroutine.wrap(function() for i = 1,5 do print(i) coroutine.yield() end end) c() c()  Result: 1 2  #### Module Fist off, make a Lua file called Module_1.lua or any name you want to be honest, but it will be that name in this example. Put it in the scripts directory of the project data folder. ##### Make a table The first task is to make a table. It is better to keep your table local, but it will be global to show you why it should be local later. --[[ m = {} -- make local return m --]]  ##### Add Tasks You will need to add m. before any table item like normal. m.printHello = function() print("hello") end m.pi = 3.1415 m.t = {1, 2, 3} m.number = function(number) print("Number is: "..number) end  ##### Require Module If you plan to use this module all of your scripts, then it would be best to require it at the top of main.lua. In this case I will use a map script because it will be discarded when leaving the map. In first_map.lua require the module and activate the tasks. One will have to assign a variable to the required script to use it. c = require("scripts/module_1") --print hello c.printHello() --print pi print(c.pi) --print all values in table for _, v in pairs(c.t) do print(v) end --number is: c.number(400)  Result: hello 3.1415 1 2 3 Number is: 400  ##### Global Module Table Issue Making the table in the module global is not a good idea because at some point there might be mix ups with code in the module. Let me show you what I mean. c = require("scripts/module_1") c.printHello() m.printHello()  Result: hello hello  As you can see “hello” printed twice because there is no local restriction in the module for m.printHello(). This might become a problem at some point. An easy fix is to make the table in the module local. local m = {} -- make local m.printHello = function() print("hello") end m.pi = 3.1415 m.t = {1, 2, 3} m.number = function(number) print("Number is: "..number) end return m  Now if you try it an error will occur with m.printHello(). Error: In maps/first_map: [string "maps/first_map.lua"]:21: attempt to index global 'm' (a nil value)  ##### Module Shortcut Instead of writing m. over and over again, one can set a metatable and point the table to _ENV (Environment). local m = {} setmetatable(m, {__index = _G}) -- index items in table to be global (_G) _ENV = m -- use this to remove "m." in code. printHello = function() print("hello") end pi = 3.1415 t = {1, 2, 3} number = function(number) print("Number is: "..number) end return m  ##### Assign New Variable One can assign a new variable to require and use it. c = require("scripts/module_1") c.printHello() print(c.pi) for _, v in pairs(c.t) do print(v) end c.number(400) value = require("scripts/module_1") value.number(700) c.number(500) maths = c maths.number(2000)  Result: hello 3.1415 1 2 3 Number is: 400 Number is: 700 Number is: 500 Number is: 2000  ##### Dot vs Colon The colon : is for implementing methods that pass self as the first parameter and the dot . does not unless you pass it into itself. x = {pos_x = function(x,y) return x end, pos_y = function(x,y) return y end, } print("Dot: ",x.pos_x(3,4)) print("Dot: ",x.pos_y(3,4)) print("Colon: ",x:pos_x(3,4)) print("Colon: ",x:pos_y(3,4)) --Same as Colon. print("Dot self: ",x.pos_x(x,3,4)) print("Dot self: ",x.pos_y(x,3,4))  Result: Dot: 3 Dot: 4 Colon: table: 0x06a57fb8 Colon: 3 Dot self: table: 0x06a57fb8 Dot self: 3  #### Function Objects An object has: state Being in a form for growth or development. independent value identity A self. independent life cycle Does not matter what created them or where they were created. assignablity Receive operation. ##### Almost Method A table in Lua is basically a object. However, this function will work only for this object. --almost method MoneyBag = {amount = 0} function MoneyBag.add(value) MoneyBag.amount = MoneyBag.amount + value end MoneyBag.add(200) print("You have the total amount of "..MoneyBag.amount.." in your bag.")  Result: You have the total amount of 200 in your bag.  You can change the name of MoneyBag. bag = MoneyBag bag.add(50) print("You have the total amount of "..MoneyBag.amount.." in your bag.") or print("You have the total amount of "..bag.amount.." in your bag.")  Result: You have the total amount of 250 in your bag.  The reason this is almost a method is because if we do the following we get an error. MoneyBag = nil bag.add(50) print("You have the total amount of "..bag.amount.." in your bag.")  Result: Error: attempt to index global 'MoneyBag' (a nil value)  ##### Method This function will work only for more than one object. Self refers to itself. MoneyBag = {amount = 0} function MoneyBag.add(self, value) self.amount = self.amount + value end MoneyBag.add(MoneyBag, 200) bag = MoneyBag MoneyBag = nil bag.add(bag,50) print("You have the total amount of "..bag.amount.." in your bag.")  Result: You have the total amount of 250 in your bag.  ##### Method With Colon You can shorten the method with a Colon. This will pass self for you. MoneyBag = {amount = 0} function MoneyBag:add(value) self.amount = self.amount + value end MoneyBag:add(200) bag = MoneyBag MoneyBag = nil bag:add(50) print("You have the total amount of "..bag.amount.." in your bag.")  Result: You have the total amount of 250 in your bag.  ##### Colon Hidden Parameter The colon passes a hidden parameter by assigning the function to a variable called add in this case. That means the colon is doing the following:  MoneyBag = { amount = 0, --Assign variable to dot function add = function (self, value) self.amount = self.amount + value end } MoneyBag:add(400) print("You have the total amount of "..MoneyBag.amount.." in your bag.")  Result: You have the total amount of 400 in your bag.  I prefer using a colon though. It is cleaner and easier to organize. MoneyBag = {amount = 0} function MoneyBag:add(value) self.amount = self.amount + value end MoneyBag:add(400) print("You have the total amount of "..MoneyBag.amount.." in your bag.")  Result: You have the total amount of 400 in your bag.  ### Tutorial Point Lua PDF Read this book for more information and detail. https://www.tutorialspoint.com/lua/lua_tutorial.pdf ### Ways To Load Script In Solarus Part 1 ##### Require() Require Part 1: Using require is the best way to load your file, but I use sol.main.load_file a lot when simply testing because it is faster to set up. In the file game_manager.lua put local load_that = require("scripts/0_Lua_Quick_Basics.lua") at the top of game_manager.lua put load_that:load_test() above return game_manager at the bottom of game_manager.lua Require Part 2: In the file 0_Lua_Quick_Basics.lua --Make a table local load_that = {} --Make a function function load_that:load_test(game) --Code of file 0_Lua_Quick_Basics.lua end -- end of function return load_that --return the table  Breaking down the script: In the file game_manager.lua local load_that = {} is making a table named load_that require is for loading and remembering code files "scripts/0_Lua_Quick_Basics.lua" is a directory. Scripts folder > file 0_Lua_Quick_Basics.lua In the file 0_Lua_Quick_Basics.lua Now you should know everything basic except for the function from the quick Lua knowledge files. A function does a certain task and in this case it loads the script. function table:give_name_to_function(parameter) --Code in here end return table  (parameter) is like the scope or range of something. Normally, it is either the (game) or (map) Playtest the game with F5 and the script will run. Sometimes the console will open. If not, then press F12. You can drag it up to show more of the output. Lesson Sample File: I added a test file in the Github repo. Lessons folder > Chapter_6 > chapter_6_require_load.zip ##### Sol Main Load sol.main.load_file(script_name)  This one way to load a Lua script with Solarus. Not the best way. Slower than require because require actually remembers the script after the first run. I use this mainly for testing purposes. In the file game_manager.lua put sol.main.load_file("scripts/0_Lua_Quick_Basics.lua")(game) above game:start() Breaking down the script: sol.main.load_file() is for loading files "scripts/0_Lua_Quick_Basics.lua" is a directory. Scripts folder > file 0_Lua_Quick_Basics.lua Direct it to the game parameter:(game) The end result is this: sol.main.load_file("scripts/0_Lua_Quick_Basics.lua")(game) Playtest the game with F5 and the script will run. Sometimes the console will open. If not, then press F12. You can drag it up to show more of the output. I added a test file in the Github repository. Lessons folder > Chapter_6_sol_main_load.zip ### Grab Numbers & Letters Grabbing letters and numbers can make some interesting puzzles or scripts. I made a very bulky Menu Dialog Display Script using letter grabs and I used digit grabs in my ADVANCED DIGIT DISPLAY SCRIPT. I made those scripts as I was first learning Lua. ##### Grab Numbers Script 1: This script converts the number value into a string, splits it up, and converts it back into a number. local value = 25436 -- value local value_string = string.format("%04d", value) --value_string = "25436" (make value a string) -- sting format: "%d" -- Add zeros: "%04d" (if below 4 digits) local lenth = value_string:len() --Grabs lenth of string for soda array local value_split = {} for i = 0,lenth do local index = value_string:len()-i --decrease by i local num = tonumber(value_string:sub(index,index)) -- convert string to number and decrease string by i table.insert(value_split, num) --insert letter into table value_split end print("value "..value_split[1]) print("value "..value_split[2]) print("value "..value_split[3]) print("value "..value_split[4]) print("value "..value_split[5])  Result: value 6 value 3 value 4 value 5 value 2  Script 2: This script inserts each digit into a table. local value = 25436 local value_split = {} for digit in string.gmatch( tostring(value), "%d" ) do table.insert(value_split, digit) end print("value "..value_split[1]) print("value "..value_split[2]) print("value "..value_split[3]) print("value "..value_split[4]) print("value "..value_split[5])  Result: value 2 value 5 value 4 value 3 value 6  Script 3: This script uses a somewhat classic calculation in an advanced way. local value = 25436 local value_split = {} local num = value if num == 0 then value_split = {0} end while num > 0 do local digit = num % 10 num = math.floor(num / 10) table.insert(value_split, digit) end print("value "..value_split[1]) print("value "..value_split[2]) print("value "..value_split[3]) print("value "..value_split[4]) print("value "..value_split[5])  Result: value 6 value 3 value 4 value 5 value 2  The script above takes the remainder of the value and decreases the place value. local value = 25436 local num = value local digit = num % 10 num = math.floor(num / 10) print(num) -- 2543 print(digit) -- 6 --Takes the remainder digit = num % 1 -- remainder of the 1st place is 0 ( No remainder) digit = num % 10 -- remainder of the 10th place is 6 digit = num % 100 -- Remainder of the 100th place is 36 digit = num % 1000 -- Remainder of the 1000th place is 436 digit = num % 10000 -- Remainder of the 10000th place is 5436 digit = num % 100000 -- Remainder of the 100000th place is 25436 --Decreases the value place num = math.floor(num / 1) -- 25436 num = math.floor(num / 10) -- 2543 num = math.floor(num / 100) -- 254 num = math.floor(num / 1000) -- 25 num = math.floor(num / 10000) -- 2  ##### Grab Letter Script 1: This script uses the alphabet pattern "%w" to get letters and inserts them into a table. local string = "test" local string_split = {} for char in string.gmatch(string, "%w") do table.insert(string_split, char) end print("letter "..string_split[1]) print("letter "..string_split[2]) print("letter "..string_split[3]) print("letter "..string_split[4])  Result: letter t letter e letter s letter t  Script 2: This one shows how one can reverse the string with string.reverse(). string_split = {} local text = "test" local length = text:len() local reverse = false if reverse == true then for msg = 0, length do index = text:len()-msg letter = text:sub(index,index) table.insert(string_split, letter) end else for msg = 0, length do index = string.reverse(text):len()-msg letter = string.reverse(text):sub(index,index) table.insert(string_split,letter) end end print("letter "..string_split[1]) print("letter "..string_split[2]) print("letter "..string_split[3]) print("letter "..string_split[4])  Result: reverse = false  letter t letter e letter s letter t  Result: reverse = true  letter t letter s letter e letter t  ## Chapter 7: Setting up Dialog and Pause ##### Setting Up The Dialog Script In game_manager.lua put the following require directory at the top of the script. (I explained how to use require already. This is the dialog box script designed by Christopho.) require("scripts/menus/alttp_dialog_box") in folder scripts/menus/ put alttp_dialog_box.lua in folder scripts/ put multi_events.lua in folder sprites/hud put dialog_box.png (I provide a free image to use in the lesson > chapter_7_Dialog.zip) in folder fonts/ put bitmap font alttp.png In the editor in the font section. Make sure to add the alttp.png. ##### Using the Dialog box Go to the dialog section of the editor. Languages > en > double click Press the big green plus(+) sign. type _dialog.test _dialog is the main folder .test is the dialog Double click on test, go to dialog properties and down to the first rectangle box where it says text (At the right) Type any text you want in that box. For example, “This is a test dialog.” ##### Mouse Control Fix In game manager.lua Basically for the mouse control to work function game:on_started() end needs to be replaced with game:register_event("on_started", function() end). Change this:  function game:on_started() -- HUD menu. local hud = require("scripts/menus/hud") sol.menu.start(game, hud) hud:create(game) -- Mouse control. local mouse_control = require("scripts/menus/mouse_control") sol.menu.start(game, mouse_control) mouse_control:create(game, hud) local hero = game:get_hero() hero:set_tunic_sprite_id("main_heroes/eldran") end  To this:  game:register_event("on_started", function() -- HUD menu. local hud = require("scripts/menus/hud") sol.menu.start(game, hud) hud:create(game) -- Mouse control. local mouse_control = require("scripts/menus/mouse_control") sol.menu.start(game, mouse_control) mouse_control:create(game, hud) local hero = game:get_hero() hero:set_tunic_sprite_id("main_heroes/eldran") end)  Add multi_events at the beginning of the script: require("scripts/multi_events")  You can add a NPC and add _dialog.test to it. Save the project and playtest with F5. You should see a dialog box appear after “pressing the space bar” to talking to the NPC. ##### Passing a value and string into the dialog Now what if you wanted to pass a name or number value into the dialog? Make a new dialog. Click test > add new dialog (+) > change it to “_dialog.test2 In the text section, add the $v in the text. This passed a variable into the dialog.

Example:

“I got the number $v.” Open your map script. map folder > right click > open script You want to pass the game parameter into the map. local map = ... local game = map:get_game()  You would make a variable to pass to $v

local value = 5

game:start_dialog("_dialog.test2", value)


game:start_dialog("_dialog.test2", starts the dialog

, value) passes the number 5 from value variable into the dialog.

The following would stop the dialog, but you cannot start a dialog and stop one at the same time. You most likely would use a key press to stop the dialog, but we will get to that in a later chapter.

game:stop_dialog("_dialog.test2")


Save the project and playtest with F5. It should just appear. Press the “space bar” to get rid of the text.

##### Setting up yes_no

I personally script my own yes_no menu with images, but the alttp dialog box can make yes and no.

First off, we will start with making the dialog for the pause: _dialog.yes_no

Secondly, make the text: "Do you want to print yes?"

The characters for activating the arrow and picking of yes/no is: $? In the text section: "Do you want to print yes?" $?Yes

$? No(3)  ##### NPC Answer No The dialog, “What will I do with this shiny reward now?” is shown when the player chooses No. ##### NPC Answer Yes The dialog, “Took you long enough! Here is your reward.” is shown when the player chooses Yes. ##### NPC Treasure The reward or treasure is a gem. In order to have the hero (player) receive a reward is by using the hero:start_treasure("Treasure_name") function. Example:  hero:start_treasure("gem")  The script would look like this. function big_boss:on_interaction() game:start_dialog("hammer.hello", function(answer) if answer == 3 then --No game:start_dialog("hammer.no") else game:start_dialog("hammer.yes") hero:start_treasure("gem") end) end end) end  The dialog, “you got a gem!,” will automatically display if you put the dialog in _treasure. The number “1” is the variant. ##### Prevent Repeating NPC Dialog With Boolean Now we do not want the NPC to say the same thing over and over again. This could result in the player getting lots of gems too fast. We can use a boolean to stop the repeating. This will only work if the player never returns to this map again after getting a reward. If hammer_started is true, then the dialog hammer.done will appear. hammer_started = true  local hammer_started = false function big_boss:on_interaction() if hammer_started then game:start_dialog("hammer.done") else game:start_dialog("hammer.hello", function(answer) if answer == 3 then --No game:start_dialog("hammer.no") else game:start_dialog("hammer.yes", function() hero:start_treasure("gem") hammer_started = true end) end end) end end  ##### Prevent Repeating NPC Dialog With Get Value Now we do not want the NPC to say the same thing over and over again. This could result in the player getting lots of gems too fast. The game function game:get_value("name_of_quest") will work the same way as the boolean, but the dialog will not appear again when the player leaves and returns to the map. If the get_value hammer quest is true, then the dialog hammer.done will appear. game:get_value("hammer_quest_started", true)  function big_boss:on_interaction() if game:get_value("hammer_quest_started") then game:start_dialog("hammer.done") else game:start_dialog("hammer.hello", function(answer) if answer == 3 then --No game:start_dialog("hammer.no") else game:start_dialog("hammer.yes", function() hero:start_treasure("gem") game:get_value("hammer_quest_started", true) end) end end) end end  ##### NPC Shortening the Script There is a way to shorten the script. A few lines of script can be combined. Example: This line of code,  hero:start_treasure("gem") game:get_value("hammer_quest_started", true)  can be the following line. The “1” is the variant. The quest will automatically return true.  hero:start_treasure("gem", 1, "hammer_quest_started",function()  Below would result in our completed script. function big_boss:on_interaction() if game:get_value("hammer_quest_started") then game:start_dialog("hammer.done") else game:start_dialog("hammer.hello", function(answer) if answer == 3 then --No game:start_dialog("hammer.no") else game:start_dialog("hammer.yes", function() hero:start_treasure("gem", 1, "hammer_quest_started",function() game:start_dialog("hammer.wonderful_day") end) end) end end) end end  ##### NPC Wonderful Day As one can see below, the NPC says something right after you get your reward. This is the dialog hammer.wonderful_day. This is a temporary reply by the NPC. Any other time the hammer.done will show. ##### NPC Dialogs One can check Christopho’s tutorial for more ways of setting up dialog near the end of the video. I explained the less error prone method. ##### Generalized NPC A Generalized NPC can only be interacted based on its starting direction. Down is common for a Generalized NPC. An example of a Generalized NPC is a sign post. You would interact with it from the front, but one is able to pick up the sign by default and throw it from other directions. There is a special direction called,”any.” This will allow the player character to interact from all four directions of the sign. Generalized NPC(s) are used normally for something and not somebody, but there are a few exceptions. ##### Generalized NPC Desk Method Generalized NPC(s) are useful for not only signs or other objects. They can be used to talk to a person across a table. Now this isn’t in the sample, but what if both NPC(s) are not a generalized NPC? If I talk to the magician from the right, then that makes him turn to the right. If the hero interact with the desk, then the magician will still be facing the wrong direction. In this case we use a function called, “NPC:get_sprite():set_direction(Number).” Number Direction Direction(0) Right Direction(1) Up Direction(2) Left Direction(3) Down Example: magician:get_sprite():set_direction(3)  The Magician will look down(3) in this case. ### Movable Block Entity ##### Add Block The block entity is right by the green NPC person entity. A block can be moved around. ##### Block Properties Type Option Name A name is needed for scripting reasons. You can leave it blank. Layer The layer you want the entity on. Position The coordinates the entity is at. You can manually change them or move the entity with the cursor. Direction The direction you are allowed to push the block. Sprite Pick the sprite image for the block. Max Moves The options are cannot move, 1 move only, and unlimited. Interactions There are 2 ways to interact with a block. It can be pushed or pulled. The block entity is that simple. There will be more customization for the block entity in Solarus 1.6 version. ### Switch Entity ##### Add Switch The switch is the button with the red dot next to the block entity. You can step on the switch to activate certain events and there are a few other ways to activate it. ##### Switch Properties Type Option Name A name is needed for scripting reasons. You can leave it blank, but unless you plan to have it there just for show, then a name is needed. Layer The layer you want the entity on. Position The coordinates the entity is at. You can manually change them or move the entity with the cursor. Sprite Pick the sprite image for the switch. Subtype Walkable: Ability to walk on the switch. Solid: You can hit the switch with the ‘c’ key to activate it. Usually, that is a weapon like a sword. Arrow Target: You can shoot an arrow at it. There is a built in bow and arrow. Play Sound Pick a sound that you want played when the switch activates. Activation You can require a block to be on the switch for it to be activated. Leaving switch The switch can be deactivated if this option is checked. ##### Walkable Switch Coding In order to code a script one much give it a name. I gave it the name chest_button. In the following example I use the on_activated() function. function chest_button:on_activated()  on_activated means that something will happen when the switch is stepped on. In this case a sound will be played and a chest will appear. --chest_1 function chest_button:on_activated() sol.audio.play_sound("chest_appears") chest:set_enabled(true) end  I named the chest the name chest. The function Set_enabled(true/false is used to make it appear or not appear. The first thing that needs to be carried out is that the chest needs a save value because we will be using this to see if the chest has been opened. I used the save value name Map_4_gem_treasure.  if game:get_value("Map_4_gem_treasure") then  Next we want to show the button as activated and not deactivated. The set_activated(true/false) function is used in order to achieve this.  chest_button:set_activated(true)  Now we want the chest to be invisible if the switch is not activated yet.  else chest:set_enabled(false) end end  The result is the following script.  --chest_1 function map:on_started() if game:get_value("Map_4_gem_treasure") then chest_button:set_activated(true) else chest:set_enabled(false) end end --chest_1 function chest_button:on_activated() sol.audio.play_sound("chest_appears") chest:set_enabled(true) end  ##### Block Switch Coding The block coding is almost exactly the same, so I will not be typing everything over again. I will cover the parts that are different. Name the block. I named it block. Name the switch. I named it chest_button_2. Check require a block to be activated and deactivate when leaving. Name the chest. I named it chest_2. I gave it the save state name Map_4_gem_treasure_2. The script. The switch and chest will activate/deactivated if the block is moved on/off it. function map:on_started() --chest_2 if game:get_value("Map_4_gem_treasure_2") then chest_button_2:set_activated(true) else chest_2:set_enabled(false) end end --chest_2 function chest_button_2:on_activated() sol.audio.play_sound("chest_appears") chest_2:set_enabled(true) end  Now we want the chest to vanish when the block leaves the button. We want this to happen only when the chest is not opened. We need to check when the button is inactivated and will use the function on_inactivated() for this. function chest_button_2:on_inactivated()  After that we need to check if the chest is open or not. We use the function is_open(). The chest needs to be set_enabled(false) because we do not want the chest to appear if the button is inactive.  if not chest_2:is_open() then chest_2:set_enabled(false) end end  The script will look like this. function chest_button_2:on_inactivated() if not chest_2:is_open() then chest_2:set_enabled(false) end end  Now we need to check the block position. We want the block to still be on the switch when we leave and come back to the map. Check if the chest is open.  if chest_2:is_open() then  If the chest is open, then set button activated to true, otherwise set the chest to false.  chest_button_2:set_activated(true) else chest_2:set_enabled(false)  Set the position of the block. Use the function set_position(x,y). Hover over the location of switch and set the block to that position. Adjust it if you have to.  block:set_position(216,308)  The result. function map:on_started() if chest_2:is_open() then chest_button_2:set_activated(true) block:set_position(216,308) else chest_2:set_enabled(false) end end  The full script. Tip: When I say the chest is false, that means the chest does not appear. function map:on_started() --chest_2 --Save chest state if chest is opened and set button activation to true. Otherwise, the chest is set to false. if game:get_value("Map_4_gem_treasure_2") then chest_button_2:set_activated(true) else chest_2:set_enabled(false) end --if chest is open, then have the button activated and set block position. Otherwise, the chest is false. if chest_2:is_open() then chest_button_2:set_activated(true) block:set_position(216,308) else chest_2:set_enabled(false) end end --Set chest_2 to activate if the block is on the button function chest_button_2:on_activated() sol.audio.play_sound("chest_appears") chest_2:set_enabled(true) end --Set chest_2 to deactivated if the block is not on or move off the button and if the chest is not open. function chest_button_2:on_inactivated() if not chest_2:is_open() then chest_2:set_enabled(false) end end  ##### Solid Switch Coding The same as the walkable switch. Just set it to solid and press c to activate it. There will be an example in the dynamic Tile section. ### Dynamic Tile Dynamic tiles are entities, and they can be manipulated like an entity once a name is given to them. You can script it and all that jazz. Tiles are originally static meaning they cannot be used with scripts until converted to Dynamic. ##### Convert to Dynamic Right click > Convert to dynamic tile ##### Convert to Static Right click > Convert to static tile ##### Dynamic Properties Type Option Name A name is needed for scripting reasons. You can leave it blank, but unless you plan to have it there just for show, then a name is needed. Layer The layer you want the entity on. Position The coordinates the tile is at. You can manually change them or move the entity with the cursor. Size The dimension size of the tile. Initial State Display or do not display at start of game. ##### Dynamic Scripting Dynamic scripting is not really different from scripting with entities. Give a name to a switch. I am using a solid switch in this case and gave it the name solid_switch. The next step is to convert a normal tile to dynamic, so we can script it. Make sure that enabled at start is unchecked. Now we will make the bridge to appear when the solid switch is hit. We will do this with the following script. Not really anything to explain because we already covered these functions. --Solid Switch bridge function solid_switch:on_activated() bridge:set_enabled(true) end  ### Wall Entity ##### Add Wall Entity Click on the stop sign like image by the switch entity to add the wall entity. It can be stretched to fit a large area and blocks paths for certain obstacles. ##### Wall Entity Properties Type Option Name A name is needed for scripting reasons. You can leave it blank, but unless you plan to have it there just for show, then a name is needed. Layer The layer you want the entity on. Position The coordinates the entity is at. You can manually change them or move the entity with the cursor. Size The dimension size of the entity. Obstacles Hero - Prevents the hero from passing. Enemies - Prevents the enemies from passing. NPCs - Prevents the NPCs from passing. Blocks - Prevents the blocks from passing. Projectiles - Prevents the projectiles from passing. ##### Wall Entity Scripting The scripting is no different from any other entity. There will be an example in the sensor section, but let me cover another function before that. The function is remove(). This function deletes or erases an entity from the map. One must be really careful when using this function because annoying messages can appear if not taken care of properly. The reason why I am covering this function is that one will want the wall to vanish at a certain point. Let us pretend that the wall is blocking the enemy. On some condition, like stepping on a switch, the wall can be removed.  enemy_wall:remove()  Now every time that switch is activated an annoying message will appear in the terminal because the entity was removed and no longer exists (nil). The following script is a way to avoid the annoying message. Of course, there are many other ways and this way may not be very professional. One could just show an entity as activated instead of leaving the space blank or remove the entity too. Removing the switch avoids the error message all together.  if enemy_wall == nil then --nothing happens else enemy_wall:remove() end  ### Sensor Entity ##### Add Sensor Entity The sensor entity is right next to the wall Entity. It is a green circle with a question mark on it. It can be stretched to fit a large area and can detect the hero when it gets into the boundary. ##### Sensor Properties Type Option Name A name is needed for scripting reasons. You can leave it blank, but unless you plan to have it there just for show, then a name is needed. Layer The layer you want the entity on. Position The coordinates the entity is at. You can manually change them or move the entity with the cursor. Size The dimension size of the entity. ##### Sensor Scripting This is an example of wall and sensor scripting. First off, do not name your sensor entity the name sensor. You can, but it will interfere with a shortcut, at least when I tried it. Instead, we will be using the name ground_sensor_. Name the wall enemy_wall or any name you want. Now let us go over the scripting part. There is a good function that goes good with sensors. The function is hero:save_solid_ground. This function teleports the hero back to the sensor in this case. That means if the hero falls into a hole he/she/it will go back to the sensor instead of near the falling point. function ground_sensor_1:on_activated() hero:save_solid_ground()  Enable the bridge with the following script. Make sure that enabled at start is unchecked.  bridge_2:set_enabled(true)  Remove the wall when the sensor is touched and prevent annoying message because the wall entity will no longer exists (nil).  if enemy_wall == nil then --nothing happens else enemy_wall:remove() end  The final script: --Bridge sensor function ground_sensor_1:on_activated() hero:save_solid_ground() bridge_2:set_enabled(true) if enemy_wall == nil then --nothing happens else enemy_wall:remove() end end  Tip: There is a shortcut for hero:save_solid_ground(). Instead of typing hero:save_solid_ground() over and over again for each new sensor, you could use the following script. --Do not name your sensor, "sensor." Do not give it the same name. Use a unique name like "ground_sensor." for sensor in map:get_entities("ground_sensor_") do function sensor:on_activated() hero:save_solid_ground() end end  To start, the “for sensor” part refers to the sensors on the map. The get_entities() function refers to the names of the sensors. The names are all ground_sensor_ with some number index. For example, ground_sensor_1. The get_entities() functions grabs or gets the sensors with the same name, but with a number difference (number index). for sensor in map:get_entities("ground_sensor_") do  Now we will make a function for the sensors on the map. We will save_solid_ground()with this function. The “sensor” in the on_activated function refers to all the sensors on the map.  function sensor:on_activated() hero:save_solid_ground() end  The resulting script. --Do not name your sensor, "sensor." Do not give it the same name. Use a unique name like "ground_sensor." for sensor in map:get_entities("ground_sensor_") do function sensor:on_activated() hero:save_solid_ground() end end  ##### Sensor Get Position We covered the set_position function, but we can get the position of an entity as well. The function for getting an entity is get_position(). Using the get_position() function is quite easy. For example, if you wanted the hero to teleport to an entity to trick or torture the person playing your game, then you could have the player go to a destination entity. I used the name up_stairs_2.  hero:set_position(up_stairs_2:get_position())  function ground_sensor_2:on_activated() hero:set_position(up_stairs_2:get_position()) end  ##### Sensor Multiple Dynamic Tiles This a shortcut for bulk numbers of dynamic tiles with the same name. The first thing we will do is add a sensor. I named it ground_sensor_3. The next step is to add a dynamic tile and name it. Make sure to set up the properties before copying. The number index in the name will change as you copy it. We do not want the dynamic tiles enabled at start, so uncheck enabled at start. We will use a timer for a delay with each dynamic tile. One will appear after the other. You could shorten the timer for an instant result. The first thing that needs to be done is to make a variable called tile_index. We will be concatenating this with the name of the dynamic tiles, tile_ with some number index. We will assign the value 1 to tile_index. local tile_index = 1  The second step is to make a timer. You can assign the time delay you want.  sol.timer.start(400, function()  The third step is to male a variable called previous_tile. This will activate the first tile. Now let us set up the previous_tile variable. local previous_tile =  We will assign it to a function called map:get_entity. We will use this to get the times of all the dynamic tiles we want. One wants the names of all the tile_ dynamic tiles with some number index. For example, tile_1. local previous_tile = map:get_entity("tile_"  Lastly, we will concatenate the tile_index. That will name it tile_1 because the value of tile_index is 1. local previous_tile = map:get_entity("tile_" .. tile_index)  The fourth step next_tile is almost the same as previous_tile. The only difference is that we will be adding 1 to the tile_index.  local next_tile = map:get_entity("tile_" .. (tile_index + 1))  The fifth step is to set up an increment for next_tile. This is needed for tile_ indexes 2, 3, 4, and 5. Tip: Increment is adding a value to itself.  tile_index = tile_index + 1  The seventh step is to enable the previous_tile. If it is set to false, then the tiles will vanish one after the other. That could be useful for timed puzzles. False example  previous_tile:set_enabled(false)  However, we want it to be true.  previous_tile:set_enabled(true)  Step 8 will be to stop the index from going beyond the number of tiles we have. The number of dynamic tiles is five for me. We will return next_tile false if it becomes nil. For instance, tile_6 will be nil because it does not exist.  if next_tile == nil then --finished return false end  The 9th step is to set next_tile to true, but in this case it really does not matter if it is true or false. There may be transition differences.  next_tile:set_enabled(true) --Return true or it will stop after the second tile. return true end) end  The final script. function ground_sensor_3:on_activated() hero:save_solid_ground() local tile_index = 1 sol.timer.start(400, function() local previous_tile = map:get_entity("tile_" .. tile_index) local next_tile = map:get_entity("tile_" .. (tile_index + 1)) tile_index = tile_index + 1 previous_tile:set_enabled(true) if next_tile == nil then --finished return false end next_tile:set_enabled(true) --Return true or it will stop after the second tile. return true end) end  Lastly, if you check enabled at start for the initial state of all the tile_ dynamic tiles, then set previous_tile and next_tile enabled to false, the dynamic tiles will vanish one after the other instead of appearing on after another.  previous_tile:set_enabled(false) next_tile:set_enabled(false)  function ground_sensor_3:on_activated() hero:save_solid_ground() local tile_index = 1 sol.timer.start(400, function() local previous_tile = map:get_entity("tile_" .. tile_index) local next_tile = map:get_entity("tile_" .. (tile_index + 1)) tile_index = tile_index + 1 previous_tile:set_enabled(false) if next_tile == nil then --finished return false end next_tile:set_enabled(false) --Return true or it will stop after the second tile. return true end) end  ### Crystal Switch Entity ##### Add Crystal Switch The crystal switch works with the crystal block. A crystal block rises or lowers when a crystal switch is hit with key c. For example, the block will lower if the initial state of the block is set to lowered. ##### Crystal Switch Properties Type Option Name A name is needed for scripting reasons. You can leave it blank, but unless you plan to have it there just for show, then a name is needed. Layer The layer you want the entity on. Position The coordinates the entity is at. You can manually change them or move the entity with the cursor. ##### Default Crystal Switch Graphic Names As far as I know the animation keywords for switches are blue_lowered and orange_lowered. The default animation is the color that one wants to see first. ### Crystal Block Entities The crystal block works with the crystal switch. A crystal block rises or lowers when a crystal switch is hit with key c. For example, the block will lower if the initial state of the block is set to lowered. ##### Add Crystal Block ##### Crystal Block Properties Type Option Name A name is needed for scripting reasons. You can leave it blank, but unless you plan to have it there just for show, then a name is needed. Layer The layer you want the entity on. Position The coordinates the entity is at. You can manually change them or move the entity with the cursor. Size The dimension size of the entity. Subtype Initially lowered or raised. Basically, start the block lowered or raised at the start of the map. ##### Default Crystal Block Graphic Names As far as I know the keywords are blue_lowered, blue_raised, orange_lowered, and orange_raised. I tried different keywords for the animations, but the blocked failed to show up on the map when playtesting the game. ### Stream Entity The stream entity pushes the player or moves him/her/it in the desired direction. It can also be used to slow the player down. For example, gravity, spinning wheel, and/or a sandstorm. A developer might want to have some force to slow down the player. ##### Add Stream ##### Stream Properties Type Option Name A name is needed for scripting reasons. You can leave it blank, but unless you plan to have it there just for show, then a name is needed. Layer The layer you want the entity on. Position The coordinates the entity is at. You can manually change them or move the entity with the cursor. Direction You can pick the direction you want the stream to go or push the player. Up, down, left, left-up, right-up, and right. Sprite Pick the sprite image for the switch. Movement Allow the player to move when on the stream. Sword Allow the player to use the sword during movement. Items Allow the usage of items when on the stream. Speed The speed at which the stream will move the player. ### HUD HUD stands for heads up display. It is the health bar, money counter, etc. There are many scripts from Christopho’s games that can be used. You can check his YouTube Tutorial for that information. I will be covering the heart display and money counter. ##### Setup HUD Scripts The 1st step will be to add the HUD scripts folder (Get them from sample > E_Crystal_switch-Block_Shop_stream.zip.) and remove the current HUD in the menu directory or rename the scrips to .old. Remember to comment out the old hud in the game_manager.lua and require the HUD from the manager. require("scripts/hud/hud")  require("scripts/menus/alttp_dialog_box") require("scripts/multi_events") require("scripts/hud/hud") local game_manager = {}  Add the green_digits and white_digits fonts to the font directory. Get them from sample > E_Crystal_switch-Block_Shop_stream.zip. Remember to add them in the manager too. ##### Hud Configurations hud_config.lua You can change the coordinates of the counter and heart health display from this script. Change the x,y coordinates until you like what you see.  -- Hearts meter. { menu_script = "scripts/hud/hearts", x = -88, y = 0, }, -- Rupee counter. { menu_script = "scripts/hud/rupees", x = 121, y = 10, }  ##### Health Heart Display hearts.lua Health is the life points the player has until he dies or faints. The way this script works is that it draws a surface of your heart image. The image will have full, half empty, and empty graphics. You might have to adjust the surface for your image if you have super huge hearts or other graphics related to this system. This part can be found at the beginning of the hearts.lua script.  hearts.surface = sol.surface.create(80, 16)  If your hearts or graphics are like mine (beyond 8x8 in dimensions), then you will have to adjust them. At first mine turned out like this. The script is currently set up for 8x8 hearts, but mine is 16x16 hearts. You will have to adjust the function hearts:rebuild_surface().  function hearts:rebuild_surface() hearts.surface:clear() local life = hearts.current_life_displayed local max_life = hearts.max_life_displayed for j = 1, max_life do if j % 2 == 0 then local x, y if j <= 20 then x = 4 * (j - 2) y = 0 else x = 4 * (j - 22) y = 8 end if life >= j then hearts_img:draw_region(0, 0, 8, 8, hearts.surface, x, y) else hearts_img:draw_region(16, 0, 8, 8, hearts.surface, x, y) end end end if life % 2 == 1 then local x, y if life <= 20 then x = 4 * (life - 1) y = 0 else x = 4 * (life - 21) y = 8 end hearts_img:draw_region(8, 0, 8, 8, hearts.surface, x, y) end end  To be specific this part:  if j <= 20 then x = 4 * (j - 2) y = 0 else x = 4 * (j - 22) y = 8 end if life >= j then hearts_img:draw_region(0, 0, 8, 8, hearts.surface, x, y) else hearts_img:draw_region(16, 0, 8, 8, hearts.surface, x, y) end end end if life % 2 == 1 then local x, y if life <= 20 then x = 4 * (life - 1) y = 0 else x = 4 * (life - 21) y = 8 end  In order to fix this I have to adjust draw_region functions. Draw_region draws certain locations on a surface. Note: You can set up your graphics in the sprite editor to get coordinates easier. Location 1 is at (0, 0, 16, 16,). The 2 zeros are the positions. The y position does not change (px,py,sx,sy,) and the next 2 spots 16,16 are the sprite dimensions. px,py = position sx,sy = sprite dimensions hearts_img:draw_region(0, 0, 16, 16, hearts.surface, x, y)  Location 2 is at (16, 0, 16, 16,). hearts_img:draw_region(16, 0, 16, 16, hearts.surface, x, y)  Location 3 is at (32, 0, 16, 16,). hearts_img:draw_region(32, 0, 16, 16, hearts.surface, x, y)  The script result is the hearts are almost fixed. Notice that spacing issue? if life >= j then for j = 1, max_life do if j % 2 == 0 then local x, y if j <= 20 then x = 4 * (j - 2) y = 0 else x = 4 * (j - 22) y = 8 end if life >= j then hearts_img:draw_region(0, 0, 16, 16, hearts.surface, x, y) else hearts_img:draw_region(32, 0, 16, 16, hearts.surface, x, y) end end end if life % 2 == 1 then local x, y if life <= 20 then x = 4 * (life - 1) y = 0 else x = 4 * (life - 21) y = 8 end hearts_img:draw_region(16, 0, 16, 16, hearts.surface, x, y) end  One must adjust the variable x to fix the spacing issue. I changed them all to x = 5. if life >= j then for j = 1, max_life do if j % 2 == 0 then local x, y if j <= 20 then x = 5 * (j - 2) y = 0 else x = 5 * (j - 22) y = 8 end if life >= j then hearts_img:draw_region(0, 0, 16, 16, hearts.surface, x, y) else hearts_img:draw_region(32, 0, 16, 16, hearts.surface, x, y) end end end if life % 2 == 1 then local x, y if life <= 20 then x = 5 * (life - 1) y = 0 else x = 5 * (life - 21) y = 8 end hearts_img:draw_region(16, 0, 16, 16, hearts.surface, x, y) end  ##### Money System Rupee Style I will explain on how to adjust it to different size hearts and coordinate changes. You can change the counter’s location from hud_config.lua. The HUD uses an image file called rupee_icon.png. I made up a simple gem for this purpose. This needs to be added to sprites > hud directory. The counter should just show up after adding the scripts. You can adjust the gem’s location in rupees.lua. Look for function rupees:on_draw. This line changes the x-axis. The -2 location.  rupee_icon_img:draw(dst_surface, x + -2, y)  This line changes the y-axis. The 11 location.  digits_text:draw(dst_surface, x, y + 11)   function rupees:on_draw(dst_surface) local x, y = dst_x, dst_y local width, height = dst_surface:get_size() if x < 0 then x = width + x end if y < 0 then y = height + y end rupee_icon_img:draw(dst_surface, x + -2, y) digits_text:draw(dst_surface, x, y + 11) end  The counter shows up green and nothing happens. In order to use the counter one must set the limit. By default, it is set to 0. That means it is full. Green font means the counter is full. In game_manager.lua under function function game_manager:start_game() add the following line of code.  game:set_max_money(100)  function game_manager:start_game() local exists = sol.game.exists("save1.dat") local game = sol.game.load("save1.dat") if not exists then -- Initialize a new savegame. game:set_max_life(12) game:set_life(game:get_max_life()) game:set_ability("lift", 2) game:set_max_money(100) game:set_ability("sword", 1) game:set_starting_location("Map_4") -- Starting location. end  ### Money (Gem) Setup The gem already exists for you. You can thank Diarandor for that, but I will explain how to set up the gem. This script is a little cleaner. 1. Make an item script called gem. You probably want to delete the old one first or use the name gem2. 1. Go to sprites > entities > items. The item script name must match, the item animation game. 1. By default, a script template is made when making an item. -- Lua script of item gem. -- This script is executed only once for the whole game. -- Feel free to modify the code below. -- You can add more events and remove the ones you don't need. -- See the Solarus Lua API documentation for the full specification -- of types, events and methods: -- http://www.solarus-games.org/doc/latest local item = ... local game = item:get_game() -- Event called when the game is initialized. function item:on_started() -- Initialize the properties of your item here, -- like whether it can be saved, whether it has an amount -- and whether it can be assigned. end -- Event called when the hero is using this item. function item:on_using() -- Define here what happens when using this item -- and call item:set_finished() to release the hero when you have finished. item:set_finished() end -- Event called when a pickable treasure representing this item -- is created on the map. function item:on_pickable_created(pickable) -- You can set a particular movement here if you don't like the default one. end  1. The functionfunction item:on_using() will not be used because you buy things with money (gems), but if you plan to attack with gems, then you would use this function. That means you can delete this part. -- Event called when the hero is using this item. function item:on_using() -- Define here what happens when using this item -- and call item:set_finished() to release the hero when you have finished. item:set_finished() end  1. The functionfunction item:on_pickable_created(pickable) is used for when an item is created on a map. The movement animation can be changed. For example, have it spin differently (default one works fine in my opinion) or have the gem move slowly away from the player. That means you can delete this part of the script as well. -- Event called when a pickable treasure representing this item -- is created on the map. function item:on_pickable_created(pickable) -- You can set a particular movement here if you don't like the default one. end  1. We are left with one function function item:on_started(). This function is used to set up the properties for your item. For example, shadow size, and sound when picked up. There are a lot of functions that can be used and I will cover the basic ones. local item = ... local game = item:get_game() -- Event called when the game is initialized. function item:on_started() -- Initialize the properties of your item here, -- like whether it can be saved, whether it has an amount -- and whether it can be assigned. end  1. Set the shadow size with the function self:set_shadow("animation_name"). function item:on_created() -- Define the properties of rupees. self:set_shadow("small") end  1. Set whether it can disappear or not with the function self:set_can_disappear(true/false). function item:on_created() -- Define the properties of rupees. self:set_can_disappear(true) end  1. Set the “ta da da daa” brandish sound when picking up the item. This will be false because it would be strange for this to happen on a simple gem. Normally, this happens when a chest is open. The function for that is self:set_brandish_when_picked(false/true). function item:on_created() -- Define the properties of rupees. self:set_brandish_when_picked(false) end  1. Set the sound for when the item is picked up with function self:set_sound_when_picked("name_of_sound"). function item:on_created() -- Define the properties of rupees. self:set_sound_when_picked("picked_rupee") end  The result: function item:on_created() -- Define the properties of rupees. self:set_shadow("small") self:set_can_disappear(true) self:set_brandish_when_picked(false) self:set_sound_when_picked("picked_rupee") end  Function item:on_obtaining The last function will be for setting up the value for all the variants and so that money can be added to the counter. We do this with the function function item:on_obtaining(variant, savegame_variable). 1. It is best to start this with a table. The table will hole the money amount for 3 variants. For example, value 2 = variant 1, value 10 = variant 3, etc. function item:on_obtaining(variant, savegame_variable) local amounts = { 2, 6, 10 } end  1. Next we will use the function game:add_money(). This is used to add value to the money counter. We will use the variable amounts and variant from the function item:on_obtaining(variant, savegame_variable) to add values for the gem amounts[variant]. function item:on_obtaining(variant, savegame_variable) local amounts = { 2, 6, 10 } game:add_money(amounts[variant]) end  The result is the gem script. local item = ... local game = item:get_game() function item:on_created() -- Define the properties of rupees. self:set_shadow("small") self:set_can_disappear(true) self:set_brandish_when_picked(false) self:set_sound_when_picked("picked_rupee") end function item:on_obtaining(variant, savegame_variable) local amounts = { 2, 6, 10 } game:add_money(amounts[variant]) end  ### Shop Entity The shop entity is a quick shop setup. The shop entity shows the price, an icon, and the treasure. It uses an image file called rupee_icon.png. ##### Add Shop Entity ##### Shop Entity Properties Type Option Name A name is needed for scripting reasons. You can leave it blank, but unless you plan to have it there just for show, then a name is needed. Layer The layer you want the entity on. Position The coordinates the entity is at. You can manually change them or move the entity with the cursor. Treasure The treasure item to choose. You can pick a variant and save state. Price The cost of the item. Price font The font for the shop. Description dialog id Dialog to use when buying the item. ##### Shop Setup This is what the basic shop set up looks like. ##### Shop Entity Dialogs The shop requires some dialogs. The first is in the dialog properties. The name can be whatever you want in this case. shop.gem Do you want to buy a gem?  The rest of the dialog go by default built in names. They will all be under, “_shop.” _shop.amount_full You can't carry any more!  _shop.not_enough_money Sorry, you don't have enough Rupees!  _shop.question Price:$v Rupees.
$? Buy$? Don't Buy


Lastly, if you save the state of the treasure from the shop, then you will only be able to buy that item once.

### Door Entity

The purpose of this entity is for opening doors.

You can find the sample for this section in the directory Lessons > Chapter_13_Entities > F_door_stairs_seperator_custom.zip.

The door entity is by the stream entity.

##### Door Properties
Type Option
Name A name is needed for scripting reasons. You can leave it blank, but unless you plan to have it there just for show, then a name is needed.
Layer The layer you want the entity on.
Position The coordinates the entity is at. You can manually change them or move the entity with the cursor.
Direction You can pick the sprite direction of the door if that graphic exists in an animation setup. The options are up, down, left, and right.
Sprite Pick the sprite image for the door.
Door State If you want the door to stay open when leaving the map, then you much check the save the door state.
Opening mode There are bunches of opening modes for a door.
By script - That means a script is required for opening a door.
By hero - The hero opens the door.
By hero, savegame variable - This means the hero can open this door if the savegame variable exists.
By hero, item - An item is required for the hero to open the door.
By explosion - A bomb can open the door or some other item with an explosion ability.
Dialog If the door fails to open, then a dialog can be shown. For example, “you need a small key to open this door.”

##### Door Graphic Setup

For a door to work 3 default animation keywords are needed.

• closed - Door is closed. Not open.
• closing - Door is opening or closing
• opening - Door is open.

The closing time determines whether the graphic shows or not. Give the door entity a frame delay of 0 ms for animation closed if you do not want the door graphic to vanish when playtesting.

##### Door Script

We are going to open two doors at the same time with a switch entity.

1. Add a switch entity. I named the switch door_trigger.

1. Add a door entity. I named it switch_door.
2. You can save the state of the door.
3. Select the opening mode By script.
4. You can add a dialog as well.

1. Copy the door entity you just made and set it somewhere. Do not rename it because the number index at the end is needed to open both doors at the same time.

1. The function map:open_doors("name_without_number_index") will open both doors at the same time.
local map = ...
local game = map:get_game()

function door_trigger:on_activated()
map:open_doors("switch_door")
sol.audio.play_sound("door_open")
end

##### Opening Door With Key
1. Create an item named key.

1. Make an animation for the key in sprites > entities > items.

1. Setup the door and require the key.

1. Make sure to create a dialog for the item key.

1. Saving the item key. The item must be saved in order for it to work. Double click on the item key to open its item script. On creating the key use the function self:set_savegame_variable("name_of_item").
##### Door Key
local item = ...
local game = item:get_game()

function item:on_created()
-- Define the properties of key.
self:set_savegame_variable("map_4_key")
end

##### Door Opening By Hero

The hero is able to open the door.

### Stairs Entity

The purpose of the stair entity is to create stair walking animation.

The stair entity is by the door entity.

##### Stairs Properties
Type Option
Name A name is needed for scripting reasons. You can leave it blank, but unless you plan to have it there just for show, then a name is needed.
Layer The layer you want the entity on.
Position The coordinates the entity is at. You can manually change them or move the entity with the cursor.
Direction You can pick the hero direction for when the hero goes up the stairs. The options are up, down, left, and right.
Subtype The subtypes are:
Spiral staircase (going upstairs) - Upward spiral stairs walking animation.
Spiral staircase (going downstairs) - Downward spiral stairs walking animation.
Straight staircase (going upstairs) - Straight upstairs walking animation.
Straight staircase (going downstairs) - Straight down stairs walking animation.
Platform stairs (same map) - Walking up platform animation. It basically walks up a layer. Trying the “Straight staircase” would make the hero go behind the layer.

##### Stairs Setup

Set the destination and teletransporter onto the stair entity. The player will do a walking stair animation and teleport to the desired destination.

### Separator Entity

The purpose of this is block the view of the player or enemy. For example, if you have many sections in a room and do not want to see the other sections, then use the separator to block the view. The blocking has to be reasonable though. The sections should all be even or the separator will not work properly.

The separator entity is by the stair entity. It is the purple icon.

##### Separator Properties
Type Option
Name A name is needed for scripting reasons. You can leave it blank, but unless you plan to have it there just for show, then a name is needed.
Layer The layer you want the entity on.
Position The coordinates the entity is at. You can manually change them or move the entity with the cursor.
size One is able to expand, stretch, and/or resize the separator.

##### Separator viewpoint
1. View without separator.

1. View with separator.

### Custom Entities

The custom entity is for custom scripts.

The custom entity is by the purple separator entity. It is the green puzzle piece icon.

##### Custom Entity Properties
Type Option
Name A name is needed for scripting reasons. You can leave it blank, but unless you plan to have it there just for show, then a name is needed.
Layer The layer you want the entity on.
Position The coordinates the entity is at. You can manually change them or move the entity with the cursor.
size One is able to expand, stretch, and/or resize the custom entity.
Direction The direction of the sprite if it exists in an animation.
- Up
- Down
- Left
- Right
Sprite Pick the sprite image for the entity.
Custom entity script Call a custom entity from the entity folder from the resource manager. You will notice the green puzzle icon.

##### Create Custom Entity Script

Go to entities and right click to add an entity script.

You can pick an entity script from the custom entity.

##### Trick Chest Entity Scripting

We are going to script a chest that hurts the player.

1. Double click on the trick_chest entity.

2. Erase everything, but the function entity:on_created() and the entity signifier local entity = .... By signifier, I mean it just tells that its entity related.

3. Setup the entity, so it works on the map. local map = entity:get_map().

4. Setup the entity, so it affects the hero local hero = map:get_hero().

local entity = ...
local map = entity:get_map()
local hero = map:get_hero()

1. Okay, we got the basics set up. Now we can give the entity trick_chest properties when it is created function entity:on_created(). These properties are not really needed if you set it up in the editor.

2. The only function that is truly needed is self:set_traversable_by(true/false). You will not go through the entity if the is set to false. Furthermore, I demonstrated how to set the size and origin, but, you can do this in the editor.

function entity:on_created()
self:set_size(16, 16)
self:set_origin(8, 13)
self:set_traversable_by(false)
end

1. Now we get to find out why we needed to local hero = map:get_hero(). We needed to get the hero in order to cause damage using the function on_interaction(). There are a few ways to cause damage.

One can use game function game:remove_life(total_life - damage_amount). That would require one to get the game local game = entity:get_game(), but there is not indication that damage was caused.

local entity = ...
local map = entity:get_map()
local hero = map:get_hero()
local game = entity:get_game()

function entity:on_created()
self:set_traversable_by(false)
end

function entity:on_interaction()
game:remove_life(12 - 6)
end


Another way is to use the function hero:start_hurt(x,y,damage_amount). The hero will be thrown back and damage will be inflicted. The x and y are the positions of the entity.

local entity = ...
local map = entity:get_map()
local hero = map:get_hero()

function entity:on_created()
self:set_traversable_by(false)
end

function entity:on_interaction()
hero:start_hurt(240,277,6)
end

1. Lastly, you can remove the entity if you want after it causes damage. I mentioned the remove() before.
local entity = ...
local map = entity:get_map()
local hero = map:get_hero()

function entity:on_created()
self:set_size(16, 16)
self:set_origin(8, 13)
self:set_traversable_by(false)
end

function entity:on_interaction()
--game:remove_life(12 - 6)
hero:start_hurt(240,277,6)
entity:remove()
end


#### Custom Entity Switch

There is no function for on_activated with a custom entity, but one can easily make one with Lua using a timer.

local hero = map:get_hero()

--Create on_activated
sol.timer.start(500, function()
if entity.on_activated ~= nil then
entity:on_activated()
return true
end
end)


The easiest way to detect an entity overlapping another is with the overlaps function.

entity:overlaps(other_entity, [collision_mode])

Collision mode Description
“overlapping” Collision if the bounding box of both entities overlap. This is the default value.
“containing” Collision if the bounding box of the other entity is fully inside the bounding box of this entity.
“origin” Collision if the origin point or the other entity is inside the bounding box of this entity.
“center” Collision if the center point of the other entity is inside the bounding box of this entity.
“facing” Collision if the facing position of the other entity’s bounding box is touching this entity’s bounding box. Bounding boxes don’t necessarily overlap, but they are in contact: there is no space between them. When you consider the bounding box of an entity, which is a rectangle with four sides, the facing point is the middle point of the side the entity is oriented to. This “facing” collision test is useful when the other entity cannot traverse your custom entity. For instance, if the other entity has direction “east”, there is a collision if the middle of the east side of its bounding box touches (but does not necessarily overlap) this entity’s bounding box. This is typically what you need to let the hero interact with this entity when he is looking at it.
“touching” Like “facing”, but accepts all four sides of the other entity’s bounding box, no matter its direction.
“sprite” Collision if a sprite of the other entity overlaps a sprite of this entity. The collision test is pixel precise.
local hero = map:get_hero()

function entity:on_activated()
if hero:overlaps(entity) then
sol.audio.play_sound("secret")
hero:start_hurt(240,277,6)
end
end


Another way to detect the hero is by doing it manually with the get_position() function, but overlaps function is easier.

--if hero's position is equal to entity's position, then hero is damaged when stepping on entity.
function entity:on_activated()
local x1,y1 = hero:get_position()
print("Hero: "..x1..","..y1)
if (x1 > 240 and x1 < 256) and (y1 > 272 and y1 < 288) then
sol.audio.play_sound("secret")
hero:start_hurt(240,277,6)
end
end


#### Custom Animation

You can change the animation for the custom entity. Let us say you want to do a sword swing animation. All you would have to do is the following line of code.

entity:get_sprite():set_animation("sword_swing")


You must make the sword_swing animation in the sprite editor.

For the hero you will not have to get_sprite() because the function exists for the hero and it does not have to be retrieved from the sprites methods, so it would be like the following line of code.

hero:set_animation("dead")


#### Get Distance to Entity

The function entity:get_distance(other_entity) checks the distance in pixels to another entity. It is super useful.

Example:

If the entities distance is less that 20 pixels, then print “Entity encounters hero!”

local hero = map:get_hero()

--Create on_activated
sol.timer.start(500, function()
if map.on_activated ~= nil then
map:on_activated()
return true
end
end)

function map:on_activated()
print("------------",hero:get_distance(sprite))
local distance_between = hero:get_distance(sprite)
if distance_between < 20 then
print("Entity encounters hero!")
end
end


#### Make Entity Turn to Entity

Then function set_direction and entity:get_direction4_to(other_entity) are needed for this to work.

The entity:get_direction4_to(other_entity) function gets the direction of another entity and set_direction makes an entity face a direction.

The following code makes the two sprites look at each other.

--set_direction
npc_2:get_sprite():set_direction(npc_2:get_direction4_to(npc))
npc:get_sprite():set_direction(npc:get_direction4_to(npc_2))


#### Obstacle Detection

Let us say a sprite is using the target movement and gets stuck. The best way to solve this is with the function entity:on_obstacle_reached(). Basically, if the entity hits an obstacle, then something happens.

Example:

In the following script the entity uses the path_finding movement until the distance to the hero is less than 25 pixels. At that time it uses the target movement again.

function entity:on_obstacle_reached()

movement = sol.movement.create("path_finding")
movement:set_target(hero)
movement:set_speed(60)
movement:start(entity)

local distance_between = hero:get_distance(entity)
if distance_between < 25 then
movement = sol.movement.create("target")
movement:set_target(hero)
movement:set_speed(60)
movement:start(entity)
end
end


#### On Hero State

The hero has many built in states.

States
“back to solid ground”
“boomerang”
“bow”
“carrying”
“falling”
“forced walking”
“free”
“frozen”
“grabbing”
“hookshot”
“hurt”
“jumping”
“lifting”
“plunging”
“pulling”
“pushing”
“running”
“stairs”
“stream”
“swimming”
“sword spin attack”
“sword swinging”
“sword tapping”
“treasure”
“using item”
“victory”

The following script print “spin attack” when the hero does a sword spin attack.

function hero:on_state_changed(state)

if state == "sword spin attack" then
print("spin attack")
end
end


Samples:

You can find samples of custom switch to on hero state in:

Lessons > Chapter_13_14_custom_entity_game_over.zip

### Hero Entity

This section is about “some” hero methods examples and you can check the documentation for them all. I have already demonstrated some throughout the book and will not repeat those. You can check chapter 14 section “abilities” for more and everything is in the Solarus documentation.

#### Hero Teleport

Teleports the hero to a destination with a transition.

hero:teleport(map_id, [destination_name, [transition_style]])

local map = ...
local game = map:get_game()
local hero = map:get_hero()

function map:on_started()
end


transition_style
“immediate” No transition effect.
“scrolling” It scrolls.

#### Hero Get Animation

Gets the animation the hero is currently doing.

hero:get_animation()

Example:

local map = ...
local game = map:get_game()
local hero = map:get_hero()

-- Call a function every second.
sol.timer.start(1000, function()
if hero:get_animation() == "walking" then
print("walking")
end
return true  -- To call the timer again (with the same delay).
end)


#### Hero Set Animation

Sets the animation you made for the hero in the sprite editor.

hero:set_animation(animation, [callback])

Example:

local map = ...
local game = map:get_game()
local hero = map:get_hero()

-- Call a function every second.
sol.timer.start(1000, function()
if hero:get_animation() == "walking" then
hero:set_animation("stopped")
else
hero:set_animation("walking")
end
return true  -- To call the timer again (with the same delay).
end)


#### Set Sword Sound

The sound the sword makes. By default, the sound is sword1.

hero:set_sword_sound_id(sound_id)

local map = ...
local game = map:get_game()
local hero = map:get_hero()

function map:on_started()
hero:set_sword_sound_id("bomb")
end


#### Hero Walk

The hero walk function moves the hero along a path. It can loop or ignore obstacles.

hero:walk(path, loop, ignore_obstacles)

Example:

local map = ...
local game = map:get_game()
local hero = map:get_hero()

function map:on_started()
hero:walk("6446600222",false,true)
end

Number Direction
0 right
1 up right
2 up
3 up left
4 left
5 down left
6 down
7 down right

#### Hero Jump

Makes the hero jump in a direction.

hero:start_jumping(direction8, distance, [ignore_obstacles])

Example:

local map = ...
local game = map:get_game()
local hero = map:get_hero()

function map:on_started()
hero:start_jumping(2, 100, false)
end

Number Direction8
0 right
1 up right
2 up
3 up left
4 left
5 down left
6 down
7 down right

## Chapter 14: Abilities, Save Game, Quest Launcher, and Game Over

The sample for this lesson is in the following directory:

Lessons > Chapter_14_Abilities_Quest-launcher_savegame

### Abilities: Swim, Lift, Sword, Run, etc

Built-in ability levels indicate whether the hero can perform some built-in actions like attacking, swimming, and running.

Ability Description
sword Ability to use the sword and with which sprite.
sword_knowledge Ability to make the super spin-attack.
tunic Tunic (determines the sprite used for the hero’s body).
shield Protection against enemies. Determines whether the hero can avoid some kinds of attacks.
lift Ability to lift heavy objects.
jump_over_water Automatically jump when arriving into water without the “swim” ability.
swim Ability to swim in deep water.
run Ability to run when pressing the action command.
detect_weak_walls Notifies the player with a sound when a weak wall is nearby.
##### Set Ability

You can set an ability with the game function game:set_ability.

game:set_ability("Ability", level)


Example:

The player would gain the sword1 ability.

game:set_ability("sword", 1)


The level at 0 turns off the ability.

game:set_ability("sword", 0)


In my opinion, I think it would be best to activate abilities in the game manager, with an NPC, and/or when obtaining an item.

Example:

function item:on_obtaining()
game:set_ability("sword", 1)
end


One can deactivate an ability on different maps.

Example:

function map:on_started()
game:set_ability("sword", 0)
end

##### Get Ability

This function will get the level of the ability.

game:get_ability("Ability")

##### Has Ability

This function will return true if the hero has the ability or false if the hero does not have it.

game:has_ability("Ability")

##### Tunic Ability Setup

An ability needs to be set or activated before it can work.

game:set_ability("tunic", 1)


There are some default names that will need to be known for setting up the hero. The hero sprite animation is called tunic1 by default. Many levels or variants of a tunic can be used by adding another number.

Example:

To make a second tunic all someone has to do is create an animation file called tunic2.

game:set_ability("tunic", 2)


One can use a custom animation name and directory for the tunic as well.

The function hero:set_tunic_sprite_id("directory/animation_name") can be used to change the hero sprite.

Example:

Diarandor uses the following line of code for his hero sprite Eldran.

    hero:set_tunic_sprite_id("main_heroes/eldran")


Tip:

By default, the “walking” animation will disable any animation. To change the default walking one could use hero:set_tunic_sprite_id(sprite_id) and have the animation for “walking” be “stopped.” That way the hero will walk around using the “stopped” animation. Another way to do this is with the drawable sprite functions.

Tunic Animation List:

The tunic has the following default animations and probably more. They are needed for the hero abilities.

• boomerang1
• boomerang2
• bow
• brandish
• carrying_stopped
• carrying_walking
• dying
• falling
• grabbing
• hookshot
• hurt
• jumping
• lifting
• plunging_lava
• plunging_water
• pulling
• pushing
• running
• spin_attack
• super_spin_attack
• stopped
• stopped_with_shield
• swimming_fast
• swimming_slow
• swimming_stopped
• sword
• victory
• walking
• walking_diagonal
• walking_with_shield
##### Sword Ability Setup

An ability needs to be set or activated before it can work.

game:set_ability("sword", 1)


There are some default names that will need to be known for setting up the sword. The sword sprite animation is called sword1 by default. Many levels or variants of a sword can be used by adding another number.

Example:

To make a second sword all someone has to do is create an animation file called sword2. The sword will take away 2 life points at level 2.

game:set_ability("sword", 2)


One can use a custom animation name and directory for the sword as well.

The function hero:set_sword_sprite_id("directory/animation_name") can be used to change the sword sprite.

Example:

    hero:set_sword_sprite_id("sword/red_sword")


The sword has the following default animations and probably more.

• spin_attack
• super_spin_attack
• sword
• sword_running
• sword_tapping
• victory

An animation called sword_stars1 is needed for the charging animation during the spin attack. The sword_stars2 and so on are needed for the other swords if they have charged attacks.

##### Sword Knowledge

An ability needs to be set or activated before it can work.

game:set_ability("sword_knowledge", 1)


The sword_knowledge ability allows the player to do a super spin attack.

An animation called super_spin_attack is needed in tunic1 and sword1 for this to work.

##### Shield Ability Setup

An ability needs to be set or activated before it can work.

game:set_ability("shield", 1)


There are some default names that will need to be known for setting up the shield. The shield sprite animation is called shield1 by default. Many levels or variants of a shield can be used by adding another number.

Example:

To make a second shield all someone has to do is create an animation file called shield2.

game:set_ability("shield", 2)


One can use a custom animation name and directory for the shield as well.

The function hero:set_shield_sprite_id("directory/animation_name") can be used to change the shield sprite.

Example:

    hero:set_shield_sprite_id("shield/red_shield")


The shield has the following default animations. They follow when a sword is used.

• stopped
• sword
• sword_tapping
• walking
##### Lift Ability Setup

An ability needs to be set or activated before it can work.

game:set_ability("lift", 1)


The lift ability connects directly with the destructible entity weight.

The following would require lift ability level 3.

game:set_ability("lift", 3)


The lifting, carrying_stopped, and carrying walking animations are required in the tunic sprite animation.

##### Water Jump Ability Setup

An ability needs to be set or activated before it can work.

game:set_ability("jump_over_water", 1)


The player drowns instantly when touching deep water unless they have the swim ability. This allows the player to jump before drowning.

The plunging_water animation is required in the tunic sprite animation.

##### Run Ability Setup

An ability needs to be set or activated before it can work.

game:set_ability("run", 1)


One must press and hold the space bar for this ability to activate.

The running animation is required in the tunic sprite animation.

I have encountered issues when jumping. For example, it crashes with the jump_over_water ability and with the jumper entity.

A solution can be a key pressed/released function and activate/deactivate walking speed. Maybe one just wants to change the hero speed anyway. The default walking speed is 88 pixels per second.

I think 150 pixels per second makes a very quick run.

  hero:set_walking_speed(150)

##### Swim Ability Setup

An ability needs to be set or activated before it can work.

game:set_ability("swim", 1)


The hero can swim in deep water once this ability is activated. One might want to change the hero tunic to a boat or something simple if one does not want a complex swim motion.

The swimming_fast and swimming_slow animations are required in the tunic sprite animation. You can press the action key c to swim faster.

### Quest Launcher

The quest launcher is a place where all Solarus games can be played from.

##### Activate Quest Launcher

Activating the quest launcher.

Preview

##### Game - Play & Stop

The logos/ directory can contain logos and icons to represent your game in the Quest launcher.

Christopho says, “The logo of your quest should be a PNG image of size 200x140 called logos/logo.png" The logo is optional.”

##### Quest Icons

An icon can also represent your game or quest. The icon is optional as well. Many icon sizes are allowed and every icon needs to be on a separate png. Icon sizes 16 x 16 to 1024x1024 pixels are allowed.

“logos/icon_16.png”,
“logos/icon_24.png”,
“logos/icon_32.png”,
“logos/icon_48.png”,
“logos/icon_64.png”,
“logos/icon_128.png”,
“logos/icon_256.png”,
“logos/icon_512.png”,
“logos/icon_1024.png”.

The Solarus GUI will automatically choose the best size.

### Save Game

Saving the game is quite simple. The game saves at the destination entity on the maps. There are two functions that need to be known. They are sol.game.exists(file_name) and sol.game.load(file_name). One checks if the save file exists and the other loads the save file. The best place to put the save script is in the game_manager.lua.

local exists = sol.game.exists(file_name)

--check if save exists and if not, then create a save file with the following default data.
if not exists then
--Initialize a new savegame
--Default game data
end


Example:

 local exists = sol.game.exists("save1.dat")
if not exists then
--Initialize a new savegame

game:set_max_life(12)
game:set_life(game:get_max_life())
game:set_ability("lift", 2)
game:set_max_money(100)
game:set_ability("sword", 2)
game:set_ability("sword_knowledge", 1)
game:set_ability("shield", 1)
game:set_ability("swim", 1)
game:set_ability("jump_over_water", 1)
game:set_starting_location("Map_4", "starting_destination") -- Starting location.
end


The best way to save the game is by using the d key and a simple dialog. By now you know that by default the d key pauses the game. The function game:save() saves the game by making a save file called save1.dat.

function game:on_paused()
game:save()
end
game:set_paused(false)
end)
end
end


game_manager.lua

require("scripts/menus/alttp_dialog_box")
require("scripts/multi_events")
require("scripts/hud/hud")

local game_manager = {}

-- Starts the game from the given savegame file,
-- initializing it if necessary.
function game_manager:start_game()

local exists = sol.game.exists("save1.dat")
if not exists then
--Initialize a new savegame

game:set_max_life(12)
game:set_life(game:get_max_life())
game:set_ability("lift", 2)
game:set_max_money(100)
game:set_ability("sword", 2)
game:set_ability("sword_knowledge", 1)
game:set_ability("shield", 1)
game:set_ability("swim", 1)
game:set_ability("jump_over_water", 1)
game:set_starting_location("Map_4", "starting_destination") -- Starting location.
end

game:register_event("on_started", function()

local hero = game:get_hero()
hero:set_tunic_sprite_id("main_heroes/eldran")
end)
game:start()

function game:on_paused()
game:save()
end
game:set_paused(false)
end)
end
end

return game_manager


You can find the save file in a folder called .solarus in your users directory. The engine creates a file called save1.dat by default when the game is saved. The file can be found in folder that is set in the Engine properties write directory. In my case the name is sample_quest.

users/user_name/.solarus/sample_quest

Example:

users/zefk/.solarus/sample_quest

The names in save1.dat that have an underscore before it are automatically created by the engine.

Other save values are created by entities or with the function game:set_value(savegame_variable_name, value). The value can be a string, boolean, or a number. game:set_value() is very useful when making custom scripts.

### Game Over

In this section we will be covering gameover. I will be using a quick simple script I made for this purpose. You can check out Christopho’s gameover script for something more complex. He creates a hero sprite that he unpauses and sets an animation.

Here is the script we will be covering.

game_over.lua



--Function to go under game:start() in save_menu.lua

local gameover = {

browse = 0,

yes_hover_img = sol.surface.create("game_over/yes_hover.png"),
no_hover_img = sol.surface.create("game_over/no_hover.png"),
idle_bg_img = sol.surface.create("game_over/idle_bg.png"),

yes_hover = true,
no_hover = false,
idle_bg = true,

up = true,
down = true,

up_sound = "none",
down_sound = "none",

}

--Set up and down sound
gameover.up_sound = "cursor"
gameover.down_sound ="cursor"

--The draw function for showing images

--Show idle-bg-hover image when conditions are true
if gameover.idle_bg == true then
gameover.idle_bg_img:draw(screen)
end

--Show yes-hover image when conditions are true
if gameover.yes_hover == true then
gameover.yes_hover_img:draw(screen)
end

--Show no-hover image when conditions are true
if gameover.no_hover == true then
gameover.no_hover_img:draw(screen)
end

end -- end draw function

--key function for pressing buttons

--Go down
if key == "down" and gameover.up == true then
sol.audio.play_sound(gameover.up_sound)
if gameover.browse < 1 then
gameover.browse = gameover.browse + 1
end
end

--Go up
if key == "up" and gameover.down == true then
sol.audio.play_sound(gameover.down_sound)
if gameover.browse > 0 then
gameover.browse = gameover.browse - 1
end
end

--Yes hover
if gameover.browse == 0 then
print("up")
gameover.yes_hover = true
gameover.no_hover = false

local map = game:get_map()

if key == "a" then

game:set_starting_location(map:get_id()) -- Starting location.
game:start()
game:stop_game_over()
end
end

--No hover
if gameover.browse == 1 then
print("down")
gameover.no_hover = true
gameover.yes_hover = false

if key == "a" then
sol.main.reset()
end
end
end -- end key pressed function
end -- end of function game_over_menu:start(game)



The script is called from the game_manger.lua.

local game_over_menu = require("scripts/game_over.lua")

game:register_event("on_started", function()

local hero = game:get_hero()

--Game over
print("life"..game:get_life())

function game:on_game_over_started()
local life = game:get_life()
if life == 0 then
sol.audio.play_sound("hero_dying")
end
end
end) -- end of game:register_event


The game parameter is passed through the save_menu.lua after game:start() just like the game_manger.lua.

game:start()

local game_manager = require("scripts/game_manager")

game_manager:manage(game)


The important functions in this script are game:stop_game_over() and function game:on_game_over_started().

game:stop_game_over() stops the function game:on_game_over_started() function. By default, the game starts over and restores health, but function game:on_game_over_started() is needed to make a custom death.

I set an animation called hero:set_animation("dead") and the animation dead is only one frame. The reason for this is that the game_over_started function suspends the game and it will stop any complex animation before it finishes. That is why it is best to use a sprite method because a sprite method can be unpaused. That is what Christopho does in his script.

     function game:on_game_over_started()
local life = game:get_life()
if life == 0 then
sol.audio.play_sound("hero_dying")
end
end


Okay, after starting the animation the death sound occurs and the game_over.lua menu is started. In the game over script you can start the game again game:start().

--Yes hover
if gameover.browse == 0 then
print("up")
gameover.yes_hover = true
gameover.no_hover = false

local map = game:get_map()

if key == "a" then

game:set_starting_location(map:get_id()) -- Starting location.
game:start()
game:stop_game_over()
end
end


Sample:

You can check out the sample in:
Lessons > Chapter_13_14_custom_entity_game_over.zip

## Chapter 15: Title Screen, Save menu, Movements, Map Types, Camera, I/O

This chapter is mostly about the remaining basics that need to be covered. You can get the sample Chapter_15_Sample.zip in the Lessons > Chapter_15 directory.

### Title Screen

Almost every game has a title screen. A place to start the game. The title screen I scripted for the section is fairly simple. The script can be found in the sample mentioned above because it is too long for the book.

This is a three (3) slot load save menu script. The player can make newgames and select the save slot they wish.

Features:

1. Change the action keys, music, and sounds in the change area(s)
3. Makes newgames

Install Instructions: Part 1

1. Put the save_menu.lua script in the directory scripts/ (get it from the chapter 15 sample).
2. Go to main.lua and add the following under the title screen on_finished function.

Example

  -- Start the game when the Solarus logo menu is finished.
solarus_logo.on_finished = function()
-- Show the title screen after the Solarus Logo

game_manager:start_game()
end
end

1. Put the folder “save_menu” that contains images for the menu in the directory sprites/

Install Instructions: Part 2

1. Add the following in the game manager.

Example:

require("scripts/menus/alttp_dialog_box")
require("scripts/multi_events")
require("scripts/hud/hud")

local game_manager = {}

-- Starts the game from the given savegame file,
-- initializing it if necessary.
function game_manager:manage(game)

--Change hero sprite ID
game:register_event("on_started", function()

local hero = game:get_hero()
hero:set_tunic_sprite_id("main_heroes/eldrina/eldrina")
end)

--This happens when the game is paused with the default pause key "D"
--Save the game
function game:on_paused()
game:save()
end
game:set_paused(false)
end)
end

function sol.main:on_key_pressed(key)

if key == "l" then
game:set_suspended(true)
end
end
end

return game_manager

1. I suggest making a menu with the default d pause key. The menu would be where the player would load and save the game. At the moment the d key saves the game in the sample.

Usage Instructions:

1. Use the up and down keys
2. Change the action key to what you desire in the change area. By default, it is key a, reset with s, and in game clear with q.
3. Key L activates the save menu in game and key q can clear it.

Breaking Down The Script:

The comments in the script cover everything in the script. There are a few functions I will go over.

The function sol.file.remove("file_name.dat") removes a file in the write directory. For this lesson the write directory is .users/your_name/solarus/sample_quest/. I used this function to remove the save file for a new game.

The function sol.game.exists("file_name.dat") checks if a file exists in the write directory. This is normally used to check if a save files exits and if not, then set default hero settings. For example, the hero’s health, item, abilities, and etc.

The function sol.game.load("file_name.dat") loads a saved file or creates one if none exist. It will not save it.

The function game:start() runs the game. Only one game can run at a time.

I do not know if I covered this, but let us say your hero dies. He will by default use the tunic animation instead of the tunic_sprite_id you set. You can use the function game:register_event("on_started", function() after starting the game to prevent this from ever happening.

game:register_event("on_started", function()

local hero = game:get_hero()
hero:set_tunic_sprite_id("main_heroes/eldran")
end)


### Movements

Movement Description String
Straight movement: Straight trajectory in any direction. “straight”
Random movement: A straight movement whose direction changes randomly from time to time. “random”
Target movement: Straight trajectory towards a possibly moving target. “target”
Path movement: Predetermined path composed of steps in the 8 main directions. “path”
Random path movement: Like a path movement, but with random steps. “random_path”
Path finding movement: Like a path movement, but calculated to reach a possibly moving target. “path_finding”
Circle movement: Circular trajectory around a possibly moving center. “circle”
Jump movement: An illusion of jump above a baseline. “jump”
Pixel movement: A trajectory described pixel by pixel. “pixel”
##### Create Movement

This is the basic structure for creating a movement.

local variable = sol.movement.create("movement_name")

variable:start(entity_name)


There are many movement functions and one should check the documentation for more.

##### Jump Movement

An illusion of jump above a baseline.

function map:on_started()

--Jump
local jump = sol.movement.create("jump")

jump:set_direction8(2)
jump:set_distance(100)
jump:start(elf_2)

##### Random Path Movement

Like a path movement, but with random steps.

 --Random_Path
local random_path = sol.movement.create("random_path")
random_path:start(elf)

##### Target Movement

Straight trajectory towards a possibly moving target.

The default target is the hero.

 --Target
--Default target is hero
local target = sol.movement.create("target")
target:set_speed(32) -- set speed
target:start(elf_4)


If one wants to target a different entity, then one has to use the function :set_target(entity_name).

 --Follow sprite "elf"
local target2 = sol.movement.create("target")

target2:set_speed(32)
target2:start(elf_5)
target2:set_target(elf)

##### Path Finding Movement

Like a path movement, but calculated to reach a possibly moving target.

 --Path finding (Go around obstacles)
local path = sol.movement.create("path_finding")

path:set_speed(69)
path:start(elf_6)
path:set_target(hero)

##### Random Movement

A straight movement whose direction changes randomly from time to time.

 --Random
local straight_random = sol.movement.create("random")

straight_random:start(elf_7)

##### Straight Movement

Straight trajectory in any direction.

You can set the angle to the following values to get basic directions, but you can use negatives and other values. I used 3 in straight:set_angle(3).

Angle Value
East 0
North math.pi / 2
West math.pi
South 3 * math.pi / 2
 --Straight
local straight = sol.movement.create("straight")
straight:set_angle(3)
straight:start(elf_3)

##### Path Movement

Predetermined path composed of steps in the 8 main directions.

 --Path
local path = sol.movement.create("path")

path:set_path{3,0,3,0,3,0,3,0,3,0,3,0,3,0,3,0,3}
path:set_speed(80)
path:set_loop(true)
path:set_ignore_obstacles(true)
path:start(elf_8)

##### Pixel Movement

A trajectory described pixel by pixel.

Pixel Movement needs a transition array.

Transition Example:

For 1 translation: table1 = {{244,270}}
For 2 translations: table1 = {{244,270}, {244,270}}


Pixel Movement Example:

 --Pixel movement
local pixel = sol.movement.create("pixel")

pixel:set_trajectory{{5,-5},{0,-1}}
pixel:set_loop(true)
pixel:set_ignore_obstacles(true)
pixel:start(elf_9)

##### Circle Movement

Circular trajectory around a possibly moving center.

 --Circle movement
local circle = sol.movement.create("circle")
circle:set_center(test)
circle:set_loop_delay(1000)
circle:set_angle_speed(100)
circle:set_duration(1000000)
circle:set_max_rotations(100)
circle:set_initial_angle(100)
circle:set_clockwise(true)
circle:set_ignore_obstacles(false)
circle:start(elf_10)

##### Walk through Entity

Instead of bumping into entities and getting trapped. I think it is best the walk through them. You can use the function entity:set_traversable(true/false) to walk through NPC, etc.

elf_4:set_traversable(true)
elf_6:set_traversable(true)


### Moving Image

Moving an image is almost the same as moving an entity. Let us use a 320x240 Solarus logo.

You can find everything in the sample in the following directory.

Lessons > Chapter_15 > Chapter_15_Movements_on_image.zip

Tip:
The Solarus screen zooms to 640x480, so the logo will enlarge.

An easy way to set this up is with a menu.

local solarus_logo_menu = {}



Setup Image & Make Movement:

Next we need to load/create the image and movement. We apply a movement to an image by starting the movement on the created surface variable.

  movement:start(logo_img)

local solarus_logo_menu = {}

local movement = sol.movement.create("straight")
movement:start(logo_img)
end

logo_img:draw(screen)
end



Movement properties:

We want:

• The image to move at a decent speed.
  movement:set_speed(128)

• The image angle to go south. South is 3 * math.pi / 2.
4 Directions Description
East 0
North math.pi / 2
West math.pi
South 3 * math.pi / 2
  movement:set_angle(3 * math.pi / 2)

• The image to not run off the screen, so we set the max distance.
  movement:set_max_distance(240)

• To draw the image off screen because it is an easy way to calculate max distance. We change the image’s y coordinates to -240 because we set the max distance to go down by 240. The image is 320x240.
  logo_img:draw(screen, 0, -240)

local solarus_logo_menu = {}

local movement = sol.movement.create("straight")
movement:set_speed(128)
movement:set_angle(3 * math.pi / 2)
movement:set_max_distance(240)
movement:start(logo_img)
end

logo_img:draw(screen, 0, -240)
end



• Setup a key press function with the key being space and stop the menu inside.
• Return true to activate function or you could change the order of your function.
• Return false to not activate the key press function for other keys, but not really needed.
• Return false and true are not really needed, but it is good practice programming wise.
function solarus_logo_menu:on_key_pressed(key)
if key == "space" then
return true
end
return false
end


Now the menu will move down and pressing the space key will stop it.

local solarus_logo_menu = {}

local movement = sol.movement.create("straight")
movement:set_speed(128)
movement:set_angle(3 * math.pi / 2)
movement:set_max_distance(240)
movement:start(logo_img)
end

logo_img:draw(screen, 0, -240)
end

if key == "space" then
end
end



One can remove the key press function and use a callback to stop the menu if you want the game to just start after the logo finishes.

 movement:start(logo_img, callback())

  movement:start(logo_img, function()
end)

local solarus_logo_menu = {}

local movement = sol.movement.create("straight")
movement:set_speed(128)
movement:set_angle(3 * math.pi / 2)
movement:set_max_distance(240)
movement:start(logo_img, function()
end)
end

logo_img:draw(screen, 0, -240)
end



### Map Types

I have covered a few map types already, but here are some more useful ones that I did not cover.

--Name of the map
map:get_id()

--Name of the world
map:get_world()

--Floor number
map:get_floor()

--Coorndinates in the world
map:get_location()

--Name of tileset
map:get_tileset()

--Name of music playing
map:get_music()


Example:

This example comes directory from the sample. Press key 5 and key 6 to try it out.

local example = {}
local test = {}
local map_functions = false

--Name of the map
example[1] = "Map: "..map:get_id()

--Name of the world
example[2] = "World: "..map:get_world()

--Floor number
example[3] = "Floor: "..map:get_floor()

--coorndinates in the world
example[4] = "Location: "..map:get_location()

--Name of tileset
example[5] = "Tieset: "..map:get_tileset()

--Name of music playing
example[6] = "Music playing: "..map:get_music()

--Display text
for rep = 1,6 do
--http://www.solarus-games.org/doc/latest/lua_api_text_surface.html
test[rep] = sol.text_surface.create({ -- name a local variable something and assign it to the sol.text_surface
font = "minecraftia", -- font name
text = example[rep], -- text you want to show
font_size = 12, -- font size obviously
rendering_mode = "antialiasing", -- "solid" (faster) and default
color = {240,248,255}, -- color must be in a table RGB (http://www.rapidtables.com/web/color/RGB_Color.htm)
})
end

--Draw text to screen
function sol.main:on_draw(screen)

if map_functions == true then
test[1]:draw(screen,10, 15)
test[2]:draw(screen,10,30)
test[3]:draw(screen,10,45)
test[4]:draw(screen,10,60)
test[5]:draw(screen,10,75)
test[6]:draw(screen,10,90)
end

end --end of draw function

--Display map types using key 5 and key 6.
function map:on_key_pressed(key)

if key == "5" then
map_functions = true
end

if key == "6" then
map_functions = false
end
end


You can also get the music you set for the map. This is useful for when playing a different music and wanting to go back to the default music for the map. Maybe you do not want to write a long directory name.

sol.audio.play_music(map:get_music())

##### Making a Map Entity

It is quite easy to make map entities with script. This can be useful for when spawing projectiles.

Example:

The following script is placed in a custom entity. If an entity named enemy overlaps it, then an custom entity arrow will spawn or appear.

local entity = ...
local game = entity:get_game()
local map = entity:get_map()
local enemy = map:get_entity("enemy")

--Create on_activated
sol.timer.start(500, function()
if entity.on_activated ~= nil then
entity:on_activated()
return true
end
end)

function entity:on_activated()
local x,y = entity:get_position()

if entity:overlaps(enemy)then
print("overlap")
map:create_custom_entity({
name = "arrow",
direction = 2,
layer = 0,
width = 16,
height = 16,
x = x,
y = y,
sprite = "entities/arrow",
})
end
end


### Camera Entity

The camera is an entity like a NPC. You can check the Documentation for the functions for all entity types. You need to get the camera before you can use it.

local camera = map:get_camera()

##### Camera Size

The camera size is what you can see on the screen. A size of (96,96) would be quite small compared to the default size of (320,240). The camera size function goes by 8 (8,16,24,32,40,48,56,64,72,80,88,96)

camera:set_size(96, 96)


You can set your screen back to normal with:

 --That is the default quest screen size.
camera:set_size(320, 240)

##### Camera Tracking

Changing the screen size can help with camera tracking when it comes to sprites.

The function camera:start_tracking(entity_name) is used for camera tracking. By default, the camera tracks where the hero goes.

        camera:set_size(96, 96)
camera:start_tracking(elf_6)

##### Camera Position

Normally, the camera position is centered at (0,0). You can change the position of the screen with the function camera:set_position_on_screen(x,y).

Example:

        camera:set_position_on_screen(120,60)


You can change it back to normal like this:

        camera:set_position_on_screen(0,0)

##### Camera & Movements

You can apply movements to the camera. The camera entity name is map:get_camera().

    local path = sol.movement.create("path")

path:set_path{2,0,2,0,3,0,3,0,3,0,3,0,3,0,3,0,3}
path:set_speed(80)
path:set_loop(false)
path:set_ignore_obstacles(true)

path:start(map:get_camera())

##### Camera Example Script

Press the keys 1, 2, 3, and 4 to test the camera. Key 2 sets everything back to default.

local map = ...
local game = map:get_game()
local hero = map:get_hero()
local camera = map:get_camera()

function map:on_key_pressed(key)

if key == "1" then
--Camera size goes by 8
camera:set_size(96, 96)
camera:start_tracking(elf_6)
camera:set_position_on_screen(0,0)
end

if key == "2" then
camera:set_size(320, 240)
camera:set_position_on_screen(0,0)
camera:start_tracking(hero)
end

if key == "3" then
camera:set_size(320, 240)
--Camera default position is 0,0
camera:set_position_on_screen(120,60)
camera:start_tracking(hero)
end

local path = sol.movement.create("path")

path:set_path{2,0,2,0,3,0,3,0,3,0,3,0,3,0,3,0,3}
path:set_speed(80)
path:set_loop(false)
path:set_ignore_obstacles(true)

if key == "4" then
--Use movements on camera
path:start(map:get_camera())
camera:set_position_on_screen(0,0)
end
end


### I/O - Input/Output

The I/O is writing and reading text from a file. The easiest way to do this is to just use the engine’s functions game:get_value and game:set_value.

game:set_value("variable_name", value/string)


Example:

--It might be easier to just store your values and strings in a save file.
--value
game:set_value("coordinate_z", 50)
print("Coordinate Z is: "..game:get_value("coordinate_z"))

--String
game:set_value("coordinate_question", "what")
print("Coordinate Question is: "..game:get_value("coordinate_question"))


However, you can write to files in other ways. You can use the function:

sol.file.open("file_name", "mode")

Modes: Decription:
“w” write mode
“a” append mode
“r+” update mode, all previous data is preserved
“w+” update mode, all previous data is erased
“a+” append update mode, previous data is preserved writing is only allowed at the end of file.
##### Opening, writing, and closing file

Writing by default creates the file. You must always remember to close a file with the function file_variable_name:close() or you risk memory leaks. You use the mode "w" to write and the function file_variable_name:write("text to show or", variable_value_to_show).

local file_variable_name = sol.file.open("example.txt", "w")

file_variable_name:write("blah")
file_variable_name:close()


Example:

local coordinate_x = 50
local coordinate_y = 40
local file_write = sol.file.open("example.txt", "w")
file_write:write("x:",coordinate_x, "y:", coordinate_y)
file_write:close()


You can use the mode "r" to read a file and the function string.find(file_variable_name, "string_to_look_for") to check if the string exists in the file.

local file_read = sol.file.open("example.txt", "r")
print(line)

if string.find(line,"0") then
print("zero")
end

##### Making New Lines

You can use sequences when writing to a file.

Sequence Description
\a bell
\b back space
\f form feed
\n newline
\r carriage return
\t horizontal tab
\v vertical tab
\ backslash
\” double quote
\’ single quote
[ left square bracket
] right square bracket

You can use formats for the function file_variable_name:read("Format"). I use the format "*a" in the example below to read all the text in the file.

Formats: Description
“*n” reads a number; this is the only format that returns a number instead of a string.
“*a” reads the whole file, starting at the current position. On end of file, it returns the empty string.
“*l” reads the next line (skipping the end of line), returning nil on end of file. This is the default format.
local file_make_file2 = sol.file.open("file2.txt", "w")

file_make_file2:write("The apple\nThe orange.\nThe limon.\nThe pear.\n")
file_make_file2:close()

print(line2)

##### File Seek: Grab a Variable

You can use file:seek to grab a variable or string, but this is not really the best way to do it. It is probably the easiest way without custom functions.

file_variable_name:seek (whence, offset)

Whence Description
“set” base is position 0 (beginning of the file);
“cur” base is current position;
“end” base is end of file;
local file_seek = sol.file.open("example.txt", "r")

--x:50y:40 in example.txt. -2 would be two from the end. (40)
file_seek:seek("end",-2)

--Convert string "40" to the number value 40
print("The variable is:"..tonumber(value))

print("The variable is:"..value + 5)

file_seek:close()

##### Read & Write Functions Script

This script will be very useful for managing read/write, but the easiest way to do this is to just use the engine’s functions game:get_value and game:set_value.

--Read line function
local file = sol.file.open(sPath, "r")
if file then
local tLines = {}
while sLine do
table.insert(tLines, sLine)
end
file.close()
return tLines
end
return nil
end

--Write line function
local function writeLines(sPath, tLines)
local file = sol.file.open(sPath, "w")
if file then
for _, sLine in ipairs(tLines) do
file:write(sLine)
end
file:close()
end
end

local file_make_test = sol.file.open("test.txt", "w")
file_make_test:close()

table.insert(tLines, "This is the first line!\n") -- Line 1
tLines[2] = "This is line 2!\n" -- Line 2
tLines[3] = "This is line 3!\n" -- Line 3
tLines[4] = 50 -- Line 4

table.remove(tLines, 2) -- Remove line 2
writeLines("test.txt", tLines) --Write lines to this file
print("Lines in the file: ", #tLines) --Print number of lines

--Open file. You must open the file to get the value

--Print line 3. Line 4 will not be 50 because we removed line 2. That means line 3 will be 50.
print("Line 4 value is: "..tLines[3])


You can ignore the functions, but it would be best to try to understand them. The only important part is after the functions.

Make the file test.txt.

--This makes the file test.txt.
local file_make_test = sol.file.open("test.txt", "w")
file_make_test:close()


The comments in the script below tell you how to use it.

local file_make_test = sol.file.open("test.txt", "w")
file_make_test:close()

table.insert(tLines, "This is the first line!\n") -- Line 1
tLines[2] = "This is line 2!\n" -- Line 2
tLines[3] = "This is line 3!\n" -- Line 3
tLines[4] = 50 -- Line 4

table.remove(tLines, 2) -- Remove line 2
writeLines("test.txt", tLines) --Write lines to this file
print("Lines in the file: ", #tLines) --Print number of lines

--Open file. You must open the file to get the value

--Print line 3. Line 4 will not be 50 because we removed line 2. That means line 3 will be 50.
print("Line 4 value is: "..tLines[3])


## Chapter 16: Make a Chain Quest, Bow, Boomerang, and Hookshot

### Chain Quest

The chain quest is putting together what you have learned, some new functions, and scripts are introduced. It is more like a demo than anything else.

### Sola House

Sola house is the starting point of the game. Sola has woken in a world with no memories of her past and sets out on a journey to figure out who she is.

### Sola House > F1

On the first floor there are some blockades that must be passed to exit the house. Also, an optional quest with the female armor. You will be able to perform spin attacks and have extra speed when the spirit gem is obtained.

##### Disabling Spin Attack

There are no function or method as of Solarus 1.5.3 that disables the spin attack, but there is a quick hack for it that I learned from MetalZelda.

This is accomplished by registering an event using the multi_events.lua script. What the script does is add a callback kinda like with timers.

Register event way:

-- local multi_events = require("scripts/multi_events")
-- Register two callbacks for the game:on_started() event:
game:register_event("on_started", function()
-- Some code.
end)


Normal way:

function game:on_started()
-- Some code.
end


The following code disables the spin attack until the save variable “skill_spin_attack” is set. It should be put in the game manager.

function game_manager:manage(game)

game:register_event("on_started", function()

local hero = game:get_hero()

hero:register_event("on_state_changed", function(hero, state)
if not game:get_value("skill_spin_attack") then
game:simulate_command_released("attack")
end
end
end) -- end of hero:register
end) -- end of game:register
end


First off, the register event with the function on_started:

game:register_event("on_started", function()
end) -- end of game:register


Secondly, we get the hero and register it with the function on_state_changed:

game:register_event("on_started", function()

local hero = game:get_hero()

hero:register_event("on_state_changed", function(hero, state)

end) -- end of hero:register
end) -- end of game:register


Thirdly, we want to apply it to the state “sword_loading” and simulate a release on “attack”.

game:register_event("on_started", function()

local hero = game:get_hero()

hero:register_event("on_state_changed", function(hero, state)
if not game:get_value("skill_spin_attack") then
game:simulate_command_released("attack")
end
end
end) -- end of hero:register
end) -- end of game:register


To enable the spin attack as I said above, just set the save variable. I normally do it in items. I put it in the spirit gem script in the chain quest.

function item:on_obtained()
game:set_value("skill_spin_attack",true)
end


The optional quest is just a bunch of save variable, elseif, and dialogs. I explained this in a previous chapter. Chapter 13 NPC Entity section.

-- Event called at initialization time, as soon as this map becomes is loaded.
function map:on_started()

--Spirit quest
function woman_armor:on_interaction()

if game:get_value("sola_house_gem_quest_finished")then
game:start_dialog("sola_gem.done.1")
elseif game:get_value("sola_house_yes") and not game:get_value("sola_house_gem") then
game:start_dialog("sola_gem.find.1")
elseif game:get_value("sola_house_yes") and game:get_value("sola_house_gem") then
game:start_dialog("sola_gem.yes.1", function()
hero:start_treasure("spirit_gem", 1, "sola_house_gem_quest_finished",function()
game:start_dialog("sola_gem.wonderful_day.1")
end)
end)
else
if answer == 4 then --No
game:start_dialog("sola_gem.no.1")
game:start_dialog("sola_gem.find.1")
game:set_value("sola_house_yes",true)
end
end)
end
end


The spirit gem was hidden in a pot by a demon. I use a npc entity above the pot tile and use on_interaction, then start_treasure. I set the save variable, so the hero can only get the treasure once. Very basic.


--Get spirit gem
function pot:on_interaction()
if not game:get_value("sola_house_gem") then
hero:start_treasure("spirit_gem", 1, "sola_house_gem")
end
end


I use a save variable again here, but with string instead of a true/false boolean.
block_pot is the NPC and flower wall is the dynamic tile. I set the skeleton disabled because I do not want the enemy to come back or respawn.


--The pot vanishes if the skeleton save string is "dead".
sol.timer.start(1000, function()
flower_wall:set_enabled(false)
block_pot:set_enabled(false)
skeleton:set_enabled(false)
end
return true  -- To call the timer again (with the same delay).
end)


The enemy called skeleton will be disabled until the switch on the second floor is activated.


--Skeleton disabled until save variable is set
if game:get_value("sola_house_switch_off") == nil then
skeleton:set_enabled(false)
end


The skeleton enemy is enabled and now can attack the hero. The wall entity and the table blockade is also disabled.


--Skeleton is enabled. Table and wall entity are disabled.
if game:get_value("sola_house_switch_off") == true then
skeleton:set_enabled(true)
table_wall:set_enabled(false)
wall:set_enabled(false)
end


For when the enemy dies the script sets the “sola_house_switch_off” to false from the skeleton enemy script. This is to make sure that nothing respawns when the player leaves the map and returns.


--Disables everything
if game:get_value("sola_house_switch_off") == false then
skeleton:set_enabled(false)
table_wall:set_enabled(false)
wall:set_enabled(false)
flower_wall:set_enabled(false)
end
end -- end of map on started

##### Skeleton.lua
function enemy:on_dead()
game:set_value("sola_house_switch_off", false)
end


A timer checking if the enemy is dead. It uses the method enemy:get_life(), but to be honest it would be better to use the functions entity:on_removed() or enemy:on_dead(). The timer in this case can effect the enemy’s explosion death animation.


--Create on_activated timer
sol.timer.start(2000, function()
if map.on_activated ~= nil then
map:on_activated()
return true
end
end)

--Timer that checks every 2 seconds
function map:on_activated()

--when the skeleton's life reaches zero, the skeleton save string is set.
if skeleton:get_life() == 0 then
end

--The pot vanishes if the skeleton save string is "dead".
flower_wall:set_enabled(false)
block_pot:set_enabled(false)
end

end -- end of on_activated


### Sola House > F2

Sets npc dialog “wall_switch_2” disabled and makes the wall switch active on return to the map because you do not want the player to activate it again.

-- Event called at initialization time, as soon as this map becomes is loaded.
function map:on_started()
--Set npc dialog "wall_switch_2" disabled and makes the switch active on return
if game:get_value("sola_house_switch_off",true) then
wall_switch_2:set_enabled(false)
wall_switch:set_activated(true)
end


Sets npc dialog “wall_switch_2” disabled and removed the blockages on the first floor by setting the save variable.


--disables npc and sets a save variable
function wall_switch:on_activated()
game:set_value("sola_house_switch_off",true)
wall_switch_2:set_enabled(false)
end
end


### Soulia Forest > Part 1

##### Hidden Switch

The switch is hidden under the trees with a flower on top to give a hint to its location. A sound is played when the switch is activated and the stump vanishes. Also, the check makes sure the switch cannot be activated again and to insure the stump does not respawn.

--Flower stump
function flower_switch:on_activated()
flower_stump:set_enabled(false)
sol.audio.play_sound("secret")
game:set_value("flower_stump",true)
end

--Flower stump check
if game:get_value("flower_stump") == true then
flower_stump:set_enabled(false)
flower_switch:set_activated(true)
end

##### Bomb Stump

The bomb is assigned to the x command slot by default in this script game:set_item_assigned(1, self). Although, one could just assign it to a key press function game:on_key_pressed(key, modifiers). The following script is simple and it creates a bomb at the player’s location for the hero’s facing direction.

items > bomb.lua

function item:on_created()

self:set_savegame_variable("bomb")
self:set_assignable(true)
end

function item:on_obtaining()
-- Automatically assign the item to a command slot
-- because it is the only existing item for now.
-- And we have no HUD.
game:set_item_assigned(1, self)
end

-- Called when the player uses the bombs of his inventory by pressing
-- the corresponding item key.
function item:on_using()

local hero = self:get_map():get_entity("hero")
local x, y, layer = hero:get_position()
local direction = hero:get_direction()
if direction == 0 then
x = x + 16
elseif direction == 1 then
y = y - 16
elseif direction == 2 then
x = x - 16
elseif direction == 3 then
y = y + 16
end

self:get_map():create_bomb{
name = "bomb",
x = x,
y = y,
layer = layer
}
self:set_finished()
end


The following script removes any entity that a bomb is placed on, but the entity has to be specified in the script. In this case it checks if a bomb is overlapping an entity “bomb_stump”. It uses the function map:get_entities_by_type() to check a list of strings with bomb name prefixes. Bombs are placed with a prefix if there is more than one on a map.

--Bomb stump
sol.timer.start(1000, function()
for bomb in map:get_entities_by_type("bomb") do
if bomb:overlaps(bomb_stump) then
function bomb:on_removed()
bomb_stump:set_enabled(false)
sol.audio.play_sound("secret")
game:set_value("bomb_stump",true)
end
end
end
return true
end)

--Bomb stump check
if game:get_value("bomb_stump") == true then
bomb_stump:set_enabled(false)
end


Furthermore, it is good to check if thebomb_stumpor any other entity still exists when using theentity:on_removed()function or you could get an annoying error message. I will explain that in more detail later.

      function bomb:on_removed()
if bomb_stump ~= nil and bomb_stump:exists() then
bomb_stump:set_enabled(false)
end
sol.audio.play_sound("secret")
game:set_value("bomb_stump",true)
end

##### Trick Chest

I previously presented the trick chest script in a previous chapter, but it is a pain to get the coordinates the previous way. This time I use thehero:start_hurt([source_entity, damage)method. All one has to do is get the entity from the map with its namemap:get_entity("trick_chest").

local entity = ...
local map = entity:get_map()
local game = entity:get_game()
local hero = map:get_hero()

function entity:on_created()
self:set_traversable_by(false)
entity:get_sprite():set_animation("closed")
end

local trick_chest = map:get_entity("trick_chest")

function entity:on_interaction()
hero:start_hurt(trick_chest, 6)
end


### Soulia Forest > Part 2

##### Key Stump

Since, making a door entity for a dynamic tile would be a total pain. I simply used a NPC to check if the chest that contain the key is open. Remember to set a save variable for the chest.

--Key stump
function key:on_interaction()
if key_chest:is_open() then
key_stump:set_enabled(false)
key_stump_hole:set_enabled(false)
game:set_value("key_stump",true)
key:set_enabled(false)
sol.audio.play_sound("open_lock")
end
end

--Key stump check
if game:get_value("key_stump") == true then
key_stump:set_enabled(false)
key_stump_hole:set_enabled(false)
end

##### Block Switch

This is simply moving a block on a switch. Nothing special. Remember to check the block’s coordinates when returning to the map.

--block switch
function hole_block_switch:on_activated()
game:set_value("hole_block_switch",true)
hole:set_enabled(false)
sol.audio.play_sound("secret")
end

--block switch check
if game:get_value("hole_block_switch") == true then
switch_block:set_position(856,668)
hole_block_switch:set_activated(true)
hole:set_enabled(false)
end


### Chain Village

Chain village is where almost all of its people have fallen to death due to a strange power coming over the mountains. The heroine must get a heart shield to show the mage that she is worthy of entering Zark house. The reason is that there is a slime enemy in there. Afterwards, thee heroine finds the water shield after defeating the slime and is able to cross the lake to the Water house and get the spirit shield to enter Elfa House. This is where the mini dungeon resides.

chain_village.lua

This is a check for leaving the map after the heroine shows that she is a true hero and removes the magic barrier from Zark house. This is so the door will not close up again.

--Shows that she is a true hero check
if game:get_value("shows_heroism") then
heart_door:set_enabled(true)
else
heart_door:set_enabled(false)
end


This is a check for when the heroine gets the spirit shield and is able to enter Elfa house. This is so the door will not close up again.

--Obtains the spriti shield check
if game:get_value("spirit_shield") then
elfa_house_door:set_enabled(true)
else
elfa_house_door:set_enabled(false)
end


This is for when the hero tries to enter a blocked door. In this case when the hero enters the door she is damaged and sent back by a evil spirit. An animation with stars over head and sound is played.

-- Call a function every half second
-- Damaged when overlapping elfa house doorway
sol.timer.start(500, function()
if hero:overlaps(elfa_house_door) and elfa_house_door:is_enabled() == false then
sol.audio.play_sound("danger")
hero:start_hurt(elfa_house_door, 1)
game:start_dialog("evil_spirit")
hero:walk("66",false,true)
hero:set_animation("bubble_stars")
end
return true
end)


The hero interacts with the mage NPC and she checks if the heroine has a heart shield. I use the game:has_item()method to check this without a need for a save variable.

 local has_heart_shield = game:has_item("heart_shield")

--Checks if the her has a heart_shield and diables the barrier is she does.
function sprite:on_interaction()
if has_heart_shield and not game:get_value("magic_gone") == true then
game:start_dialog("heart_shown", function()
game:set_value("shows_heroism",true)
heart_door:set_enabled(true)
game:set_value("magic_gone",true)
sol.audio.play_sound("teleporter")
end)
elseif not has_heart_shield then
game:start_dialog("show_heart")
end

--A check for when the barrier is removed. A new dialog.
if game:get_value("magic_gone") == true then
game:start_dialog("heart_luck")
end
end


The heroine is pushed back if she tries to enter before the barrier is vanquished.


-- Call a function every second.
--If the heroine tries to enter zark house if barrier is active, then she is flung back with a suprise bubble.
sol.timer.start(100, function()
if hero:overlaps(magic_info) and not game:get_value("magic_gone") == true then
hero:walk("66",false,true)
hero:set_animation("bubble_surprise")
game:start_dialog("magic_barrier")
else
magic_info:set_enabled(false)
end
return true
end)


### Chain Village > Shop

The shop is the only place where the heroine can obtain the heart shield. It costs 20 gems.

### Chain Village > Zark House

Okay, I menttioned above in soulia forest that I would explain more about the functionentity:on_removed(). One must check if it is nil or exists if an entity is placed in the functionentity:on_removed().

--When slime is removed
--Bookcase vanishes and chest is revealed behind it
function slime:on_removed()
if bookcase ~= nil and bookcase:exists() then
bookcase:set_enabled(false)
end

if chest ~= nil and chest:exists() then
if not chest:is_open() then
sol.audio.play_sound("secret")
end
end

game:set_value("zark_house_enemy_defeated",true)
end


Otherwise, you will get an errors like when leaving the map. For instance:

Error: In on_removed: [string "maps/chain_village/zark_house.lua"]:21: attempt to index global 'chest' (a nil value)

Error: In on_removed: [string "maps/chain_village/zark_house.lua"]:17: attempt to index global 'bookcase' (a nil value)


A better soultion in this case would be function enemy:on_dead() because in this case the script is working with a slime enemy.

--When slime is dead
--Bookcase vanishes and chest is revealed behind it
bookcase:set_enabled(false)

if not chest:is_open() then
sol.audio.play_sound("secret")
end

game:set_value("zark_house_enemy_defeated",true)
end


This is to just check to make sure the bookcase and sline do not return.

--Slime and bookcase return check
if game:get_value("zark_house_enemy_defeated") == true then
bookcase:set_enabled(false)
slime:set_enabled(false)
end


### Chain Village > Water House

Interacting with the book makes the bookcase vanish.

--Interacting with the book npc makes bookcase vanish and reveal wall switch
function book:on_interaction()
if not game:get_value("water_house_book") then
game:start_dialog("water_house.book", function()
bookcase:set_enabled(false)
sol.audio.play_sound("open_lock")
game:set_value("water_house_book",true)
end)
end
end

--Checks if book is active and makes sure the bookcase stays gone when returning to the map.
if game:get_value("water_house_book") == true then
bookcase:set_enabled(false)
end


Removed the wall blockade and the shadowing belonging to it, which is just a dynamic tile shadow.

--Removes wall and its shadow
--Sets wall switch save variable
function wall_switch:on_activated()
blockage:set_enabled(false)
game:set_value("water_house_wall_switch",true)
end

--Checks to make sure the blockage and shadow is disabled when returning to the map.
if game:get_value("water_house_wall_switch") == true then
wall_switch:set_activated(true)
blockage:set_enabled(false)
end


A series of switches and checks to make sure the chest appears to obtain the spirit shield. The comments say everything.

--switch 1 enables switch 2 and it appears
function switch_1:on_activated()
switch_2:set_enabled(true)
end

--switch 2 makes a chest appear and plays a sound.
function switch_2:on_activated()
chest:set_enabled(true)
sol.audio.play_sound("secret")
game:set_value("water_house_floor_switch",true)
end

--Checks to make sure the chest and switch_2 are not visible when entering the map
if switch_1:is_activated() == false and switch_2:is_activated() == false then
chest:set_enabled(false)
switch_2:set_enabled(false)
end

--Checks to make sure the switches stay active and the chest/switch_2 is visible on returning to the map
if game:get_value("water_house_floor_switch") == true then
switch_1:set_activated(true)
switch_2:set_activated(true)
chest:set_enabled(true)
switch_2:set_enabled(true)
end


### Chain Village > Elfa House

##### Cutscene

A cut scene is just a series of movements and dialogs. Commonly, the player cannot move during these events and pictures scenes are displayed.

In this case a NPC named Elfa runs toward the hero. At the same time the hero runs toward Elfa. The hero:walk method freezes the hero until the movement is over. Once the hero:walk function is finished the hero can move again, so we must freeze her with the method hero:freeze(). Usually, one would not want the HUD to show when the image appears during a cut scene. In that case, we would set our HUD to false and we are using christopho’s hud, so it would be game:set_hud_enabled(false). It will not be found in the documentation. Once the cut scene is over we want to unfreeze the hero using the method hero:unfreeze() and set a save variable because we do not want the cut scene to repeat.


local map = ...
local game = map:get_game()

--Set a boolean for image
local elfa_separate_cutscene = false

local night_background = sol.surface.create("background/fantasy_background.png")

-- Event called at initialization time, as soon as this map becomes is loaded.
function map:on_started()

--Cutscene
if not game:get_value("end_of_cutscene") then
hero:walk("22222222222")
local elfa_movement = sol.movement.create("path")
elfa_movement:set_path({6,6,6,6,6,6,6,6,6,6})
elfa_movement:set_speed(88)
elfa_movement:start(elfa, function()
sol.timer.start(map, 500, function()
hero:freeze()
game:start_dialog("elfa_house.elfa", function()
game:set_hud_enabled(false)
elfa_separate_cutscene = true
sol.timer.start(map, 1000, function()
game:start_dialog("elfa_house.night_background", function()
sol.timer.start(map, 1000, function()
game:set_hud_enabled(true)
elfa_separate_cutscene = false
hero:unfreeze()
game:set_value("end_of_cutscene",true)
end)
end)
end)
end)
end)
end)
end

--Display image
function map:on_draw(dst_surface)
if elfa_separate_cutscene then
night_background:draw(dst_surface)
end
end


The hero must find a secret passage to enter the dungeon and it is heavely hinted in the dialog that it is under a bookcase. A passage will be shown when the hero interacts with the bookcase. In this case, a custom entity is used for the interaction because it can be resized to fit the length of the bookcase.


--Dungeon entrance bookcase
function bookcase:on_interaction()
game:start_dialog("elfa_house.bookcase", function()
sol.audio.play_sound("switch")
large_bookcase:set_enabled(false)
end)
end
end


### Chain Village > Underground

##### Green Orc Soldier

First off, I would like to explain the orc soldier on this map because he is a little unique. The soldier consists of two sprites. The orc and the sword to be precise. The orc is invincible and can only be disabled by hitting his sword. I set it up so when the first orc is tapped 3 times, then the bookcase vanishes.

Let me break down how I do this. I first make the orc body and sword ignore all attacks with the method enemy:set_invincible_sprite(). Then I gave the sword a custom consequence with the sword using method enemy:set_attack_consequence_sprite(sword_sprite, "sword", "custom") . Afterward, I used thefunction enemy:on_custom_attack_received(attack, sprite) to set what happens when the sword is hit by the hero. In the green_orc_soldier.lua I use a boolean to check when to immobilize using the method enemy:immobilize(), but one could just use a timer instead.

Timer example:

function enemy:on_custom_attack_received(attack, sprite)

if attack == "sword" and sprite == sword_sprite then
sol.audio.play_sound("sword_tapping")
print("tapped")

local hero = enemy:get_map():get_entity("hero")
local angle = hero:get_angle(enemy)
local movement = sol.movement.create("straight")
movement:set_speed(128)
movement:set_angle(angle)
movement:set_max_distance(500)
movement:set_smooth(true)
movement:start(enemy)
--immobilize orc
sol.timer.start(1000, function()
enemy:immobilize()
end)
tapped = tapped + 1
print("tapped: ", tapped)
end
end

##### green_orc_soldier.lua
local enemy = ...

local game = enemy:get_game()
local map = enemy:get_map()
local hero = map:get_hero()
local body_sprite
local sword_sprite
local movement
local immobilize = false
local tapped = 0

function enemy:on_created()

body_sprite = enemy:create_sprite("enemies/green_orc_soldier")
sword_sprite = enemy:create_sprite("enemies/green_orc_soldier_sword")
enemy:set_life(140)
enemy:set_damage(0)
enemy:set_size(16, 16)
enemy:set_origin(8, 13)

-- Make the sword and body sprite ignore all attacks.
enemy:set_invincible_sprite(sword_sprite)
enemy:set_invincible_sprite(body_sprite)

-- Except the sword.
enemy:set_attack_consequence_sprite(sword_sprite, "sword", "custom")
end

if attack == "sword" and sprite == sword_sprite then
sol.audio.play_sound("sword_tapping")
print("tapped")

local hero = enemy:get_map():get_entity("hero")
local angle = hero:get_angle(enemy)
local movement = sol.movement.create("straight")
movement:set_speed(128)
movement:set_angle(angle)
movement:set_max_distance(500)
movement:set_smooth(true)
movement:start(enemy)
immobilize = true
tapped = tapped + 1
print("tapped: ", tapped)
end
end

--Create on_activated
sol.timer.start(2000, function()
if enemy.on_activated ~= nil then
enemy:on_activated()
return true
end
end)

function enemy:on_activated()

print("activate")

if immobilize == true then
enemy:immobilize()
end

if tapped >= 3 then
game:set_value("underground_tapped_3_times",true)
end

local distance_to_hero = hero:get_distance(enemy)

if distance_to_hero < 100 then
movement = sol.movement.create("target")
movement:set_target(hero)
movement:set_speed(48)
movement:start(enemy)
immobilize = false
else
movement = sol.movement.create("random")
movement:start(enemy)
immobilize = false
end
end

function enemy:on_movement_changed()

body_sprite:set_direction(movement:get_direction4())
sword_sprite:set_direction(movement:get_direction4())
end

##### Underground Map

I do not present anything new with this map, so nothing to explain. The only difference was with green_orc_soldier.lua because when it is tapped three times a save variable is set when the sword it hit three times.

local map = ...
local game = map:get_game()
local hero = map:get_hero()

-- Event called at initialization time, as soon as this map becomes is loaded.
function map:on_started()
game:set_value("boss_map",true)
game:set_value("scrolling_credits",true)

function leaver_1:on_activated()
wall_1:set_enabled(false)
game:set_value("underground_leaver_1",true)
end

if game:get_value("underground_leaver_1") == true then
leaver_1:set_activated(true)
end
end

function door_1:on_opened()
print("opened door")
end

sol.timer.start(1000, function()
if game:get_value("underground_tapped_3_times") == true then
bookcase_1:set_enabled(false)
end
if door_1:is_opening() == true then
end
return true
end)


### Chain Village > Underground Boss

The underground boss was originally supposed to be the mini boss, but I decided to make it the boss because the orcs were hard enough. The script uses the map:get_entities() function to grab all the solid switches on the map. Thanks to Max on the Solarus forum. The skeleton boss is immortal and can only be hurt when all switches are active. The hero has 5 seconds to damage the skeleton before he reverts to being immortal.

local map = ...
local game = map:get_game()

-- Event called at initialization time, as soon as this map becomes is loaded.
function map:on_started()

local switches_on= 0

for switch in map:get_entities("solid") do
function switch:on_activated()
switches_on = switches_on + 1
if switches_on >= 4 then
switches_on = 0
timer_sound = sol.timer.start(5000, function() deactivate_switches() end)
timer_sound:set_with_sound(true)
end
end
end

function deactivate_switches()
for switch in map:get_entities("solid") do
switch:set_activated(false)
end
end

end


Sample:

Lessons > Chapter_16 > Chapter_16_Chain_Quest.zip

### Bow

The methodhero:start_bow()activates the bow and shoots an arrow. The bow animation is needed for your hero and the sounds bow.ogg and arrow_hit.ogg.

Animation:
Bow

Sounds:
bow.ogg
arrow_hit.ogg

Script Sample:

A key press function can be used to activate the bow. In the sample, I put it in thegame_manager.luascript.

 function game:on_key_pressed(key)

local hero = game:get_hero()

--Bow & Arrow
if key == "a" then
hero:start_bow()
end
end


### Boomerang

The boomerang has more detail than the bow. The boomerang will return to the hero or chase the hero if moving away from the boomerang.
hero:start_boomerang(max_distance, speed, tunic_preparing_animation, sprite_name)

Boomerang Description
max_distance (number) Maximum distance of the boomerang’s movement in pixels.
speed (number) Speed of the boomerang’s movement in pixels per second.
tunic_preparing_animation (string) Name of the animation that the hero’s tunic sprite should take while preparing the boomerang.
sprite_name (string) Sprite animation set to use to draw the boomerang then.
Source http://www.solarus-games.org/doc/latest/lua_api_hero.html#lua_api_hero_start_boomerang

Preparing Animation:

In the sample, the tunic_preparing_animation is boomerang1.

hero:start_boomerang(60, 50, "boomerang1", "main_heroes/boomerang")

Sprite Name:

The boomerang name in the sample is boomerang and I put it in the main_heroes directory.

hero:start_boomerang(60, 50, "boomerang1", "main_heroes/boomerang")

Sounds:

The boomerang needs the sound boomerang.ogg and sword_tapping.ogg.

The boomerang.ogg sound repeats when it is activates and the sword_tapping.ogg actives when encountering something.

Script Sample:

A key press function can be used to activate the boomerang. In the sample, I put it in thegame_manager.luascript.

 function game:on_key_pressed(key)

local hero = game:get_hero()

--Boomerang
if key == "b" then
hero:start_boomerang(60, 50, "boomerang1", "main_heroes/boomerang")
end
end


### Hookshot

The method hero:start_hookshot() can be used to activate the hookshot.

Animation:

The hookshot requires a sprite in the sprites entities section. The sprite name needs to behookshotand needs two animations. Those animations are called hook and link for the chain.

Sounds:

The hookshot reqiures the sounds hookshot.ogg and sword_tapping.ogg.

The hookshot.ogg sound repeats when it is activates and the sword_tapping.ogg actives when encountering something.

Script Sample:

A key press function can be used to activate the hookshot. In the sample, I put it in thegame_manager.luascript.

 function game:on_key_pressed(key)

local hero = game:get_hero()

--Hookshot
if key == "h" then
hero:start_hookshot()
end
end


Sample:

Lessons > Chapter_16 > chapter_16_bow_hookshot_boomerang.zip

## Chapter 17: Game Design Walkthrough

##### Enemy Types
Enemy_Types Description
Boss A boss is the strongest enemy in a dungeon or any other location. They are difficult to beat and sometimes are cannot be beaten unless their weakness is found.
Miniboss They are basically weak bosses. They are strong, but not really unbeatable. It is common to gain a weapon by defeating them and that allows the player to defeat the boss in that location.
Enemy Simple to defeat. Should not take more that a few projectiles or sword hits to take down.
##### Enemy Attack Patterns

These attack patterns are normally used by all enemies. Some foes are only one of these types, but minibosses and bosses normally have more than one type.

Attack_Pattern Description
-flation This boss either gets bigger after each strike the player inflicts on it or smaller. The hero and boss become easier to hit when the boss inflates. When the boss deflates it takes a longer time to get to the hero and its small size might be hard to hit because it is not a big balloon.
Item This boss is normally impossible to beat as long as he has his special item. (Staff, ring, etc)
Condition This is a normal type of enemy. Requires one weapon to defeat it.
Multi-condition This type of enemy is normally a boss. Sometimes the hero will have attack more than just the boss to do damage. For example, the hero will have to take out the bubbles, hit the enemy with an arrow, and strike it with the sword to make the enemy take damage.
Wack the Whistle This enemy hides in a hole and comes out to attack.
Terrain This type of enemy uses the terrain to attack the hero. For example, falling spikes or rocks. Also, it can spin the terrain or bump up the edges to make the hero go off balance.
Grab and throw This type of enemy grabs and throws the hero.
One with Terrain This type of enemy becomes one with the terrain. For example, an enemy can cover itself with water and attack. A good way to defeat this type would to know where the core is.
The Phantom A enemy that normally floats, becomes invisible, and hides in a shadow. An item is normally needed to see it and/or light based attacks to cause damage. A phantom can use curses to hurt the hero when they try to cause damage. That curse only lasts a few seconds or a condition needs to be met to break it.
The deflectors The projectile attacks need to be deflected and bounced back at the enemy in order for the foe to take damage. The enemy might be able to deflect back.
Projectile seeker This enemy shoots projectiles and sometimes the projectile will follow the hero.
Hammer This type of enemy rises in the air and slams down to the ground like a hammer.
Clone These types of enemies can clone themselves and the only way to defeat them is to take out the original or quickly defeat them all.
limp-flation This enemy either inflates its limps to make them bigger or ejects their limbs like a hookshot. This type of enemy normally protects its limps, so it will not take damage.
Floor mover This type of enemy works with the floors. It can change its location and bounce off the walls at a rapid pace. For example, they can bounce off the walls by bouncing, spinning, climbing, using magic, flipping, and with their blades.
The magician The magician is similar to the Phantom, but it normally uses magic tricks. For example, runs into a mirror, teleport, strikes with magic, turns into objects, protects itself in a hat, etc.
Dark hero This is a dark version of the hero. Normally encountered in other worlds or dimensions.
Weapon This type of enemy fight with weapons.
Distancer This enemy normally hides on the ceiling, jumps on pillars, and/or flys at a distance. That way this flying foe does not take damage until it comes down to attack.
Duplicator This type of enemy divides based on the damage that is being taken.
Color warning This enemy display warnings that tells the hero what kind of attack it will use or how rapid its strikes will be. It does not have to be colors to be honest.
Monster commander This type of enemy can produce weaker enemies to attack the hero.
Suicide Bomber This type of enemy kills itself to harm the hero in an explosion.
Time traveler This enemy can restore its health by time traveling its body. A normal effect is that it gets distorted and weakened as it keeps doing it.
The eater This type of enemy eats the hero for a short time and spits the hero out.
Damaged by terrain only This enemy can only be harmed by something in the terrain. A special root or statue with special powers.
Drag down This type of enemy drags the hero down. Normally resulting in going to a different floor.
Transformer This enemy changes and gets stronger the more it is attacked.

Check the following link for examples of bosses:

http://zelda.wikia.com/wiki/Boss

##### Puzzles

Everyone knows that puzzles are very important in any RPG. The wonder of knowing what will happen when solving them or just the wanting to defeat the annoying bugger.

Puzzle_Type Description
Puzzles: A puzzle is a game, problem, or toy that tests a person’s ingenuity or knowledge. In a puzzle, one is required to put the pieces together in a logical way, in order to arrive at the correct solution of the puzzle. Many beings can tell puzzles, whether they are magical or not.
Block Puzzle The Block Puzzle involves moving shapes or plain blocks into a certain position, or the rearranging of blocks to form an image/picture. This may be to press a switch, to create a step which can be used to gain high ground, to put blocks color/colour order, move the block into a hole, etc.
Return Puzzle The most common puzzle is the return puzzle, a puzzle in which a player must depart from a room and return again with an extra item or key, making that room passable. This can be the case with dungeon rooms with multiple exits.
Enemy Puzzle The Enemy Puzzle involves a room or area in which one or several enemies must be defeated to move on. There are three common forms. Enemy, miniboss, and boss.

Multiple foes: This is where the player has to defeat multiple enemies in the same room. They are normally much weaker than the hero and sometimes they must be defeated in a certain order. A rewards can be gained from defeating the enemies in different orders.

Mini Boss: The mini boss is normally encountered inside dungeons. The common reward is a new weapon or item for their defeat. Sometimes they even use an item similar to what the player will gain. They are often difficult to defeat, but not as hard as a boss.

The boss: The player must defeat this enemy in order to pass or beat a dungeon. They are normally the most difficult foe in the dungeon to defeat. The hero normally becomes stronger in some way due to defeating them. For example, the strength gain can be more health or stronger strikes against certain types of foes.
Switch Puzzle Switches in the form of levers and buttons are used quite often and many more types can be used. For example, crystals, organic organs, and other things can be used as switches. There is really no limit on the type of switch.
Lever: Needs to be pushed or pulled. Some inaccessible levers require use of the Hookshot (pull), Seed/nut Shooter (push), or Bombs (for timing).
Button: Many types exist, but can be broken down into the form of weight. The weight of a block might need to be removed from a button or weight might need to be put on it, sometimes there is an item to use if the player is not heavy enough to push it. The switches can have a timer on them, meaning the player might need to hurry or the switch will have to be stepped on again.
Target Puzzle: The Target Puzzle is normally used to open a door or in some way to help the hero reach the next floor. For example, shooting an object above a door, with a projectile weapon, can open that door. The puzzle can be made more difficult in a few ways. For example, the target can be moving or the movement might be from a platform the player is standing on. Furthermore, other objects or enemies might be moving in the hero’s way! Another example, can be to activate floating objects in a certain order to reach the next floor. Weapons used are normally slingshot, bow, crossbow, and gun.
Force of Nature Puzzles: I have noticed that wind and other forces of nature can be used to make puzzles as well. The player or objects like a bomb can move to certain points and be shot around due to the forces, like wind or maybe even plant life.
Torch puzzle: This might be considered a force of nature, but this deserves a whole puzzle of its own. The Torch Puzzle involves the lighting of one or more torches by fire in order to receive access to another room, treasure chest, or something similar.
Riddle Puzzle: This is normally a word based puzzle and can require doing a type of action or even wearing certain garment. Sometimes bad occurrences can happen for getting the answer wrong. The player or character can be hurt/killed, or be forced to fight a bunch of enemies. A lot of time there can be more deadly cases, but not many people do this anymore. The player’s life force can decrease permanently, etc. For example, you could be cursed permanently or for a certain amount of time. The curse could have a good side too, and another riddle might be needed to break it! Do you want to?
Location Change Puzzle: Locations can be used as puzzles. For example, the location might look exactly the same, no matter where the player goes. The player is not “always” teleporting to the same spot, but is going to a similar location. The Lost Woods in Zelda is a good example. Also, areas or dungeon rooms can switch in a different order. This might not always be a puzzle because it could be completely random. Another example, time can be used to follow a character in a location and if the player gets too far behind, then the player will not be able to pass the puzzle for getting to the next location.
Source: https://en.wikipedia.org/wiki/Puzzle
##### Quest Types

One must think of quest types in order to make a proper story. Meeting characters can involve rescue quests, etc. Also, do not think that quests types will make your game unique every time because many characters have something unique about them. It can be a weird personality flaw, a way of living or something different about their body, but we will get more into that later. Let us start with quest types!

Quest_Type Description
Kill quests The character must go out and kill a specific number of creature types, or a particular non-player character and the short way to say that is NPC. These kinds of quests involve bringing back evidence of success, such as trophies or something belonging to the being. (Staff, tusks, head, etc.)
Combo quests The player will attack certain foes or structures with a combination of attacks until the necessary number of combos has been reached. Foes in these quests are normally either immortal or infinite in amount until the player character is victorious in which the foes would be eliminated or stop appearing.
Delivery quests A quest type called the delivery quest or fetch-carry quest. This is a situation where the character is sent to deliver or obtain an item from one place to another. In certain cases the character might need to collect the object first instead of being handed the item to deliver when beginning the quest. These quests are created to be difficult by asking the character to journey through different or dangerous terrain, sometimes with a time limit.
Gather quests Gather quests, also known as collection quests, call for a player character to collect a specific amount of items. These can either be gathered from a place or environment, or need the player to kill creatures to obtain the required items. The quest could also require the character to gather a number of different items. For example, to assemble a device.
Escort quests The Escort quest is a combination of defeating creatures to protect a non-player character(s) all while investigating an area alongside that Non-player character (NPC). A normal escort quest would have the player defending a NPC as he, it (3rd,4th, etc gender), or she moves through a monster-infested area. Most of the time the quest will force the player to kill many monsters to ensure the well-being of the NPC. Escort quests can be beneficial, in making the player’s pay attention to a particular spot in order to play out a scene or reveal a section of the plot. They can also be used to transport a character from one location to another, leading the player along a route or path. However, problems with this type of quest can occur if the artificial intelligence controlling the NPC causes them to behave in unexpected or unmanageable ways. Because many of them are often done wrong, they are very unpopular among the gaming community.
Syntax quests A phenomenon unique to text-based games, syntax quests depend on guessing the correct syntax to use to carry out a (typically simple) operation. For instance, arranging stone tablets in a certain order to make a picture or figuring out how to read the sentence and carrying out a certain action. It mostly involves arranging something in a certain order to figure out the meaning.
Hybrids Parts of the above quest types can be put together to make more complex quests. For instance, a quest could need that the player locate the pieces needed to assemble a certain weapon or item (Gather Quest) and then use it to defeat a specific foe (Kill quest). Hybrid quests can also involve puzzles and riddles.
Quest chains A quest chain is a group of quests that are completed in sequence they are also known as quest lines. Completion of each quest is a prerequisite to beginning the next quest in the chain. Quests usually heighten in toughness as a character goes further along the chain. The quests normally shows a single plotline in an order that explains the reason for the quests. Quest chains can also start with the opening or breadcrumb quests, in order to encourage characters to journey to a new area, where further elements of the quest chain are revealed. Through mechanisms like these, the setting of a particular location is explained to the player, with the plot or storyline being unveiled as the character progresses.
Source: https://en.wikipedia.org/wiki/Quest_(video_gaming)
##### Map Design

Map design can take up a lot of time. It is best to get quick ideas from generators. Donjon Dungeon Generator

Telling you how to design your map is almost impossible because there is no right way, but I will give basic tips.

Tip Description
Cludder Do not put too many objects on one map unless it is like a junk yard or something like that.
Duplicate objects The same objects all over the place would look weird. The same flower pot appearing in a room 10 times would look unnatural.
Spacing Try to keep decent space when making a map. For example, one will want to get around the chair.
Larger Rooms Small rooms are okay for houses, but in main locations they should be a bit more complex. For example, a square room after every door might get boring.
Outline One should outline the map with basic tiles first because if one were to change things later after mapping, then it might look bad or a lot of things might need to be moved around. A complete map redesign can be needed in some cases when a change is decided.
Doors Doors are always good to have because there is just that wonder of what is on the other side. Having the door locked is even better because it is like a forbidden special place.
Plant Life Plant life (EX: Vines) around windows and other places can make maps look natural and not so plain.
Stairs Going up to another level or floor can be as exciting as opening a door. What is up there? A stairway that is blocked can be more interesting.
Hidden Floors Finding hidden floors can make the hero feel special and enjoy exploring the map more.
World Name The world having a name can help you with your map organization. You do not want to get lost in over 100 maps.
Challenging Getting through a map too easily can be a drag! Make it at least a little tough or have some locations that can be seen, so the player will not want to leave the map as soon as possible.
Heal Spots Having spots to rest and people there to give one information is good way to not make a player mad while playing the game.

Border:

Room:

Down Stairs:

Up Stairs:

Closed Door:

Monster door:

No door way:

One way in door:

Map Examples:

##### Dungeon Layout
• In a dungeon you start by finding the key item.
• Paths to the item are blocked by locked doors.
• A hero diverts from the main path to get keys to those locked doors.
• The hero will find obstacles that you cannot pass without the key item.
• Once the hero gets the key items, the hero can get to the boss key and door.
• Some dungeons have places where the hero can get multiple keys at one time or require two keys for a door.
• Dungeon maps are found quite early.
• Dungeons have large areas to explore in a maze like order.
• Dungeons sometimes have optional rooms for other items.
• All other dungeons follow this pattern and repeat this pattern for more complex dungeons.

##### Sidescroller: Some Information

Sidescrollers or Platformers are normally constant action and almost no dialog. The movement normally never stops and the player stomps on or fights enemies all the way. This type differs from an ARPG in many ways. An ARPG is normally based on exploration with a top-down view (under a 3/4 perspective) and a platformer is just a straight line most of the time. Sidescroller graphics are always a side camera view. Sidescrollers can be anything someone wants them to be though. Some people mix ARPG and sidescroller or make the sidescroller a journey instead of constant action.

Some Movements:
Jump
Crouch
Hover
Run
walk
Look up
Pound
Push
Random Feature Dump: Description
Bouncers A object that makes the player jump higher when it is jumped on.
Speed Objects Objects that change speed on impact.
Floating Objects They are floating objects in the air.
Growing Objects This object grows when something is planted. Normally a seed that grows a giant plant. That way the player can climb or walk up it.
Falling Tile Breaker Giant falling objects or NPC that break tiles.
Locked Doors The player needs to find the key to unlock the door.
Blockades Objects that slow down the player. For example, spikes along a path. The player would need to jump carefully onto something to avoid damage.
Secret Rooms/shortcuts A quick shortcut on a hard to get to part of the map that allows all bonuses + beat the level without much effort or a mini game in a secret area.
Invisible Sections These areas of the map only appear when they are hit or touched.
Object Growth Objects that get bigger when they are hit or touched.
Floating Points Objects that float in the air. If they are hit, then the player gets a number point value or some kind of bonus.
Flying Mode Allows the player to fly.
Digging Mode Allows the player to dig.
Travel Up Wall Mode Allows the player to climb up wall.
Underwater Mode Allows the player to swim and breath under water.
Super Mode The ability to walk up walls, be immortal, and destroy enemies faster by just walking into them. Super mode does not last long.
Animated Backgrounds A background that animates.
Checkpoints The player will go back to this point if the mission is failed or death occurs.
Falling Walls The walls slam down. Most likely causes damage.
Turning Spikes Spikes that turn on a wheel. The player normally has to avoid this obstacle by running at the right time.
Jumping Enemies Enemies that can jump.
Hidden Giants Giant creatures coming out of liquid like elements.
Balance Beam This is a platform that the player stands on or jumps on. One edge of a platform will tilt or tilt back if the player goes to the other edge. The platform normally stays balanced when the player stands in the middle.)
Projectile Ricochet The projectile bounces off walls or other objects.
Unlimited Ammo No limit for projectiles that can be fired.
Scrolling Object/Scene The scene follows behind the player preventing the player from going back or if the scene catches up with the player, then death occurs. Furthermore, this scrolling can involve an object that only makes a pass once and it will not come back after the player uses it. This prevents the player from using it again to go back.
Wheel On Wire A wheel that moves on a wire when it is jumped on. There would normally be edges on the wheel for the player.
Falling Platform This would be platform or bridges that falls after a certain amount of time standing on it or just by touching it.
Enemy Pole Obstacle An enemy on an object to prevent the player character from jumping on it.
Rollers Enemies that turn into balls and roll. Sometimes they can be used to kill other enemies.
Zigzag Flayers Floating enemies that move in a zigzag pattern.
Distort Object Enemies or items that make the scre