Dialogues: Re-write dialogues to allow Minetest's like registration system instead of the actual table lookup system. In general, dialogues now are registered in similar fashion as nodes, entities and others are registered in Minetest.

Relationships: Re-write to the way favorite/disliked items are defined, now allow Minetest's like registration as well.
Random data: Random data now includes registrations for gift items and dialogues.
This commit is contained in:
Hector Franqui 2017-07-13 19:01:28 -04:00
parent bf935fd091
commit e79fb91ff3
7 changed files with 1274 additions and 675 deletions

View File

@ -1,20 +1,6 @@
-------------------------------------------------------------------------------------
-- NPC dialogue code by Zorman2000
-- Dialogue definitions:
-- TODO: Complete
-- {
-- text: "",
-- ^ The "spoken" dialogue line
-- flag:
-- ^ If the flag with the specified name has the specified value
-- then this dialogue is valid
-- {
-- name: ""
-- ^ Name of the flag
-- value:
-- ^ Expected value of the flag. A flag can be a function. In such a case, it is
-- expected the function will return this value.
-- }
-- }
-------------------------------------------------------------------------------------
npc.dialogue = {}
@ -37,11 +23,144 @@ npc.dialogue.dialogue_results = {
yes_no_dialogue = {}
}
---------------------------------------------------------------------------------------
npc.dialogue.tags = {
UNISEX = "unisex",
MALE = "male",
FEMALE = "female",
-- Relationship based tags - these are one-to-one with the
-- phase names.
PHASE_1 = "phase1",
PHASE_2 = "phase2",
PHASE_3 = "phase3",
PHASE_4 = "phase4",
PHASE_5 = "phase5",
GIFT_ITEM_HINT = "gift_item_hint",
GIFT_ITEM_RESPONSE = "gift_item_response",
GIFT_ITEM_LIKED = "gift_item_liked",
GIFT_ITEM_UNLIKED = "gift_item_unliked",
-- Occupation-based tags - these are one-to-one with the
-- default occupation names
BASIC = "basic", -- Dialogues related to the basic occupation should
-- use this. As basic occupation is generic, any occupation
-- should be able to use these dialogues.
DEFAULT_FARMER = "default_farmer",
DEFAULT_COOKER = "default_cooker"
}
-- This table will contain all the registered dialogues for NPCs
npc.dialogue.registered_dialogues = {}
--------------------------------------------------------------------------------------
-- Dialogue registration functions
-- All dialogues will be registered by providing a definition.
-- A unique key will be assigned to them. The dialogue definition is the following:
-- {
-- text: "",
-- ^ The "spoken" dialogue line
-- flag:
-- ^ If the flag with the specified name has the specified value
-- then this dialogue is valid
-- {
-- name: ""
-- ^ Name of the flag
-- value:
-- ^ Expected value of the flag. A flag can be a function. In such a case, it is
-- expected the function will return this value.
-- },
-- tags = {
-- -- Tags are an array of string that allow to classify dialogues
-- -- A dialogue can have as many tags as desired and can take any form.
-- -- However, for consistency, some predefined tags can be found at
-- -- npc.dialogue.tags.
-- -- Example:
-- "phase1",
-- "any"
-- }
-- responses = {
-- -- Array of responses the player can choose. A response can be of
-- -- two types: as [1] or as [2] (see example below)
-- [1] = {
-- text = "Yes",
-- -- Text displayed to the player
-- action_type = "dialogue",
-- -- Type of action that happens when the player chooses this response.
-- -- can be "dialogue" or "function". This example shows "dialogue"
-- action = {
-- text = "It's so beautiful, and big, and large, and infinite, and..."
-- },
-- },
-- -- A table containing a dialogue. This means you can include not only
-- -- text but also flag and responses as well. Dialogues are recursive.
-- [2] = {
-- text = "No",
-- action_type = "function",
-- action = function(self, player)
-- -- A function will have access to self, which is the NPC
-- -- and the player, which is the player ObjectRef. You can
-- -- pretty much do anything here. The example here is very simple,
-- -- just sending a chat message. But you can add items to players
-- -- or to NPCs and so on.
-- minetest.chat_send_player(player:get_player_name(), "Oh, ok...")
-- end,
-- },
-- }
-- }
--------------------------------------------------------------------------------------
-- The register dialogue function will just receive the definition as
-- explained above. The unique key will be the index it gets into the
-- array when inserted.
function npc.dialogue.register_dialogue(def)
-- If def has not tags then apply the default ones
if not def.tags then
def.tags = {npc.dialogue.tags.UNISEX, npc.dialogue.tags.PHASE_1}
end
-- Insert dialogue into table
table.insert(npc.dialogue.registered_dialogues, def)
--minetest.log("Dialogues: "..dump(npc.dialogue.registered_dialogues))
end
-- This function returns a table of dialogues that meet the given
-- tags array. The keys in the table are the keys in
-- npc.dialogue.registered_dialogues, therefore you can use them to
--retrieve specific dialogues. However, it should be stored by the NPC.
function npc.dialogue.search_dialogue_by_tags(tags, find_all)
--minetest.log("Tags being searched: "..dump(tags))
local result = {}
for key, def in pairs(npc.dialogue.registered_dialogues) do
-- Check if def.tags have any of the provided tags
local tags_found = 0
--minetest.log("Tags on dialogue def: "..dump(def.tags))
for i = 1, #tags do
if npc.utils.array_contains(def.tags, tags[i]) then
tags_found = tags_found + 1
end
end
--minetest.log("Tags found: "..dump(tags_found))
-- Check if we found all tags
if find_all then
if tags_found == #tags then
-- Add result
result[key] = def
end
elseif not find_all then
if tags_found == #tags or tags_found == #def.tags then
-- Add result
result[key] = def
end
end
-- if (find_all == true and tags_found == #tags)
-- or (not find_all and tags_found == #def.tags) then
-- end
end
return result
end
--------------------------------------------------------------------------------------
-- Dialogue box definitions
-- The dialogue boxes are used for the player to interact with the
-- NPC in dialogues.
---------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------
-- Creates and shows a multi-option dialogue based on the number of responses
-- that the dialogue object contains
function npc.dialogue.show_options_dialogue(self,
@ -67,10 +186,14 @@ function npc.dialogue.show_options_dialogue(self,
-- Create entry on options_dialogue table
npc.dialogue.dialogue_results.options_dialogue[player_name] = {
npc = self,
is_married_dialogue = (dialogue.dialogue_type == npc.dialogue.dialogue_type.married),
is_casual_trade_dialogue = (dialogue.dialogue_type == npc.dialogue.dialogue_type.casual_trade),
is_dedicated_trade_dialogue = (dialogue.dialogue_type == npc.dialogue.dialogue_type.dedicated_trade),
is_custom_trade_dialogue = (dialogue.dialogue_type == npc.dialogue.dialogue_type.custom_trade),
is_married_dialogue =
(dialogue.dialogue_type == npc.dialogue.dialogue_type.married),
is_casual_trade_dialogue =
(dialogue.dialogue_type == npc.dialogue.dialogue_type.casual_trade),
is_dedicated_trade_dialogue =
(dialogue.dialogue_type == npc.dialogue.dialogue_type.dedicated_trade),
is_custom_trade_dialogue =
(dialogue.dialogue_type == npc.dialogue.dialogue_type.custom_trade),
casual_trade_type = dialogue.casual_trade_type,
options = responses
}
@ -104,9 +227,9 @@ function npc.dialogue.show_yes_no_dialogue(self,
minetest.show_formspec(player_name, "advanced_npc:yes_no", formspec)
end
---------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------
-- Dialogue methods
---------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------
-- This function sets a unique response ID (made of <depth>:<response index>) to
-- each response that features a function. This is to be able to locate the
-- function easily later
@ -135,43 +258,79 @@ end
-- Select random dialogue objects for an NPC based on sex
-- and the relationship phase with player
function npc.dialogue.select_random_dialogues_for_npc(sex, phase, favorite_items, disliked_items)
function npc.dialogue.select_random_dialogues_for_npc(self, phase)
local result = {
normal = {},
hints = {}
}
local dialogues = npc.data.DIALOGUES.female
if sex == npc.MALE then
dialogues = npc.data.DIALOGUES.male
local phase_tag = "phase1"
if phase then
phase_tag = phase
end
dialogues = dialogues[phase]
local search_tags = {
"unisex",
self.sex,
phase_tag,
self.occupation
}
local dialogues = npc.dialogue.search_dialogue_by_tags(search_tags)
minetest.log("dialogues found by tag search: "..dump(dialogues))
-- Determine how many dialogue lines the NPC will have
local number_of_dialogues = math.random(npc.dialogue.MIN_DIALOGUES, npc.dialogue.MAX_DIALOGUES)
for i = 1,number_of_dialogues do
local dialogue_id = math.random(1, #dialogues)
result.normal[i] = dialogues[dialogue_id]
result.normal[i] = dialogue_id
set_response_ids_recursively(result.normal[i], 0, dialogue_id)
--set_response_ids_recursively(result.normal[i], 0, dialogue_id)
end
-- Add item hints.
-- Favorite items
for i = 1, 2 do
result.hints[i] = {}
result.hints[i].text =
npc.relationships.get_hint_for_favorite_item(favorite_items["fav"..tostring(i)], sex, phase)
local hints = npc.relationships.get_dialogues_for_gift_item(
self.gift_data.favorite_items["fav"..tostring(i)],
npc.dialogue.tags.GIFT_ITEM_HINT,
npc.dialogue.tags.GIFT_ITEM_LIKED,
self.sex,
phase_tag)
for key, value in pairs(hints) do
result.hints[i] = key
end
end
-- Disliked items
for i = 3, 4 do
result.hints[i] = {}
result.hints[i].text =
npc.relationships.get_hint_for_disliked_item(disliked_items["dis"..tostring(i-2)], sex)
local hints = npc.relationships.get_dialogues_for_gift_item(
self.gift_data.disliked_items["dis"..tostring(i-2)],
npc.dialogue.tags.GIFT_ITEM_HINT,
npc.dialogue.tags.GIFT_ITEM_UNLIKED,
self.sex)
for key, value in pairs(hints) do
result.hints[i] = key
end
end
-- Favorite items
-- for i = 1, 2 do
-- result.hints[i] = {}
-- result.hints[i].text =
-- npc.relationships.get_hint_for_favorite_item(
-- self.gift_data.favorite_items["fav"..tostring(i)], self.sex, phase_tag)
-- end
-- -- Disliked items
-- for i = 3, 4 do
-- result.hints[i] = {}
-- result.hints[i].text =
-- npc.relationships.get_hint_for_disliked_item(
-- self.gift_data.disliked_items["dis"..tostring(i-2)], self.sex, phase_tag)
-- end
minetest.log("Dialogue results:"..dump(result))
return result
end
@ -181,7 +340,10 @@ function npc.dialogue.create_custom_trade_options(self, player)
-- Create the action for each option
local actions = {}
for i = 1, #self.trader_data.custom_trades do
table.insert(actions, function() npc.trade.show_custom_trade_offer(self, player, self.trader_data.custom_trades[i]) end)
table.insert(actions,
function()
npc.trade.show_custom_trade_offer(self, player, self.trader_data.custom_trades[i])
end)
end
-- Default text to be shown for dialogue prompt
local text = npc.trade.CUSTOM_TRADES_PROMPT_TEXT
@ -224,10 +386,11 @@ function npc.dialogue.start_dialogue(self, player, show_married_dialogue)
end
local chance = math.random(1, 100)
minetest.log("Chance: "..dump(chance))
if chance < 30 then
-- If NPC is a casual trader, show a sell or buy dialogue 30% of the time, depending
-- on the state of the casual trader.
-- Show trading options for casual traders
-- If NPC has custom trading options, these will be
-- shown as well with equal chance as the casual
-- buy/sell options
if self.trader_data.trader_status == npc.trade.NONE then
-- Show custom trade options if available
if table.getn(self.trader_data.custom_trades) > 0 then
@ -274,6 +437,11 @@ function npc.dialogue.process_dialogue(self, dialogue, player_name)
-- Freeze NPC actions
npc.lock_actions(self)
if type(dialogue) ~= "table" then
dialogue = npc.dialogue.registered_dialogues[dialogue]
minetest.log("Found dialogue: "..dump(dialogue))
end
-- Check if this dialogue has a flag definition
if dialogue.flag then
-- Check if the NPC has this flag

View File

@ -24,6 +24,7 @@ end
mobs.intllib = S
dofile(path .. "/npc.lua")
dofile(path .. "/utils.lua")
dofile(path .. "/spawner.lua")
dofile(path .. "/relationships.lua")
dofile(path .. "/dialogue.lua")
@ -33,6 +34,10 @@ dofile(path .. "/actions/actions.lua")
dofile(path .. "/actions/places.lua")
dofile(path .. "/actions/pathfinder.lua")
dofile(path .. "/actions/node_registry.lua")
-- Load random data definitions
dofile(path .. "/random_data.lua")
dofile(path .. "/random_data/dialogues_data.lua")
dofile(path .. "/random_data/gift_items_data.lua")
dofile(path .. "/random_data/names_data.lua")
print (S("[Mod] Advanced NPC loaded"))

106
npc.lua
View File

@ -148,7 +148,38 @@ local function get_random_texture(sex, age)
return filtered_textures[math.random(1,#filtered_textures)]
end
-- Choose whether NPC can have relationships. Only 30% of NPCs cannot have relationships
function npc.get_random_texture_from_array(age, sex, textures)
local filtered_textures = {}
for i = 1, #textures do
local current_texture = textures[i]
-- Filter by age
if (sex == npc.MALE
and string.find(current_texture, sex)
and not string.find(current_texture, npc.FEMALE)
and ((age == npc.age.adult
and not string.find(current_texture, npc.age.child))
or (age == npc.age.child
and string.find(current_texture, npc.age.child))
)
)
or (sex == npc.FEMALE
and string.find(current_texture, sex)
and ((age == npc.age.adult
and not string.find(current_texture, npc.age.child))
or (age == npc.age.child
and string.find(current_texture, npc.age.child))
)
) then
table.insert(filtered_textures, current_texture)
end
end
return filtered_textures[math.random(1, #filtered_textures)]
end
-- Choose whether NPC can have relationships. Only 30% of NPCs
-- cannot have relationships
local function can_have_relationships(is_child)
-- Children can't have relationships
if is_child then
@ -177,18 +208,18 @@ local function choose_spawn_items(self)
npc.add_item_to_inventory(self, npc.trade.prices.currency.tier3.string, currency_item_count)
-- For test
npc.add_item_to_inventory(self, "default:tree", 10)
npc.add_item_to_inventory(self, "default:cobble", 10)
npc.add_item_to_inventory(self, "default:diamond", 2)
npc.add_item_to_inventory(self, "default:mese_crystal", 2)
npc.add_item_to_inventory(self, "flowers:rose", 2)
npc.add_item_to_inventory(self, "advanced_npc:marriage_ring", 2)
npc.add_item_to_inventory(self, "flowers:geranium", 2)
npc.add_item_to_inventory(self, "mobs:meat", 2)
npc.add_item_to_inventory(self, "mobs:leather", 2)
npc.add_item_to_inventory(self, "default:sword_stone", 2)
npc.add_item_to_inventory(self, "default:shovel_stone", 2)
npc.add_item_to_inventory(self, "default:axe_stone", 2)
--npc.add_item_to_inventory(self, "default:tree", 10)
--npc.add_item_to_inventory(self, "default:cobble", 10)
--npc.add_item_to_inventory(self, "default:diamond", 2)
--npc.add_item_to_inventory(self, "default:mese_crystal", 2)
--npc.add_item_to_inventory(self, "flowers:rose", 2)
--npc.add_item_to_inventory(self, "advanced_npc:marriage_ring", 2)
--npc.add_item_to_inventory(self, "flowers:geranium", 2)
--npc.add_item_to_inventory(self, "mobs:meat", 2)
--npc.add_item_to_inventory(self, "mobs:leather", 2)
--npc.add_item_to_inventory(self, "default:sword_stone", 2)
--npc.add_item_to_inventory(self, "default:shovel_stone", 2)
--npc.add_item_to_inventory(self, "default:axe_stone", 2)
--minetest.log("Initial inventory: "..dump(self.inventory))
end
@ -204,8 +235,6 @@ function npc.initialize(entity, pos, is_lua_entity, npc_stats)
ent = entity:get_luaentity()
end
ent.initialized = true
-- Avoid NPC to be removed by mobs_redo API
ent.remove_ok = false
@ -264,13 +293,17 @@ function npc.initialize(entity, pos, is_lua_entity, npc_stats)
elseif child_s <= age_chance and age_chance <= child_e then
selected_age = npc.age.child
ent.visual_size = {
x = 0.75,
y = 0.75
x = 0.60,
y = 0.60
}
ent.collisionbox = {-0.10,-0.50,-0.10, 0.10,0.40,0.10}
ent.is_child = true
-- For mobs_redo
ent.child = true
end
-- Store the selected age
ent.age = selected_age
-- Set texture accordingly
local selected_texture = get_random_texture(selected_sex, selected_age)
--minetest.log("Selected texture: "..dump(selected_texture))
@ -310,7 +343,7 @@ function npc.initialize(entity, pos, is_lua_entity, npc_stats)
-- Flag that determines if NPC can have a relationship
ent.can_have_relationship = can_have_relationships(ent.is_child)
ent.infotext = "Interested in relationships: "..dump(ent.can_have_relationship)
--ent.infotext = "Interested in relationships: "..dump(ent.can_have_relationship)
-- Flag to determine if NPC can receive gifts
ent.can_receive_gifts = ent.can_have_relationship
@ -322,10 +355,7 @@ function npc.initialize(entity, pos, is_lua_entity, npc_stats)
ent.is_married_to = nil
-- Initialize dialogues
ent.dialogues = npc.dialogue.select_random_dialogues_for_npc(ent.sex,
"phase1",
ent.gift_data.favorite_items,
ent.gift_data.disliked_items)
ent.dialogues = npc.dialogue.select_random_dialogues_for_npc(ent, "phase1")
-- Declare NPC inventory
ent.inventory = initialize_inventory()
@ -417,6 +447,9 @@ function npc.initialize(entity, pos, is_lua_entity, npc_stats)
enabled = true,
-- Lock for when executing a schedule
lock = false,
-- Queue of schedules executed
-- Used to calculate dependencies
temp_executed_queue = {},
-- An array of schedules, meant to be one per day at some point
-- when calendars are implemented. Allows for only 7 schedules,
-- one for each day of the week
@ -452,6 +485,7 @@ function npc.initialize(entity, pos, is_lua_entity, npc_stats)
local offer2 = npc.trade.create_custom_sell_trade_offer("Do you want me to fix your mese sword?", "Fix mese sword", "Fix mese sword", "default:sword_mese", {"default:sword_mese", "default:copper_lump 10"})
table.insert(ent.trader_data.custom_trades, offer2)
ent.initialized = true
--minetest.log(dump(ent))
npc.log("INFO", "Successfully initialized NPC with name "..dump(ent.npc_name)
..", sex: "..ent.sex..", is child: "..dump(ent.is_child)
@ -958,8 +992,8 @@ mobs:register_mob("advanced_npc:npc", {
{"npc_female1.png"}, -- female by nuttmeg20
},
child_texture = {
{"npc_baby_male1.png"},
{"npc_baby_female1.png"},
{"npc_child_male1.png"},
{"npc_child_female1.png"},
},
makes_footstep_sound = true,
sounds = {},
@ -1162,6 +1196,21 @@ mobs:register_mob("advanced_npc:npc", {
-- Add to action queue all actions on schedule
for i = 1, #schedule[time] do
--minetest.log("schedule[time]: "..dump(schedule[time]))
-- Check chance
local execution_chance = math.random(1, 100)
if not schedule[time][i].chance or
(schedule[time][i].chance and execution_chance <= schedule[time][i].chance) then
-- Check if entry has dependency on other entry
local dependencies_met = nil
if schedule[time][i].depends then
dependencies_met = npc.utils.array_is_subset_of_array(
self.schedules.temp_executed_queue,
schedule[time][i].depends)
end
-- Check for dependencies being met
if dependencies_met == nil or dependencies_met == true then
-- Add tasks
if schedule[time][i].task ~= nil then
-- Add task
npc.add_task(self, schedule[time][i].task, schedule[time][i].args)
@ -1172,7 +1221,16 @@ mobs:register_mob("advanced_npc:npc", {
-- Change NPC property
npc.schedule_change_property(self, schedule[time][i].property, schedule[time][i].args)
end
-- Backward compatibility check
if self.schedules.temp_executed_queue then
-- Add into execution queue to meet dependency
table.insert(self.schedules.temp_executed_queue, i)
end
end
end
end
-- Clear execution queue
self.schedules.temp_executed_queue = {}
npc.log("DEBUG", "New action queue: "..dump(self.actions))
end
end

View File

View File

@ -0,0 +1,237 @@
------------------------------------------------------------------------------
-- Gift Items data definitions
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- PHASE 1
------------------------------------------------------------------------------
npc.relationships.register_favorite_item("default:apple", "phase1", "female", {
responses = {"Hey, I really wanted an apple, thank you!"},
hints = {"I could really do with an apple..."}
})
npc.relationships.register_favorite_item("farming:bread", "phase1", "female", {
responses = {"Thanks, you didn't have to, but thanks..."},
hints = {"Some fresh bread would be good!"}
})
npc.relationships.register_favorite_item("farming:seed_cotton", "phase1", "female", {
responses = {"Thank you, I will plant this really soon"},
hints = {"I would like to have some cotton plants around"}
})
npc.relationships.register_favorite_item("farming:seed_wheat", "phase1", "female", {
responses = {"Thank you! These seeds will make a good wheat plant!"},
hints = {"I've been thinking I should get wheat seeds"}
})
npc.relationships.register_favorite_item("flowers:rose", "phase1", "female", {
responses = {"Thanks..."},
hints = {"Red roses make a nice gift!"}
})
npc.relationships.register_favorite_item("flowers:geranium", "phase1", "female", {
responses = {"Oh, for me? Thank you!"},
hints = {"Blue geraniums are so beautiful"}
})
npc.relationships.register_favorite_item("default:clay_lump", "phase1", "female", {
responses = {"Thanks! Now, what can I do with this..."},
hints = {"If I had some clay lump, I may do some pottery"}
})
npc.relationships.register_favorite_item("mobs:meat_raw", "phase1", "female", {
responses = {"This will be great for tonight! Thanks"},
hints = {"A good dinner always have meat"}
})
npc.relationships.register_favorite_item("mobs:leather", "phase1", "female", {
responses = {"Thank you! I needed this!"},
hints = {"If only I could get some leather"}
})
npc.relationships.register_favorite_item("default:sapling", "phase1", "female", {
responses = {"Now I can plant that tree..."},
hints = {"I really would like an apple tree close by."}
})
npc.relationships.register_favorite_item("farming:cotton", "phase2", "female", {
responses = {"This is going to be very helpful, thank you!"},
hints = {"If I just had some cotton lying around..."}
})
npc.relationships.register_favorite_item("wool:white", "phase2", "female", {
responses = {"Thanks, you didn't have to, but thanks..."},
hints = {"Have you seen a sheep? I wish I had some white wool..."}
})
npc.relationships.register_favorite_item("default:apple", "phase3", "female", {
responses = {"Hey, I really wanted an apple, thank you!"},
hints = {"I could really do with an apple..."}
})
npc.relationships.register_favorite_item("farming:bread", "phase3", "female", {
responses = {"Thanks, you didn't have to, but thanks..."},
hints = {"Some fresh bread would be good!"}
})
npc.relationships.register_favorite_item("default:apple", "phase4", "female", {
responses = {"Hey, I really wanted an apple, thank you!"},
hints = {"I could really do with an apple..."}
})
npc.relationships.register_favorite_item("farming:bread", "phase4", "female", {
responses = {"Thanks, you didn't have to, but thanks..."},
hints = {"Some fresh bread would be good!"}
})
npc.relationships.register_favorite_item("default:apple", "phase5", "female", {
responses = {"Hey, I really wanted an apple, thank you!"},
hints = {"I could really do with an apple..."}
})
npc.relationships.register_favorite_item("farming:bread", "phase5", "female", {
responses = {"Thanks, you didn't have to, but thanks..."},
hints = {"Some fresh bread would be good!"}
})
npc.relationships.register_favorite_item("default:apple", "phase6", "female", {
responses = {"Hey, I really wanted an apple, thank you!"},
hints = {"I could really do with an apple..."}
})
npc.relationships.register_favorite_item("farming:bread", "phase6", "female", {
responses = {"Thanks, you didn't have to, but thanks..."},
hints = {"Some fresh bread would be good!"}
})
-- Male
npc.relationships.register_favorite_item("default:apple", "phase1", "male", {
responses = {"Good apple, thank you!"},
hints = {"I could do with an apple..."}
})
npc.relationships.register_favorite_item("farming:bread", "phase1", "male", {
responses = {"Thank you! I was hungry."},
hints = {"Some fresh bread would be good!"}
})
npc.relationships.register_favorite_item("farming:seed_cotton", "phase1", "male", {
responses = {"Thank you, I will plant this soon"},
hints = {"I would like to have some cotton plants around."}
})
npc.relationships.register_favorite_item("farming:seed_wheat", "phase1", "male", {
responses = {"Thank you! These seeds will make a good wheat plant!"},
hints = {"I've been thinking I should get wheat seeds."}
})
npc.relationships.register_favorite_item("default:wood", "phase1", "male", {
responses = {"Thanks, I needed this."},
hints = {"Some wood without having to cut a tree would be good.}"}
})
npc.relationships.register_favorite_item("default:tree", "phase1", "male", {
responses = {"Excellent to get that furnace going!"},
hints = {"I'm looking for some logs"}
})
npc.relationships.register_favorite_item("default:clay_lump", "phase1", "male", {
responses = {"Thanks! Now, what can I do with this..."},
hints = {"Now, some clay would be good."}
})
npc.relationships.register_favorite_item("mobs:meat_raw", "phase1", "male", {
responses = {"This makes a great meal. Thank you"},
hints = {"Meat is always great"},
})
npc.relationships.register_favorite_item("mobs:leather", "phase1", "male", {
responses = {"Time to tan some leathers!"},
hints = {"I have been needing leather these days."}
})
npc.relationships.register_favorite_item("default:sapling", "phase1", "male", {
responses = {"Thanks, I will plant this right now"},
hints = {"I really would like an apple tree close by."}
})
npc.relationships.register_favorite_item("default:apple", "phase2", "male", {
responses = {"Good apple, thank you!"},
hints = {"I could do with an apple..."}
})
npc.relationships.register_favorite_item("farming:bread", "phase2", "male", {
responses = {"Thank you! I was hungry."},
hints = {"Some fresh bread would be good!"}
})
npc.relationships.register_favorite_item("default:apple", "phase3", "male", {
responses = {"Good apple, thank you!"},
hints = {"I could do with an apple..."}
})
npc.relationships.register_favorite_item("farming:bread", "phase3", "male", {
responses = {"Thank you! I was hungry."},
hints = {"Some fresh bread would be good!"}
})
npc.relationships.register_favorite_item("default:apple", "phase4", "male", {
responses = {"Good apple, thank you!"},
hints = {"I could do with an apple..."}
})
npc.relationships.register_favorite_item("farming:bread", "phase4", "male", {
responses = {"Thank you! I was hungry."},
hints = {"Some fresh bread would be good!"}
})
npc.relationships.register_favorite_item("default:apple", "phase5", "male", {
responses = {"Good apple, thank you!"},
hints = {"I could do with an apple..."}
})
npc.relationships.register_favorite_item("farming:bread", "phase5", "male", {
responses = {"Thank you! I was hungry."},
hints = {"Some fresh bread would be good!"}
})
npc.relationships.register_favorite_item("default:apple", "phase6", "male", {
responses = {"Good apple, thank you!"},
hints = {"I could do with an apple..."}
})
npc.relationships.register_favorite_item("farming:bread", "phase6", "male", {
responses = {"Thank you! I was hungry."},
hints = {"Some fresh bread would be good!"}
})
-- Disliked items
-- Female
npc.relationships.register_disliked_item("default:stone", "female", {
responses = {"A stone, oh... why do you give this to me?"},
hints = {"Why would someone want a stone?"}
})
npc.relationships.register_disliked_item("default:cobble", "female", {
responses = {"Cobblestone? No, no, why?"},
hints = {"Anything worst than stone is cobblestone."}
})
-- Male
npc.relationships.register_disliked_item("default:stone", "male", {
responses = {"Good apple, thank you!"},
hints = {"I could do with an apple..."}
})
npc.relationships.register_disliked_item("default:cobble", "male", {
responses = {"Cobblestone!? Wow, you sure think a lot before giving a gift..."},
hints = {"If I really hate something, that's cobblestone!"}
})
npc.log("INFO", "Registered gift items: "..dump(npc.relationships.gift_items))
npc.log("INFO", "Registered dialogues: "..dump(npc.dialogue.registered_dialogues))

View File

View File

@ -38,6 +38,40 @@ npc.relationships.RELATIONSHIP_PHASE["phase3"] = {limit = 45}
npc.relationships.RELATIONSHIP_PHASE["phase4"] = {limit = 70}
npc.relationships.RELATIONSHIP_PHASE["phase5"] = {limit = 100}
npc.relationships.GIFT_ITEM_LIKED = "liked"
npc.relationships.GIFT_ITEM_DISLIKED = "disliked"
npc.relationships.GIFT_ITEM_HINT = "hint"
npc.relationships.GIFT_ITEM_RESPONSE = "response"
-- Favorite and disliked items tables
npc.relationships.gift_items = {
liked = {
female = {
["phase1"] = {},
["phase2"] = {},
["phase3"] = {},
["phase4"] = {},
["phase5"] = {},
["phase6"] = {}
},
male = {
["phase1"] = {},
["phase2"] = {},
["phase3"] = {},
["phase4"] = {},
["phase5"] = {},
["phase6"] = {}
}
},
disliked = {
female = {},
male = {}
}
}
npc.relationships.DEFAULT_RESPONSE_NO_GIFT_RECEIVE =
"Thank you, but I don't need anything for now."
-- Married NPC dialogue definition
npc.relationships.MARRIED_NPC_DIALOGUE = {
text = "Hi darling!",
@ -90,6 +124,96 @@ function npc.relationships.get_relationship_phase_by_points(points)
end
end
-- Registration functions
-----------------------------------------------------------------------------
-- Items can be registered to be part of the gift system using the
-- below function. The def is the following:
-- {
-- dialogues = {
-- liked = {
-- -- ^ This is an array of the following table:
-- [1] = {dialogue_type="", sex="", text=""}
-- -- ^ dialogue_type: defines is this is a hint or a response.
-- -- valid values are: "hint", "response"
-- -- sex: valid values are: "male", female"
-- -- text: the dialogue text
-- },
-- disliked = {
-- -- ^ This is an array with the same type of tables as above
-- }
-- }
-- }
function npc.relationships.register_favorite_item(item_name, phase, sex, def)
local dialogues = {}
-- Register dialogues based on the hints and responses
-- Liked
for i = 1, #def.hints do
table.insert(dialogues, {
text = def.hints[i],
tags = {phase, item_name, sex,
npc.dialogue.tags.GIFT_ITEM_HINT, npc.dialogue.tags.GIFT_ITEM_LIKED}
})
end
for i = 1, #def.responses do
table.insert(dialogues, {
text = def.responses[i],
tags = {phase, item_name, sex,
npc.dialogue.tags.GIFT_ITEM_RESPONSE, npc.dialogue.tags.GIFT_ITEM_LIKED}
})
end
-- Register all dialogues
for i = 1, #dialogues do
npc.dialogue.register_dialogue(dialogues[i])
end
-- Insert item into table
table.insert(npc.relationships.gift_items.liked[sex][phase], item_name)
end
function npc.relationships.register_disliked_item(item_name, sex, def)
local dialogues = {}
-- Register dialogues based on the hints and responses
-- Liked
for i = 1, #def.hints do
table.insert(dialogues, {
text = def.hints[i],
tags = {item_name, sex,
npc.dialogue.tags.GIFT_ITEM_HINT, npc.dialogue.tags.GIFT_ITEM_UNLIKED}
})
end
for i = 1, #def.responses do
table.insert(dialogues, {
text = def.responses[i],
tags = {item_name, sex,
npc.dialogue.tags.GIFT_ITEM_RESPONSE, npc.dialogue.tags.GIFT_ITEM_UNLIKED}
})
end
-- Register all dialogues
for i = 1, #dialogues do
npc.dialogue.register_dialogue(dialogues[i])
end
-- Insert item into table
table.insert(npc.relationships.gift_items.disliked[sex], item_name)
end
function npc.relationships.get_dialogues_for_gift_item(item_name, dialogue_type, item_type, sex, phase)
local tags = {
[1] = item_name,
[2] = dialogue_type,
[3] = item_type,
[4] = sex
}
if phase ~= nil then
tags[5] = phase
end
minetest.log("Searching with tags: "..dump(tags))
return npc.dialogue.search_dialogue_by_tags(tags, true)
end
-- Returns the response message for a given item
function npc.relationships.get_response_for_favorite_item(item_name, sex, phase)
local items = npc.FAVORITE_ITEMS.female
@ -144,7 +268,7 @@ end
-- Relationship functions
---------------------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- This function selects two random items from the npc.favorite_items table
-- It checks for sex and phase for choosing the items
@ -152,18 +276,19 @@ function npc.relationships.select_random_favorite_items(sex, phase)
local result = {}
local items = {}
-- Filter sex
if sex == npc.FEMALE then
items = npc.FAVORITE_ITEMS.female
else
items = npc.FAVORITE_ITEMS.male
end
-- -- Filter sex
-- if sex == npc.FEMALE then
-- items = npc.FAVORITE_ITEMS.female
-- else
-- items = npc.FAVORITE_ITEMS.male
-- end
-- Select the phase
items = items[phase]
-- items = items[phase]
items = npc.relationships.gift_items.liked[sex][phase]
result.fav1 = items[math.random(1, #items)].item
result.fav2 = items[math.random(1, #items)].item
result.fav1 = items[math.random(1, #items)]
result.fav2 = items[math.random(1, #items)]
return result
end
@ -174,15 +299,16 @@ function npc.relationships.select_random_disliked_items(sex)
local result = {}
local items = {}
-- Filter sex
if sex == npc.FEMALE then
items = npc.DISLIKED_ITEMS.female
else
items = npc.DISLIKED_ITEMS.male
end
-- -- Filter sex
-- if sex == npc.FEMALE then
-- items = npc.DISLIKED_ITEMS.female
-- else
-- items = npc.DISLIKED_ITEMS.male
-- end
items = npc.relationships.gift_items.disliked[sex]
result.dis1 = items[math.random(1, #items)].item
result.dis2 = items[math.random(1, #items)].item
result.dis1 = items[math.random(1, #items)]
result.dis2 = items[math.random(1, #items)]
return result
end
@ -233,10 +359,8 @@ local function update_relationship(self, clicker_name, modifier)
npc.relationships.select_random_favorite_items(self.sex, self.relationships[i].phase)
-- Re-select dialogues per new
self.dialogues =
npc.dialogue.select_random_dialogues_for_npc(self.sex,
self.relationships[i].phase,
self.gift_data.favorite_items,
self.gift_data.disliked_items)
npc.dialogue.select_random_dialogues_for_npc(self,
self.relationships[i].phase)
return true
end
return false
@ -352,14 +476,22 @@ local function show_receive_gift_reaction(self, item_name, modifier, clicker_nam
-- Send message
-- TODO: There might be an error with getting the message...
--minetest.log("Item_name: "..dump(item_name)..", sex: "..dump(self.sex)..", phase: "..dump(phase))
local message_to_send =
npc.relationships.get_response_for_favorite_item(item_name, self.sex, phase)
local message_to_send = npc.relationships.get_dialogues_for_gift_item(
item_name,
npc.relationships.GIFT_ITEM_RESPONSE,
npc.relationships.GIFT_ITEM_LIKED,
self.sex,
phase)
npc.chat(self.npc_name, clicker_name, message_to_send)
-- Disliked items reactions
elseif modifier < 0 then
effect({x = pos.x, y = pos.y + 1, z = pos.z}, 8, "default_item_smoke.png")
--minetest.log("Item name: "..item_name..", sex: "..self.sex)
local message_to_send = npc.relationships.get_response_for_disliked_item(item_name, self.sex)
local message_to_send = npc.relationships.get_dialogues_for_gift_item(
item_name,
npc.relationships.GIFT_ITEM_RESPONSE,
npc.relationships.GIFT_ITEM_DISLIKED,
self.sex)
npc.chat(self.npc_name, clicker_name, message_to_send)
end
@ -425,21 +557,20 @@ function npc.relationships.receive_gift(self, clicker)
else
npc.chat(self.npc_name, clicker_name,
"Dear, I feel the same as you. But maybe not yet...")
end
-- Reset gift timer
reset_gift_timer(self, clicker_name)
return true
end
-- Marriage gifts: except for disliked items, all product a 0.5 * npc.ITEM_GIFT_EFFECT
-- Disliked items cause only a -1 point effect
-- Disliked items cause only a -0.5 point effect
if get_relationship_points(self, clicker_name) >=
npc.relationships.RELATIONSHIP_PHASE["phase5"].limit then
local modifier = 0.5 * npc.ITEM_GIFT_EFFECT
-- Check for disliked items
if item:get_name() == self.gift_data.disliked_items.dis1
or item:get_name() == self.gift_data.disliked_items.dis2 then
modifier = -1
modifier = -0.5
show_receive_gift_reaction(self, item:get_name(), modifier, clicker_name, false)
elseif item:get_name() == self.gift_data.favorite_items.fav1
or item:get_name() == self.gift_data.favorite_items.fav2 then