From 240cfdd06abfa4156f0b4d790796d23090330ee4 Mon Sep 17 00:00:00 2001
From: dg <dg@51575b47-30f0-44d4-a5cc-537603b46e54>
Date: Wed, 28 Apr 2010 00:19:01 +0000
Subject: [PATCH] Ukllmswwik is not hostile, but can be angered faction
 standing saved in savefile actors wont target a trap (and cause bugs)

git-svn-id: http://svn.net-core.org/repos/t-engine4@568 51575b47-30f0-44d4-a5cc-537603b46e54
---
 game/engine/Actor.lua                         |  1 +
 game/engine/Faction.lua                       | 21 +++++++++-
 game/engine/Game.lua                          |  2 +-
 game/engine/generator/actor/Random.lua        |  2 +
 game/modules/tome/class/NPC.lua               | 17 +++++++-
 game/modules/tome/class/interface/Combat.lua  |  8 +++-
 game/modules/tome/data/chats/ukllmswwik.lua   | 29 ++++++++++++++
 .../data/maps/zones/flooded-cave-last.lua     | 39 +++++++++++++++++++
 .../tome/data/zones/flooded-cave/npcs.lua     |  3 ++
 .../tome/data/zones/flooded-cave/zone.lua     | 18 +++++++--
 game/modules/tome/load.lua                    |  4 ++
 11 files changed, 135 insertions(+), 9 deletions(-)
 create mode 100644 game/modules/tome/data/chats/ukllmswwik.lua
 create mode 100644 game/modules/tome/data/maps/zones/flooded-cave-last.lua

diff --git a/game/engine/Actor.lua b/game/engine/Actor.lua
index a81136272e..30d6871460 100644
--- a/game/engine/Actor.lua
+++ b/game/engine/Actor.lua
@@ -27,6 +27,7 @@ module(..., package.seeall, class.inherit(Entity))
 function _M:init(t, no_default)
 	t = t or {}
 
+	if not self.targetable and self.targetable == nil then self.targetable = true end
 	self.name = t.name or "unknown actor"
 	self.level = t.level or 1
 	self.sight = t.sight or 20
diff --git a/game/engine/Faction.lua b/game/engine/Faction.lua
index 3e9097de00..a70fa0351e 100644
--- a/game/engine/Faction.lua
+++ b/game/engine/Faction.lua
@@ -33,7 +33,6 @@ function _M:add(t)
 	self.factions[t.short_name] = t
 end
 
-
 --- Returns the status of faction f1 toward f2
 -- @param f1 the source faction
 -- @param f2 the target faction
@@ -41,10 +40,30 @@ end
 function _M:factionReaction(f1, f2)
 	-- Faction always like itself
 	if f1 == f2 then return 100 end
+	if game.factions and game.factions[f1] and game.factions[f1][f2] then return game.factions[f1][f2] end
 	if not self.factions[f1] then return 0 end
 	return self.factions[f1].reaction[f2] or 0
 end
 
+--- Sets the status of faction f1 toward f2
+-- @param f1 the source faction
+-- @param f2 the target faction
+-- @param reaction a numerical value representing the reaction, 0 is neutral, <0 is aggressive, >0 is friendly
+-- @param mutual if true the same status will be set for f2 toward f1
+function _M:setFactionReaction(f1, f2, reaction, mutual)
+	-- Faction always like itself
+	if f1 == f2 then return end
+	if not self.factions[f1] then return end
+	if not self.factions[f2] then return end
+	game.factions = game.factions or {}
+	game.factions[f1] = game.factions[f1] or {}
+	game.factions[f1][f2] = reaction
+	if mutual then
+		game.factions[f2] = game.factions[f2] or {}
+		game.factions[f2][f1] = reaction
+	end
+end
+
 -- Add a few default factions
 _M:add{ name="Players", reaction={enemies=-100} }
 _M:add{ name="Enemies", reaction={players=-100} }
diff --git a/game/engine/Game.lua b/game/engine/Game.lua
index 50e2d016f8..af67ec261e 100644
--- a/game/engine/Game.lua
+++ b/game/engine/Game.lua
@@ -58,7 +58,7 @@ function _M:defaultSavedFields(t)
 		w=true, h=true, zone=true, player=true, level=true, entities=true,
 		energy_to_act=true, energy_per_tick=true, turn=true, paused=true, save_name=true,
 		always_target=true, gfxmode=true, uniques=true, object_known_types=true,
-		current_music=true, memory_levels=true, achievement_data=true,
+		current_music=true, memory_levels=true, achievement_data=true, factions=true,
 	}
 	table.merge(def, t)
 	return def
diff --git a/game/engine/generator/actor/Random.lua b/game/engine/generator/actor/Random.lua
index 06d4b81ec9..6caa279d25 100644
--- a/game/engine/generator/actor/Random.lua
+++ b/game/engine/generator/actor/Random.lua
@@ -34,6 +34,7 @@ function _M:init(zone, map, level)
 	self.filters = data.filters
 	self.nb_npc = data.nb_npc or {10, 20}
 	self.guardian = data.guardian
+	self.post_generation = data.post_generation
 end
 
 function _M:generate()
@@ -73,6 +74,7 @@ function _M:generateOne()
 		end
 		if tries < 100 then
 			self.zone:addEntity(self.level, m, "actor", x, y)
+			if self.post_generation then self.post_generation(m) end
 		end
 	end
 end
diff --git a/game/modules/tome/class/NPC.lua b/game/modules/tome/class/NPC.lua
index 83ef3f6efa..a5b78b82a5 100644
--- a/game/modules/tome/class/NPC.lua
+++ b/game/modules/tome/class/NPC.lua
@@ -19,6 +19,7 @@
 
 require "engine.class"
 local ActorAI = require "engine.interface.ActorAI"
+local Faction = require "engine.Faction"
 require "mod.class.Actor"
 
 module(..., package.seeall, class.inherit(mod.class.Actor, engine.interface.ActorAI))
@@ -44,7 +45,7 @@ end
 --- Called by ActorLife interface
 -- We use it to pass aggression values to the AIs
 function _M:onTakeHit(value, src)
-	if not self.ai_target.actor then
+	if not self.ai_target.actor and src.targetable then
 		self.ai_target.actor = src
 	end
 
@@ -52,6 +53,18 @@ function _M:onTakeHit(value, src)
 end
 
 function _M:tooltip()
+	local factcolor, factstate = "#ANTIQUE_WHITE#", "neutral"
+	if self:reactionToward(game.player) < 0 then factcolor, factstate = "#LIGHT_RED#", "hostile"
+	elseif self:reactionToward(game.player) > 0 then factcolor, factstate = "#LIGHT_GREEN#", "friendly"
+	end
+
 	local str = mod.class.Actor.tooltip(self)
-	return str..("\nTarget: %s\nUID: %d"):format(self.ai_target.actor and self.ai_target.actor.name or "none", self.uid)
+	return str..([[
+
+Faction: %s%s (%s)
+Target: %s
+UID: %d]]):format(
+	factcolor, Faction.factions[self.faction].name, factstate,
+	self.ai_target.actor and self.ai_target.actor.name or "none",
+	self.uid)
 end
diff --git a/game/modules/tome/class/interface/Combat.lua b/game/modules/tome/class/interface/Combat.lua
index afa460c5dc..7bb544ffcc 100644
--- a/game/modules/tome/class/interface/Combat.lua
+++ b/game/modules/tome/class/interface/Combat.lua
@@ -20,6 +20,7 @@
 require "engine.class"
 local DamageType = require "engine.DamageType"
 local Map = require "engine.Map"
+local Chat = require "engine.Chat"
 local Target = require "engine.Target"
 local Talents = require "engine.interface.ActorTalents"
 
@@ -34,10 +35,13 @@ function _M:bumpInto(target)
 		return self:attackTarget(target)
 	elseif reaction >= 0 then
 		-- Talk ?
+		print(self.player , target.can_talk)
 		if self.player and target.can_talk then
-			-- TODO: implement !
+			local chat = Chat.new(target.can_talk, target, self)
+			chat:invoke()
 		elseif target.player and self.can_talk then
-			-- TODO: implement! request the player to talk
+			local chat = Chat.new(self.can_talk, self, target)
+			chat:invoke()
 		elseif self.move_others then
 			-- Displace
 			game.level.map:remove(self.x, self.y, Map.ACTOR)
diff --git a/game/modules/tome/data/chats/ukllmswwik.lua b/game/modules/tome/data/chats/ukllmswwik.lua
new file mode 100644
index 0000000000..0891875708
--- /dev/null
+++ b/game/modules/tome/data/chats/ukllmswwik.lua
@@ -0,0 +1,29 @@
+-- ToME - Tales of Middle-Earth
+-- Copyright (C) 2009, 2010 Nicolas Casalini
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+newChat{ id="welcome",
+	text = [[#LIGHT_GREEN#*@npcname@ deep voice booms through the level.*#WHITE#
+This is my domain, and I do not take on intruders kindly. What is your purpose here?]],
+	answers = {
+		{"I am here to kill you and take your treasures! Die bastard fish!", action=function(npc, player) engine.Faction:setFactionReaction(player.faction, npc.faction, -100, true) end},
+		{"I did not mean to intrude, I shall leave now."},
+	}
+}
+
+return "welcome"
diff --git a/game/modules/tome/data/maps/zones/flooded-cave-last.lua b/game/modules/tome/data/maps/zones/flooded-cave-last.lua
new file mode 100644
index 0000000000..d0c0a29b0e
--- /dev/null
+++ b/game/modules/tome/data/maps/zones/flooded-cave-last.lua
@@ -0,0 +1,39 @@
+-- ToME - Tales of Middle-Earth
+-- Copyright (C) 2009, 2010 Nicolas Casalini
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+defineTile('<', "UP")
+defineTile('.', "WATER_FLOOR")
+defineTile('#', "WATER_WALL")
+defineTile('s', "WATER_FLOOR", nil, "UKLLMSWWIK")
+
+return {
+[[##################################################]],
+[[##..............................................##]],
+[[#.....######..................######.............#]],
+[[#....########................########............#]],
+[[#.....######..................######.............#]],
+[[#................................................#]],
+[[<...............................s................#]],
+[[#................................................#]],
+[[#.....######..................######.............#]],
+[[#....########................########............#]],
+[[#.....######..................######.............#]],
+[[##..............................................##]],
+[[##################################################]]
+}
diff --git a/game/modules/tome/data/zones/flooded-cave/npcs.lua b/game/modules/tome/data/zones/flooded-cave/npcs.lua
index c873237668..783bb525ad 100644
--- a/game/modules/tome/data/zones/flooded-cave/npcs.lua
+++ b/game/modules/tome/data/zones/flooded-cave/npcs.lua
@@ -26,6 +26,7 @@ local Talents = require("engine.interface.ActorTalents")
 newEntity{ define_as = "UKLLMSWWIK",
 	type = "dragon", subtype = "water", unique = true,
 	name = "Ukllmswwik the wise",
+	faction="water-lair",
 	display = "D", color=colors.VIOLET,
 	desc = [[It looks like a cross between a shark and a dragon, only nastier.]],
 	level_range = {3, 40}, exp_worth = 2,
@@ -45,4 +46,6 @@ newEntity{ define_as = "UKLLMSWWIK",
 
 	autolevel = "warrior",
 	ai = "dumb_talented_simple", ai_state = { talent_in=4, },
+
+	can_talk = "ukllmswwik",
 }
diff --git a/game/modules/tome/data/zones/flooded-cave/zone.lua b/game/modules/tome/data/zones/flooded-cave/zone.lua
index 860bab364f..e417511a60 100644
--- a/game/modules/tome/data/zones/flooded-cave/zone.lua
+++ b/game/modules/tome/data/zones/flooded-cave/zone.lua
@@ -21,7 +21,7 @@ return {
 	name = "Flooded Cave",
 	level_range = {25, 35},
 	level_scheme = "player",
-	max_level = 1,
+	max_level = 2,
 	decay = {300, 800},
 	actor_adjust_level = function(zone, level, e) return zone.base_level + e:getRankLevelAdjust() + level.level-1 + rng.range(-1,2) end,
 	width = 100, height = 100,
@@ -37,7 +37,7 @@ return {
 			class = "engine.generator.map.Roomer",
 			nb_rooms = 50,
 			edge_entrances = {4,6},
-			rooms = {"forest_clearing"},
+			rooms = {"forest_clearing","money_vault"},
 			['.'] = "WATER_FLOOR",
 			['#'] = "WATER_WALL",
 			up = "UP",
@@ -47,7 +47,7 @@ return {
 		actor = {
 			class = "engine.generator.actor.Random",
 			nb_npc = {30, 40},
-			guardian = "UKLLMSWWIK",
+--			guardian = "UKLLMSWWIK",
 		},
 		object = {
 			class = "engine.generator.object.Random",
@@ -66,5 +66,17 @@ return {
 				up = "UP_WILDERNESS",
 			}, },
 		},
+		[2] = {
+			generator = {
+				map = {
+					class = "engine.generator.map.Static",
+					map = "zones/flooded-cave-last",
+				},
+				actor = {
+					nb_npc = {7, 7},
+					post_generation = function(e) e.faction="water-lair" end,
+				},
+			},
+		},
 	},
 }
diff --git a/game/modules/tome/load.lua b/game/modules/tome/load.lua
index 4471d6c725..9b8bf101a3 100644
--- a/game/modules/tome/load.lua
+++ b/game/modules/tome/load.lua
@@ -20,6 +20,7 @@
 -- This file loads the game module, and loads data
 local KeyBind = require "engine.KeyBind"
 local DamageType = require "engine.DamageType"
+local Faction = require "engine.Faction"
 local ActorStats = require "engine.interface.ActorStats"
 local ActorResource = require "engine.interface.ActorResource"
 local ActorTalents = require "engine.interface.ActorTalents"
@@ -87,6 +88,9 @@ ActorStats:defineStat("Luck",		"lck", 50, 1, 100, "Luck defines your character's
 -- Actor leveling, player is restricted to 50 bu npcs can go higher
 ActorLevel:defineMaxLevel(75)
 
+-- Factions
+Faction:add{ name="water lair", reaction={} }
+
 -- Actor autolevel schemes
 dofile("/data/autolevel_schemes.lua")
 
-- 
GitLab