-
Notifications
You must be signed in to change notification settings - Fork 39
Special NPCs
In this tutorial, we'll be walking through how to add special types of NPC. There are some other types than regular NPCs, but some of them are just regular NPCs combined with specific types of Game Events, but since they're commonplace in the game, we'll be also talking about them.
In order to add a healer NPC, just setting the "npc_type"
to "healer"
is enough when adding it to a map. Example:
{
"key_name": "healer_1",
"x": 16,
"y": 7,
"movement_type": "idle",
"npc_type": "healer",
"avatar": "elder_healer",
"base_collision_layer": 0,
"back_interaction_message": "This a back interaction message!",
"talk_range": 40
}
In order to add an inn NPC, you not only need to set "npc_type"
to "inn"
when adding it to a map but also register an inn in assets\dbs\inn_db.json
db file. This file will hold information of all types of inns you'll have in your game, each inn has its own unique key name. Use this key name in the "inn_key"
property when adding an NPC to the map.
Example of assets\dbs\inn_db.json
:
[
{
"inn_id": "madra_inn",
"cost": 6,
"messages": {
"welcome_message": "Welcome to our inn.",
"price_message": "It's ${PRICE} coins for a room. Would you like to stay?",
"cancel_message": "Please, come again.",
"stay_message": "Please enjoy your stay.",
"goodbye_message": "Have a nice trip!",
"not_enough_coins": "You don't have enough coins."
}
}
]
Notice that you can use ${PRICE}
placeholder in the inn messages in order to place the actual inn cost.
Example of NPC:
{
"key_name": "village_1",
"x": 69,
"y": 11,
"npc_type": "inn",
"movement_type": "idle",
"back_interaction_message": "This a back interaction message!",
"avatar": "potion_shopkeeper",
"inn_key": "madra_inn",
"base_collision_layer": 0,
"talk_range": 40
}
In order to add a shop NPC, you not only need to set "npc_type"
to "shop"
when adding it to a map but also register a shop in assets\dbs\shops_db.json
db file. This file will hold information of all shops you'll have in your game, each shop has its own unique key name. Use this key name in the "shop_key"
property when adding an NPC to the map.
Example of assets\dbs\shops_db.json
:
[
{
"key_name": "madra_test_shop",
"dialog_key": "female_medicine_shopkeep_00",
"shop_type": "general_shop",
"item_list": [
{
"key_name": "herb",
"quantity": -1
},
{
"key_name": "cookie",
"quantity": 3
},
{
"key_name": "cotton_shirt",
"quantity": -1
}
]
}
]
Notice that before setting the shop db, you need to set the shopkeep dialogs db in assets\dbs\shopkeep_dialog_db.json
. This file will contain the dialogs of the shopkeep, so you can just reference this set of dialogs in the "dialog_key"
property. See details here.
Example of NPC:
{
"key_name": "village_1",
"x": 20,
"y": 9,
"avatar": "potion_shopkeeper",
"npc_type": "shop",
"movement_type": "idle",
"back_interaction_message": "Please spend all your money here!",
"shop_key": "madra_test_shop",
"base_collision_layer": 1,
"talk_range": 35
}
The below example is a configuration to get docile djinn, generally the djinn that are inside towns.
{
"key_name": "mars_djinn",
"label": "ember_djinn",
"storage_keys": {
"active": "ember_djinn"
},
"x": 7,
"y": 15,
"npc_type": "normal",
"action": "idle",
"movement_type": "idle",
"base_collision_layer": 2,
"events": [
{
"type": "djinn_get",
"djinn_key": "ember",
"finish_events": [
{
"type": "set_value",
"event_value": {
"type": "storage",
"value": {
"key_name": "ember_djinn",
"value": false
}
}
}
]
}
]
}
This NPC is using two Game Events: "djinn_get"
event and "set_value"
event. Notice that you need to have a storage value associated with this djinn so it will get permanently deactivated after it gets caught. See about storage values here.
This is the type of djinn that when you interact with it, it starts a fight before it gets caught. The setup for this NPC is very similar to the docile djinn, the only difference here is that you need to set "has_fight"
property to true
and also set the "enemy_party_key"
property, both in "djinn_get"
event. Example:
{
"key_name": "venus_djinn",
"storage_keys": {
"active": "ground_djinn"
},
"x": 20,
"y": 25,
"npc_type": "normal",
"action": "idle",
"movement_type": "idle",
"base_collision_layer": 0,
"events": [
{
"type": "djinn_get",
"djinn_key": "ground",
"has_fight": true,
"enemy_party_key": "venus_djinn_ground_party",
"custom_battle_bg": "bg_cliffs",
"finish_events": [
{
"type": "set_value",
"event_value": {
"type": "storage",
"value": {
"key_name": "ground_djinn",
"value": false
}
}
}
]
}
]
}
Djinn that can be found on the world map are not set directly just like other NPCs. When creating an enemy party, there's a special option to handle this kind of djinn. In assets/dbs/enemies_parties_db.json
, you can set a world map djinn like below:
[
{
"key_name": "jupiter_djinn_kite_party",
"name": "Jupiter Djinn",
"can_escape": true,
"djinn": "kite",
"active_storage_key": "kite_djinn",
"weight": 2.0,
"members": [
{
"key": "jupiter_djinn_kite",
"min": 1,
"max": 1
}
]
}
]
Set the "djinn"
option with the djinni key name that will be received after the battle. Also sets a boolean storage value in "active_storage_key"
. After the battle victory, this variable will be set to false, then you won't find this djinn anymore.
After creating the enemy party for the djinni, add this party to an encounter zone on the map, see image below. Details about encounter zones, you can find here.
The below example is a configuration to get a summon through a summon stone:
{
"key_name": "summon",
"storage_keys": {
"active": "summon_megaera_stone"
},
"x": 101.5,
"y": 6,
"npc_type": "normal",
"movement_type": "idle",
"base_collision_layer": 0,
"events": [
{
"type": "summon",
"summon_key": "megaera",
"finish_events": [
{
"type": "set_value",
"event_value": {
"type": "storage",
"value": {
"key_name": "summon_megaera_stone",
"value": false
}
}
}
]
}
]
}
This NPC is using two Game Events: "summon"
event and "set_value"
event. Notice that you need to have a storage value associated with this summon stone so it will get permanently deactivated after you get it. See about storage values here.
Chests and objects like jars, boxes, etc are NPCs in the engine. They use the "chest"
Game Event to work along with storage variables manipulation.
After registering the chest NPC with its sprites, you can add a chest to the map like the below example:
{
"key_name": "chest",
"storage_keys": {
"animation": "pound_cube_chest"
},
"x": 28,
"y": 10,
"npc_type": "normal",
"movement_type": "idle",
"base_collision_layer": 2,
"events": [
{
"type": "branch",
"comparator_pairs": [{
"condition": "=",
"left_comparator_value": {
"type": "storage",
"value": {
"key_name": "pound_cube_chest"
}
},
"right_comparator_value": {
"type": "value",
"value": "closed"
}
}],
"events": [
{
"type": "chest",
"item": "pound_cube",
"finish_events": [
{
"type": "set_value",
"event_value": {
"type": "storage",
"value": {
"key_name": "pound_cube_chest",
"value": "empty"
}
}
}
]
}
],
"else_events": [
{
"type": "dialog",
"dialog_info": {
"text": "${HERO} checked the chest...${BREAK}but the chest was empty."
}
}
]
}
]
}
Notice that "pound_cube_chest"
storage variable is the one that controls the state of this chest. Without it, every time you return to the map where this chest is, you'll find it open. So first we check with "branch"
Game Event whether "pound_cube_chest"
variable is equal to "closed"
. If yes, it will fire the "chest"
Game Event, then set "pound_cube_chest"
variable to "empty"
. So next time the hero interacts with this chest, "pound_cube_chest"
will be "empty"
, then the "branch"
event else condition will be fired which is just a "dialog"
Game Event telling that this chest is empty.
Notice that this NPC has the "storage_keys"
property set. Inside it, the "animation"
property is set to "pound_cube_chest"
, which means that the "animation"
property of this NPC will also be controlled by the "pound_cube_chest"
variable value. See more info about it here.
This category of NPCs is very similar to the chest ones. See below:
{
"key_name": "foo",
"x": 25,
"y": 15,
"base_collision_layer": 1,
"storage_keys": {
"affected_by_reveal": "herb_box_madra"
},
"npc_type": "sprite",
"movement_type": "idle",
"animation": "hidden_item",
"sprite_misc_db_key": "psynergy_particle",
"action": "psynergy_particle",
"allow_interaction_when_inactive": "true",
"active": false,
"events": [
{
"type": "branch",
"comparator_pairs": [{
"condition": "=",
"left_comparator_value": {
"type": "storage",
"value": {
"key_name": "herb_box_madra"
}
},
"right_comparator_value": {
"type": "value",
"value": true
}
}],
"events": [
{
"type": "chest",
"custom_init_text": "${HERO} checked the wooden box...",
"item": "herb",
"no_chest": true,
"hide_on_finish": true,
"finish_events": [
{
"type": "set_value",
"check_npc_storage_values": true,
"event_value": {
"type": "storage",
"value": {
"key_name": "herb_box_madra",
"value": false
}
}
}
]
}
],
"else_events": [
{
"type": "dialog",
"dialog_info": {
"text": "${HERO} checked the wooden box...${BREAK}but didn't find anything."
}
}
]
}
]
}
The above example is for an herb inside a wooden box. The behavior is very similar to the chest, but it has a little bit more details. First of all, the NPC for this wooden box was registered like this:
{
"key_name": "foo",
"interaction_pattern": "simple_interaction",
"no_shadow": true,
"ignore_physics": true
}
It's pretty much an empty NPC, no collision structures, no spritesheet. That's because the box image belongs to the map, and its collision structure also belongs to the map, so we just need something empty that we can interact with.
Notice that we can force this NPC to assume a different sritesheet with the "sprite_misc_db_key"
property. For this example, it's that little shiny particle that appears over the boxes, jars, etc that has an item inside of it when you cast Reveal. When an NPC has the "affected_by_reveal"
property set, it will have its active state toggled. "affected_by_reveal"
is controlled by "herb_box_madra"
variable in this example, so if this variable is set to true, the particle over the box will be shown because this NPC has its initial active state set to false as seen in "active"
property.
For jars, pots, boxes, etc that don't have anything inside, just setting the below NPC is enough:
{
"key_name": "foo",
"x": 25,
"y": 17,
"base_collision_layer": 1,
"npc_type": "sprite",
"message": "${HERO} checked the jar...${BREAK}but didn't find anything."
}
In order to place a psynergy stone you just need to create an NPC like below:
{
"key_name": "psynergy_stone",
"storage_keys": {
"active": "psy_stone_madra_active"
},
"x": 33,
"y": 15,
"npc_type": "normal",
"movement_type": "idle",
"animation": "normal",
"base_collision_layer": 1,
"events": [
{
"type": "psynergy_stone",
"finish_events": [
{
"type": "set_value",
"event_value": {
"type": "storage",
"value": {
"key_name": "psy_stone_madra_active",
"value": false
}
}
}
]
}
]
}
It's an NPC controlled by the "psy_stone_madra_active"
storage variable and the event of grabbing the psynergy stone is handled by the "psynergy_stone"
Game Event.
- Home
- Introduction for developers
- Tutorials
- Game initialization settings
- Map settings
-
Game Events
- Add item to party event
- Audio play event
- Battle event
- Branch event
- Camera fade event
- Camera follow event
- Camera move event
- Camera shake event
- Casting aura event
- Change collision layer event
- Char animation play event
- Char blend mode event
- Char exp event
- Char fall event
- Char hue event
- Char item manipulation event
- Char level change event
- Char rotation event
- Char shadow visibility event
- Char tween position event
- Chest event
- Colorize char event
- Colorize map event
- Control bgm event
- Create storage var event
- Custom collision body event
- Destroyer event
- Dialog event
- Djinn get event
- Djinn set status event
- Emoticon event
- Event activation event
- Event caller event
- Event holder event
- Event loop event
- Exit Sand mode event
- Face direction event
- Flame char event
- Generic sprite event
- Grant ability event
- IO anim play event
- IO tween position event
- Item checks event
- Jump event
- Layer tween event
- Layer visibility event
- Look event
- Main chars join split event
- Map blend mode event
- Map opacity event
- Move event
- Outline char event
- Particles event
- Party join event
- Permanent status event
- Psynergy stone event
- Set char activation event
- Set char collision event
- Set char visibility event
- Set IO activation event
- Set IO collision event
- Set IO visibility event
- Set NPC collision event
- Set party coins event
- Set value event
- Storage change event
- Summon event
- Teleport event
- Tile event manage event
- Timer event
- Tint char event
- Databases
- Code reference