File size: 6,124 Bytes
b6a38d7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
local hintColor = RGB(210, 255, 210)


----- ContinuousEffect

DefineClass.ContinuousEffect = {
	__parents = { "Effect" },
	properties = {
		{ id = "Id", editor = "text", help = "A unique Id allowing you to later stop this effect using StopEffect/StopGlobalEffect; optional", default = "",
		  no_edit = function(obj) return obj.Id:starts_with("autoid") end,
		},
	},
	CreateInstance = false,
	EditorExcludeAsNested = true,
	container = false, -- restored in ModifiersPreset:PostLoad(), won't be valid if the ContinuousEffect is not stored in a ModifiersPreset
}

function ContinuousEffect:Execute(object, ...)
	self:ValidateObject(object)
	assert(IsKindOf(object, "ContinuousEffectContainer"))
	object:StartEffect(self, ...)
end

if FirstLoad then
	g_MaxContinuousEffectId = 0
end

function ContinuousEffect:OnEditorNew(parent, ged, is_paste)
	-- ContinuousEffects embedded in a parent ContinuousEffect are managed by
	-- the parent effect and have an auto-generated internal uneditable Id
	local obj = ged:GetParentOfKind(parent, "PropertyObject")
	if obj and (obj:IsKindOf("ContinuousEffect") or obj:HasMember("ManagesContinuousEffects") and obj.ManagesContinuousEffects) then
		g_MaxContinuousEffectId = g_MaxContinuousEffectId + 1
		self.Id = "autoid" .. tostring(g_MaxContinuousEffectId)
	elseif self.Id:starts_with("autoid") then
		self.Id = ""
	elseif ged.app_template:starts_with("Mod") then
		local mod_item = IsKindOf(parent, "ModItem") and parent or ged:GetParentOfKind(parent, "ModItem")
		local mod_def = mod_item.mod
		self.Id = mod_def:GenerateModItemId(self)
	end
	self.container = obj
end

function ContinuousEffect:__fromluacode(table)
	local obj = Effect.__fromluacode(self, table)
	local id = obj.Id
	if id:starts_with("autoid") then
		g_MaxContinuousEffectId = Max(g_MaxContinuousEffectId, tonumber(id:sub(7, -1)))
	end
	return obj
end

function ContinuousEffect:__toluacode(...)
	local old = self.container
	self.container = nil -- restored in ModifiersPreset:PostLoad()
	local ret = Effect.__toluacode(self, ...)
	self.container = old
	return ret
end


----- ContinuousEffectDef

DefineClass.ContinuousEffectDef = {
	__parents = { "EffectDef" },
	group = "ContinuousEffects",
	DefParentClassList = { "ContinuousEffect" },
	GedEditor = "ClassDefEditor",
}

function ContinuousEffectDef:OnEditorNew(parent, ged, is_paste)
	if is_paste then return end

	-- remove Execute/__exec metod
	for i = #self, 1, -1 do
		if IsKindOf(self[i], "ClassMethodDef") and (self[i].name == "Execute" and self[i].name == "__exec" )then
			table.remove(self, i)
			break
		end	
	end
	-- add CreateInstance, Start, Stop, and Id
	local idx = #self + 1
	self[idx] = self[idx] or ClassMethodDef:new{ name = "OnStart", params = "obj, context"}
	idx = idx + 1
	self[idx] = self[idx] or ClassMethodDef:new{ name = "OnStop", params = "obj, context"}
	table.insert(self, 1, ClassConstDef:new{ id = "CreateInstance", name = "CreateInstance" , type = "bool", })
end

function ContinuousEffectDef:CheckExecMethod()
	local start = self:FindSubitem("Start")
	local stop = self:FindSubitem("Stop")
	if start and (start.class ~= "ClassMethodDef" or start.code == ClassMethodDef.code)  or 
		stop and (stop.class ~= "ClassMethodDef" or stop.code == ClassMethodDef.code) then
		return {[[--== Start & Stop ==--
Add Start and Stop methods that implement the effect. 
]], hintColor, table.find(self, start), table.find(self, stop) }
	end
end

function ContinuousEffectDef:GetError()
	local id = self:FindSubitem("CreateInstance")
	if not id then
		return "The CreateInstance constant is required for ContinuousEffects."
	end
end


----- ContinuousEffectContainer

DefineClass.ContinuousEffectContainer = {
	__parents = {"InitDone"},
	effects = false,	
}

function ContinuousEffectContainer:Done()
	for _, effect in ipairs(self.effects or empty_table) do
		effect:OnStop(self)
	end
	self.effects = false
end

function ContinuousEffectContainer:StartEffect(effect, context)
	self.effects = self.effects or {}
	
	local id = effect.Id or ""
	if id == "" then
		id = effect
	end
	if self.effects[id] then
		-- TODO: Add an AllowReplace property and assert whether AllowReplace is true?
		self:StopEffect(id)
	end
	if effect.CreateInstance then
		effect = effect:Clone()
	end
	self.effects[id] = effect
	self.effects[#self.effects + 1] = effect
	effect:OnStart(self, context)
	Msg("OnEffectStarted", self, effect)
	assert(effect.CreateInstance or not effect:HasNonPropertyMembers()) -- please set the CreateInstance class constant to 'true' to use dynamic members
end

function ContinuousEffectContainer:StopEffect(id)
	if not self.effects then return end
	local effect = self.effects[id]
	if not effect then return end
	effect:OnStop(self)
	table.remove_entry(self.effects, effect)
	self.effects[id] = nil
	Msg("OnEffectEnded", self, effect)
end

----- InfopanelMessage Effects

MapVar("g_AdditionalInfopanelSectionText", {})
function GetAdditionalInfopanelSectionText(sectionId, obj)	
	if not sectionId or sectionId=="" then
		return ""
	end	
	local section = g_AdditionalInfopanelSectionText[sectionId]
	if not section or not next(section) then 
		return ""
	end
	local texts = {}
	for label, text in pairs(section) do
		if label== "__AllSections" or IsKindOf(obj, label) then
			texts[#texts + 1] = text
		end
	end
	if not next(texts)then 
		return ""
	end
	return table.concat(texts, "\n")
end

function AddAdditionalInfopanelSectionText(sectionId, label, text, color, object, context)
	local style = "Infopanel"
	if color == "red" then
		style = "InfopanelError"
	elseif	color == "green" then
		style = "InfopanelBonus"	
	end
	local section = g_AdditionalInfopanelSectionText[sectionId] or {}
	label = label or "__AllSections"
	section[label] =  T{410957252932, "<textcolor><text></color>", textcolor = "<color " .. style .. ">", text = T{text, object, context}}	
	g_AdditionalInfopanelSectionText[sectionId] = section
end

function RemoveAdditionalInfopanelSectionText(sectionId, label)
	if g_AdditionalInfopanelSectionText[sectionId] then
		label = label or "__AllSections"
		g_AdditionalInfopanelSectionText[sectionId][label]= nil
	end
end