diff --git a/README.md b/README.md index 2c5afcf..e995330 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,11 @@ Phase 1: Gifts and relationships: In progress - Eventually, an NPC can fall in love with that player and marry him/her - Relationships among NPCs should be possible too -Phase 2: Dialogues: In progress +Phase 2: Dialogues: Completed - NPCs should be able to perform complex dialogues: - - Specific dialogues on certain environment flag (so that events can change what an NPC says + - Use yes/no or multiple option dialogue boxes to interact with player - Answers and responses by player + TODO: Specific dialogues on certain environment flag (so that events can change what an NPC says Phase 3: Trading - NPCs should be able to trade, either buy or sell items to/from player and other NPCs diff --git a/dialogue.lua b/dialogue.lua index 99c02d2..82f4aee 100644 --- a/dialogue.lua +++ b/dialogue.lua @@ -20,7 +20,11 @@ npc.dialogue.dialogue_results = { -------------------------------------------------------------------- -- 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, responses, dismiss_option_label, player_name) +function npc.dialogue.show_options_dialogue(self, + responses, + is_married_dialogue, + dismiss_option_label, + player_name) local options_length = table.getn(responses) + 1 local formspec_height = (options_length * 0.7) + 0.7 local formspec = "size[7,"..tostring(formspec_height).."]" @@ -39,6 +43,7 @@ function npc.dialogue.show_options_dialogue(self, responses, dismiss_option_labe -- Create entry on options_dialogue table npc.dialogue.dialogue_results.options_dialogue[player_name] = { npc = self, + is_married_dialogue = is_married_dialogue, options = responses } @@ -70,45 +75,39 @@ end -- Dialogue methods -- 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, - only_hints) +function npc.dialogue.select_random_dialogues_for_npc(sex, phase, favorite_items, disliked_items) local result = { normal = {}, hints = {} } - if only_hints == false then - local dialogues = npc.data.DIALOGUES.female - if sex == npc.MALE then - dialogues = npc.data.DIALOGUES.male - end - dialogues = dialogues[phase] + local dialogues = npc.data.DIALOGUES.female + if sex == npc.MALE then + dialogues = npc.data.DIALOGUES.male + end + dialogues = dialogues[phase] - -- Determine how many dialogue lines the NPC will have - local number_of_dialogues = math.random(npc.dialogue.MIN_DIALOGUES, npc.dialogue.MAX_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] + for i = 1,number_of_dialogues do + local dialogue_id = math.random(1, #dialogues) + result.normal[i] = dialogues[dialogue_id] - -- Check if this particular dialogue has responses - if result.normal[i].responses then - -- Check each response to see if they have action_type == "function". - -- This way the indices for this particular response will be stored - -- and the function can be retrieved for execution later. - for key,value in ipairs(result.normal[i].responses) do - if value.action_type == "function" then - result.normal[i].responses[key].dialogue_id = dialogue_id - result.normal[i].responses[key].response_id = key - minetest.log("Storing dialogue and response id: " - ..dump(result.normal[i].responses[key])) - end + -- Check if this particular dialogue has responses + if result.normal[i].responses then + -- Check each response to see if they have action_type == "function". + -- This way the indices for this particular response will be stored + -- and the function can be retrieved for execution later. + for key,value in ipairs(result.normal[i].responses) do + if value.action_type == "function" then + result.normal[i].responses[key].dialogue_id = dialogue_id + result.normal[i].responses[key].response_id = key + minetest.log("Storing dialogue and response id: " + ..dump(result.normal[i].responses[key])) end - end + end end @@ -132,11 +131,19 @@ end -- This function will choose randomly a dialogue from the NPC data -- and process it. -function npc.dialogue.start_dialogue(self, player) +function npc.dialogue.start_dialogue(self, player, show_married_dialogue) -- Choose a dialogue randomly - -- TODO: Add support for favorite items hints - -- Add support for flags + -- TODO: Add support for flags local dialogue = {} + + -- Construct dialogue for marriage + if npc.get_relationship_phase(self, player:get_player_name()) == "phase6" + and show_married_dialogue == true then + dialogue = npc.MARRIED_NPC_DIALOGUE + npc.dialogue.process_dialogue(self, dialogue, player:get_player_name()) + return + end + local chance = math.random(1, 100) if chance < 90 then dialogue = self.dialogues.normal[math.random(1, #self.dialogues.normal)] @@ -159,7 +166,8 @@ function npc.dialogue.process_dialogue(self, dialogue, player_name) if dialogue.responses then npc.dialogue.show_options_dialogue( self, - dialogue.responses, + dialogue.responses, + dialogue.is_married_dialogue, npc.dialogue.NEGATIVE_ANSWER_LABEL, player_name ) @@ -243,21 +251,20 @@ minetest.register_on_player_receive_fields(function (player, formname, fields) elseif player_response.options[i].action_type == "function" then -- Execute function - get it directly from definition -- Find NPC relationship phase with player - local phase = nil - for i = 1, #player_response.npc.relationships do - if player_name == player_response.npc.relationships[i].name then - phase = player_response.npc.relationships[i].phase - break + local phase = npc.get_relationship_phase(player_response.npc, player_name) + -- Check if NPC is married and the married NPC dialogue should be shown + if phase == "phase6" and player_response.is_married_dialogue == true then + npc.MARRIED_NPC_DIALOGUE.responses[player_response.options[i].response_id] + .action(player_response.npc, player) + else + -- Get dialogues for sex and phase + local dialogues = npc.data.DIALOGUES[player_response.npc.sex][phase] + + -- Execute function + dialogues[player_response.options[i].dialogue_id] + .responses[player_response.options[i].response_id] + .action(player_response.npc, player) end - end - - -- Get dialogues for sex and phase - local dialogues = npc.data.DIALOGUES[player_response.npc.sex][phase] - - -- Execute function - dialogues[player_response.options[i].dialogue_id] - .responses[player_response.options[i].response_id] - .action(player_response.npc, player_name) end return end diff --git a/npc.lua b/npc.lua index 2871858..d5a047f 100755 --- a/npc.lua +++ b/npc.lua @@ -143,7 +143,41 @@ npc.DISLIKED_ITEMS = { hint = "If I really hate something, that's cobblestone!"} } } - + +-- Married NPC dialogue definition +npc.MARRIED_NPC_DIALOGUE = { + text = "Hi darling!", + is_married_dialogue = true, + responses = { + [1] = { + text = "Let's talk!", + action_type = "function", + response_id = 1, + action = function(self, player) + npc.start_dialogue(self, player, false) + end + }, + [2] = { + text = "Honey, can you wait for me here?", + action_type = "function", + response_id = 2, + action = function(self, player) + self.order = "stand" + minetest.chat_send_player(player:get_player_name(), S("Ok dear, I will wait here for you.")) + end + }, + [3] = { + text = "Come with me, please!", + action_type = "function", + response_id = 3, + action = function(self, player) + self.order = "follow" + minetest.chat_send_player(player:get_player_name(), S("Ok, let's go!")) + end + } + } +} + mobs.npc_drops = { "default:pick_steel", "mobs:meat", "default:sword_steel", "default:shovel_steel", "farming:bread", "bucket:bucket_water" @@ -169,7 +203,7 @@ local function get_entity_wielded_item(entity) end -- Function to get relationship phase -function npc.get_relationship_phase(points) +function npc.get_relationship_phase_by_points(points) if points > npc.RELATIONSHIP_PHASE["phase5"].limit then return "phase6" elseif points > npc.RELATIONSHIP_PHASE["phase4"].limit then @@ -339,7 +373,7 @@ local function update_relationship(self, clicker_name, modifier) if self.relationships[i].name == clicker_name then self.relationships[i].points = self.relationships[i].points + modifier local current_phase = self.relationships[i].phase - self.relationships[i].phase = npc.get_relationship_phase(self.relationships[i].points) + self.relationships[i].phase = npc.get_relationship_phase_by_points(self.relationships[i].points) if current_phase ~= self.relationships[i].phase then self.gift_data.favorite_items = select_random_favorite_items(self.sex, self.relationships[i].phase) @@ -362,6 +396,16 @@ local function check_relationship_exists(self, clicker_name) return false end +-- Returns the relationship phase given the name of the player +function npc.get_relationship_phase(self, clicker_name) + for i = 1, #self.relationships do + if clicker_name == self.relationships[i].name then + return self.relationships[i].phase + end + end + return nil +end + -- Checks if NPC can receive gifts local function check_npc_can_receive_gift(self, clicker_name) for i = 1, #self.relationships do @@ -431,7 +475,7 @@ local function show_receive_gift_reaction(self, item_name, modifier, clicker_nam local pos = self.object:getpos() -- Positive modifier (favorite items) reactions if modifier >= 0 then - local phase = npc.get_relationship_phase(points) + local phase = npc.get_relationship_phase_by_points(points) if phase == "phase3" then effect({x = pos.x, y = pos.y + 1, z = pos.z}, 2, "heart.png") elseif phase == "phase4" then @@ -631,25 +675,14 @@ local function dialogue_relationship_update(self, clicker) end -- Chat functions -local function start_dialogue(self, clicker) +function npc.start_dialogue(self, clicker, show_married_dialogue) -- Call chat function as normal - npc.dialogue.start_dialogue(self, clicker) + npc.dialogue.start_dialogue(self, clicker, show_married_dialogue) -- Check and update relationship if needed dialogue_relationship_update(self, clicker) - -- Married player can tell NPC to follow or to stay at a given place - -- TODO: Improve this. There should be a dialogue box for this - -- if self.owner and self.owner == name then - -- if self.order == "follow" then - -- self.order = "stand" - -- minetest.chat_send_player(name, S("Ok dear, I will wait here for you.")) - -- else - -- self.order = "follow" - -- minetest.chat_send_player(name, S("Let's go honey!")) - -- end - -- end end @@ -735,12 +768,12 @@ mobs:register_mob("advanced_npc:npc", { end, npc.dialogue.NEGATIVE_ANSWER_LABEL, function() - start_dialogue(self, clicker) + npc.start_dialogue(self, clicker, true) end, name ) else - start_dialogue(self, clicker) + npc.start_dialogue(self, clicker, true) end end, @@ -828,8 +861,7 @@ local function npc_spawn(self, pos) ent.dialogues = npc.dialogue.select_random_dialogues_for_npc(ent.sex, "phase1", ent.gift_data.favorite_items, - ent.gift_data.disliked_items, - false) + ent.gift_data.disliked_items) minetest.log(dump(ent)) diff --git a/random_data.lua b/random_data.lua index 6ae92c8..9efb971 100644 --- a/random_data.lua +++ b/random_data.lua @@ -32,8 +32,8 @@ npc.data.DIALOGUES.female["phase1"] = { [1] = { text = "No, never before", action_type = "function", - action = function(self, player_name) - minetest.chat_send_player(player_name, "Oh, never? How come! You should.".. + action = function(self, player) + minetest.chat_send_player(player:get_player_name(), "Oh, never? How come! You should.".. "\nHere, take this. It will guide you to the sea...") end }, @@ -79,8 +79,8 @@ npc.data.DIALOGUES.male["phase1"] = { [1] = { text = "No, never before", action_type = "function", - action = function(npc, player_name) - minetest.chat_send_player(player_name, "Then you are not worth my time.") + action = function(npc, player) + minetest.chat_send_player(player:get_player_name(), "Then you are not worth my time.") end }, [2] = {