Commit 3fd459823e6ead702520e5bfffd049b21ba04783
1 parent
930743c1
plop
git-svn-id: http://svn.net-core.org/repos/t-engine4@3243 51575b47-30f0-44d4-a5cc-537603b46e54
Showing
17 changed files
with
0 additions
and
3058 deletions
Too many changes to show.
To preserve performance only 17 of 17+ files are displayed.
game/modules/angband/ai/angband.lua
deleted
100644 → 0
1 | --- TE4 - T-Engine 4 | |
2 | --- Copyright (C) 2009, 2010, 2011 Nicolas Casalini | |
3 | --- | |
4 | --- This program is free software: you can redistribute it and/or modify | |
5 | --- it under the terms of the GNU General Public License as published by | |
6 | --- the Free Software Foundation, either version 3 of the License, or | |
7 | --- (at your option) any later version. | |
8 | --- | |
9 | --- This program is distributed in the hope that it will be useful, | |
10 | --- but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | --- GNU General Public License for more details. | |
13 | --- | |
14 | --- You should have received a copy of the GNU General Public License | |
15 | --- along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | --- | |
17 | --- Nicolas Casalini "DarkGod" | |
18 | --- darkgod@te4.org | |
19 | - | |
20 | --- Defines AIs that can use talents, either smartly or "dumbly" | |
21 | - | |
22 | -newAI("angband", function(self) | |
23 | - if self:runAI(self.ai_state.ai_target or "target_simple") then | |
24 | - -- One in "talent_in" chance of using a talent | |
25 | - if (not self.ai_state.no_talents or self.ai_state.no_talents == 0) and rng.chance(self.ai_state.talent_in or 6) and self:reactionToward(self.ai_target.actor) < 0 then | |
26 | - self:runAI("dumb_talented") | |
27 | - end | |
28 | - if not self.energy.used then | |
29 | - self:runAI(self.ai_state.ai_move or "move_simple") | |
30 | - end | |
31 | - return true | |
32 | - end |
game/modules/angband/class/Actor.lua
deleted
100644 → 0
1 | --- ToME - Tales of Middle-Earth | |
2 | --- Copyright (C) 2009, 2010, 2011 Nicolas Casalini | |
3 | --- | |
4 | --- This program is free software: you can redistribute it and/or modify | |
5 | --- it under the terms of the GNU General Public License as published by | |
6 | --- the Free Software Foundation, either version 3 of the License, or | |
7 | --- (at your option) any later version. | |
8 | --- | |
9 | --- This program is distributed in the hope that it will be useful, | |
10 | --- but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | --- GNU General Public License for more details. | |
13 | --- | |
14 | --- You should have received a copy of the GNU General Public License | |
15 | --- along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | --- | |
17 | --- Nicolas Casalini "DarkGod" | |
18 | --- darkgod@te4.org | |
19 | - | |
20 | -require "engine.class" | |
21 | -require "engine.Actor" | |
22 | -require "engine.Autolevel" | |
23 | -require "engine.interface.ActorTemporaryEffects" | |
24 | -require "engine.interface.ActorLife" | |
25 | -require "engine.interface.ActorProject" | |
26 | -require "engine.interface.ActorLevel" | |
27 | -require "engine.interface.ActorStats" | |
28 | -require "engine.interface.ActorTalents" | |
29 | -require "engine.interface.ActorResource" | |
30 | -require "engine.interface.ActorFOV" | |
31 | -local Map = require "engine.Map" | |
32 | - | |
33 | -module(..., package.seeall, class.inherit( | |
34 | - engine.Actor, | |
35 | - engine.interface.ActorTemporaryEffects, | |
36 | - engine.interface.ActorLife, | |
37 | - engine.interface.ActorProject, | |
38 | - engine.interface.ActorLevel, | |
39 | - engine.interface.ActorStats, | |
40 | - engine.interface.ActorTalents, | |
41 | - engine.interface.ActorResource, | |
42 | - engine.interface.ActorFOV | |
43 | -)) | |
44 | - | |
45 | -_M._noalpha = true | |
46 | - | |
47 | -function _M:init(t, no_default) | |
48 | - -- Define some basic combat stats | |
49 | - self.combat_armor = 0 | |
50 | - | |
51 | - -- Default regen | |
52 | - t.power_regen = t.power_regen or 1 | |
53 | - t.life_regen = t.life_regen or 0.25 -- Life regen real slow | |
54 | - | |
55 | - t.esp = {} | |
56 | - t.speed = t.speed or 0 | |
57 | - | |
58 | - -- Default melee barehanded damage | |
59 | - self.combat = { dam=1 } | |
60 | - | |
61 | - engine.Actor.init(self, t, no_default) | |
62 | - engine.interface.ActorTemporaryEffects.init(self, t) | |
63 | - engine.interface.ActorLife.init(self, t) | |
64 | - engine.interface.ActorProject.init(self, t) | |
65 | - engine.interface.ActorTalents.init(self, t) | |
66 | - engine.interface.ActorResource.init(self, t) | |
67 | - engine.interface.ActorStats.init(self, t) | |
68 | - engine.interface.ActorLevel.init(self, t) | |
69 | - engine.interface.ActorFOV.init(self, t) | |
70 | - | |
71 | - self:computeEnergyMod() | |
72 | -end | |
73 | - | |
74 | -function _M:act() | |
75 | - if not engine.Actor.act(self) then return end | |
76 | - | |
77 | - self.changed = true | |
78 | - | |
79 | - -- Cooldown talents | |
80 | - self:cooldownTalents() | |
81 | - -- Regen resources | |
82 | - self:regenLife() | |
83 | - self:regenResources() | |
84 | - -- Compute timed effects | |
85 | - self:timedEffects() | |
86 | - | |
87 | - -- Still enough energy to act ? | |
88 | - if self.energy.value < game.energy_to_act then return false end | |
89 | - | |
90 | - return true | |
91 | -end | |
92 | - | |
93 | -function _M:move(x, y, force) | |
94 | - local moved = false | |
95 | - if force or self:enoughEnergy() then | |
96 | - -- Never move but tries to attack ? ok | |
97 | - if not force and self:attr("never_move") then | |
98 | - -- A bit weird, but this simple asks the collision code to detect an attack | |
99 | - if not game.level.map:checkAllEntities(x, y, "block_move", self, true) then | |
100 | - game.logPlayer(self, "You are unable to move!") | |
101 | - end | |
102 | - else | |
103 | - moved = engine.Actor.move(self, x, y, force) | |
104 | - end | |
105 | - if not force and moved and not self.did_energy then self:useEnergy() end | |
106 | - end | |
107 | - self.did_energy = nil | |
108 | - return moved | |
109 | -end | |
110 | - | |
111 | -local extract_energy = | |
112 | -{ | |
113 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
114 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
115 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
116 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
117 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
118 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
119 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
120 | - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | |
121 | - 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, | |
122 | - 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, | |
123 | - 5, 5, 5, 5, 6, 6, 7, 7, 8, 9, | |
124 | - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, | |
125 | - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, | |
126 | - 30, 31, 32, 33, 34, 35, 36, 36, 37, 37, | |
127 | - 38, 38, 39, 39, 40, 40, 40, 41, 41, 41, | |
128 | - 42, 42, 42, 43, 43, 43, 44, 44, 44, 44, | |
129 | - 45, 45, 45, 45, 45, 46, 46, 46, 46, 46, | |
130 | - 47, 47, 47, 47, 47, 48, 48, 48, 48, 48, | |
131 | - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, | |
132 | - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, | |
133 | -} | |
134 | - | |
135 | ---- Compute energy mod based on speed | |
136 | -function _M:computeEnergyMod() | |
137 | - self.energy.mod = extract_energy[self.speed + 111] / 10 | |
138 | -end | |
139 | - | |
140 | ---- Called when a temporary value changes (added or deleted) | |
141 | --- Takes care to compute energy mod | |
142 | --- @param prop the property changing | |
143 | --- @param v the value of the change | |
144 | --- @param base the base table of prop | |
145 | -function _M:onTemporaryValueChange(prop, v, base) | |
146 | - if prop == "speed" and base == self then | |
147 | - self:computeEnergyMod() | |
148 | - end | |
149 | -end | |
150 | - | |
151 | ---- Reveals location surrounding the actor | |
152 | -function _M:magicMap(radius, x, y) | |
153 | - x = x or self.x | |
154 | - y = y or self.y | |
155 | - radius = math.floor(radius) | |
156 | - | |
157 | - local ox, oy | |
158 | - | |
159 | - self.x, self.y, ox, oy = x, y, self.x, self.y | |
160 | - self:computeFOV(radius, "block_sense", function(x, y) | |
161 | - game.level.map.remembers(x, y, true) | |
162 | - game.level.map.has_seens(x, y, true) | |
163 | - end, true, true, true) | |
164 | - | |
165 | - self.x, self.y = ox, oy | |
166 | -end | |
167 | - | |
168 | -function _M:tooltip() | |
169 | - return ([[%s%s | |
170 | -#00ffff#Level: %d | |
171 | -#ff0000#HP: %d (%d%%) | |
172 | -Stats: %d / %d / %d | |
173 | -%s]]):format( | |
174 | - self:getDisplayString(), | |
175 | - self.name, | |
176 | - self.level, | |
177 | - self.life, self.life * 100 / self.max_life, | |
178 | - self:getStr(), | |
179 | - self:getDex(), | |
180 | - self:getCon(), | |
181 | - self.desc or "" | |
182 | - ) | |
183 | -end | |
184 | - | |
185 | -function _M:onTakeHit(value, src) | |
186 | - return value | |
187 | -end | |
188 | - | |
189 | -function _M:die(src) | |
190 | - engine.interface.ActorLife.die(self, src) | |
191 | - | |
192 | - -- Gives the killer some exp for the kill | |
193 | - if src and src.gainExp then | |
194 | - src:gainExp(self:worthExp(src)) | |
195 | - end | |
196 | - | |
197 | - return true | |
198 | -end | |
199 | - | |
200 | -function _M:levelup() | |
201 | - self.max_life = self.max_life + 2 | |
202 | - | |
203 | - self:incMaxPower(3) | |
204 | - | |
205 | - -- Healp up on new level | |
206 | - self.life = self.max_life | |
207 | - self.power = self.max_power | |
208 | -end | |
209 | - | |
210 | ---- Notifies a change of stat value | |
211 | -function _M:onStatChange(stat, v) | |
212 | - if stat == self.STAT_CON then | |
213 | - self.max_life = self.max_life + 2 | |
214 | - end | |
215 | -end | |
216 | - | |
217 | -function _M:attack(target) | |
218 | - self:bumpInto(target) | |
219 | -end | |
220 | - | |
221 | - | |
222 | ---- Called before a talent is used | |
223 | --- Check the actor can cast it | |
224 | --- @param ab the talent (not the id, the table) | |
225 | --- @return true to continue, false to stop | |
226 | -function _M:preUseTalent(ab, silent) | |
227 | - if not self:enoughEnergy() then print("fail energy") return false end | |
228 | - | |
229 | - if ab.mode == "sustained" then | |
230 | - if ab.sustain_power and self.max_power < ab.sustain_power and not self:isTalentActive(ab.id) then | |
231 | - game.logPlayer(self, "You do not have enough power to activate %s.", ab.name) | |
232 | - return false | |
233 | - end | |
234 | - else | |
235 | - if ab.power and self:getPower() < ab.power then | |
236 | - game.logPlayer(self, "You do not have enough power to cast %s.", ab.name) | |
237 | - return false | |
238 | - end | |
239 | - end | |
240 | - | |
241 | - if not silent then | |
242 | - -- Allow for silent talents | |
243 | - if ab.message ~= nil then | |
244 | - if ab.message then | |
245 | - game.logSeen(self, "%s", self:useTalentMessage(ab)) | |
246 | - end | |
247 | - elseif ab.mode == "sustained" and not self:isTalentActive(ab.id) then | |
248 | - game.logSeen(self, "%s activates %s.", self.name:capitalize(), ab.name) | |
249 | - elseif ab.mode == "sustained" and self:isTalentActive(ab.id) then | |
250 | - game.logSeen(self, "%s deactivates %s.", self.name:capitalize(), ab.name) | |
251 | - else | |
252 | - game.logSeen(self, "%s uses %s.", self.name:capitalize(), ab.name) | |
253 | - end | |
254 | - end | |
255 | - return true | |
256 | -end | |
257 | - | |
258 | ---- Called before a talent is used | |
259 | --- Check if it must use a turn, mana, stamina, ... | |
260 | --- @param ab the talent (not the id, the table) | |
261 | --- @param ret the return of the talent action | |
262 | --- @return true to continue, false to stop | |
263 | -function _M:postUseTalent(ab, ret) | |
264 | - if not ret then return end | |
265 | - | |
266 | - self:useEnergy() | |
267 | - | |
268 | - if ab.mode == "sustained" then | |
269 | - if not self:isTalentActive(ab.id) then | |
270 | - if ab.sustain_power then | |
271 | - self.max_power = self.max_power - ab.sustain_power | |
272 | - end | |
273 | - else | |
274 | - if ab.sustain_power then | |
275 | - self.max_power = self.max_power + ab.sustain_power | |
276 | - end | |
277 | - end | |
278 | - else | |
279 | - if ab.power then | |
280 | - self:incPower(-ab.power) | |
281 | - end | |
282 | - end | |
283 | - | |
284 | - return true | |
285 | -end | |
286 | - | |
287 | ---- Return the full description of a talent | |
288 | --- You may overload it to add more data (like power usage, ...) | |
289 | -function _M:getTalentFullDescription(t) | |
290 | - local d = {} | |
291 | - | |
292 | - if t.mode == "passive" then d[#d+1] = "#6fff83#Use mode: #00FF00#Passive" | |
293 | - elseif t.mode == "sustained" then d[#d+1] = "#6fff83#Use mode: #00FF00#Sustained" | |
294 | - else d[#d+1] = "#6fff83#Use mode: #00FF00#Activated" | |
295 | - end | |
296 | - | |
297 | - if t.power or t.sustain_power then d[#d+1] = "#6fff83#Power cost: #7fffd4#"..(t.power or t.sustain_power) end | |
298 | - if self:getTalentRange(t) > 1 then d[#d+1] = "#6fff83#Range: #FFFFFF#"..self:getTalentRange(t) | |
299 | - else d[#d+1] = "#6fff83#Range: #FFFFFF#melee/personal" | |
300 | - end | |
301 | - if t.cooldown then d[#d+1] = "#6fff83#Cooldown: #FFFFFF#"..t.cooldown end | |
302 | - | |
303 | - return table.concat(d, "\n").."\n#6fff83#Description: #FFFFFF#"..t.info(self, t) | |
304 | -end | |
305 | - | |
306 | ---- How much experience is this actor worth | |
307 | --- @param target to whom is the exp rewarded | |
308 | --- @return the experience rewarded | |
309 | -function _M:worthExp(target) | |
310 | - return self.exp_worth * self.level / target.level | |
311 | -end | |
312 | - | |
313 | ---- Can the actor see the target actor | |
314 | --- This does not check LOS or such, only the actual ability to see it.<br/> | |
315 | --- Check for telepathy, invisibility, stealth, ... | |
316 | -function _M:canSee(actor, def, def_pct) | |
317 | - if not actor then return false, 0 end | |
318 | - | |
319 | - -- Check for stealth. Checks against the target cunning and level | |
320 | - if actor:attr("stealth") and actor ~= self then | |
321 | - local def = self.level / 2 + self:getCun(25) | |
322 | - local hit, chance = self:checkHit(def, actor:attr("stealth") + (actor:attr("inc_stealth") or 0), 0, 100) | |
323 | - if not hit then | |
324 | - return false, chance | |
325 | - end | |
326 | - end | |
327 | - | |
328 | - if def ~= nil then | |
329 | - return def, def_pct | |
330 | - else | |
331 | - return true, 100 | |
332 | - end | |
333 | -end | |
334 | - | |
335 | ---- Can the target be applied some effects | |
336 | --- @param what a string describing what is being tried | |
337 | -function _M:canBe(what) | |
338 | - if what == "poison" and rng.percent(100 * (self:attr("poison_immune") or 0)) then return false end | |
339 | - if what == "cut" and rng.percent(100 * (self:attr("cut_immune") or 0)) then return false end | |
340 | - if what == "confusion" and rng.percent(100 * (self:attr("confusion_immune") or 0)) then return false end | |
341 | - if what == "blind" and rng.percent(100 * (self:attr("blind_immune") or 0)) then return false end | |
342 | - if what == "stun" and rng.percent(100 * (self:attr("stun_immune") or 0)) then return false end | |
343 | - if what == "fear" and rng.percent(100 * (self:attr("fear_immune") or 0)) then return false end | |
344 | - if what == "instakill" and rng.percent(100 * (self:attr("instakill_immune") or 0)) then return false end | |
345 | - return true |
game/modules/angband/class/Game.lua
deleted
100644 → 0
1 | --- ToME - Tales of Middle-Earth | |
2 | --- Copyright (C) 2009, 2010, 2011 Nicolas Casalini | |
3 | --- | |
4 | --- This program is free software: you can redistribute it and/or modify | |
5 | --- it under the terms of the GNU General Public License as published by | |
6 | --- the Free Software Foundation, either version 3 of the License, or | |
7 | --- (at your option) any later version. | |
8 | --- | |
9 | --- This program is distributed in the hope that it will be useful, | |
10 | --- but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | --- GNU General Public License for more details. | |
13 | --- | |
14 | --- You should have received a copy of the GNU General Public License | |
15 | --- along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | --- | |
17 | --- Nicolas Casalini "DarkGod" | |
18 | --- darkgod@te4.org | |
19 | - | |
20 | -require "engine.class" | |
21 | -require "engine.GameTurnBased" | |
22 | -require "engine.interface.GameTargeting" | |
23 | -require "engine.KeyBind" | |
24 | -local Savefile = require "engine.Savefile" | |
25 | -local DamageType = require "engine.DamageType" | |
26 | -local Zone = require "engine.Zone" | |
27 | -local Map = require "engine.Map" | |
28 | -local Level = require "engine.Level" | |
29 | -local Birther = require "engine.Birther" | |
30 | - | |
31 | -local Grid = require "mod.class.Grid" | |
32 | -local Actor = require "mod.class.Actor" | |
33 | -local Player = require "mod.class.Player" | |
34 | -local NPC = require "mod.class.NPC" | |
35 | - | |
36 | -local PlayerDisplay = require "mod.class.PlayerDisplay" | |
37 | - | |
38 | -local HotkeysDisplay = require "engine.HotkeysDisplay" | |
39 | -local ActorsSeenDisplay = require "engine.ActorsSeenDisplay" | |
40 | -local LogDisplay = require "engine.LogDisplay" | |
41 | -local LogFlasher = require "engine.LogFlasher" | |
42 | -local DebugConsole = require "engine.DebugConsole" | |
43 | -local FlyingText = require "engine.FlyingText" | |
44 | -local Tooltip = require "engine.Tooltip" | |
45 | - | |
46 | -local QuitDialog = require "mod.dialogs.Quit" | |
47 | - | |
48 | -module(..., package.seeall, class.inherit(engine.GameTurnBased, engine.interface.GameTargeting)) | |
49 | - | |
50 | -function _M:init() | |
51 | - engine.GameTurnBased.init(self, engine.KeyBind.new(), 1000, 100) | |
52 | - | |
53 | - -- Pause at birth | |
54 | - self.paused = true | |
55 | - | |
56 | - -- Same init as when loaded from a savefile | |
57 | - self:loaded() | |
58 | -end | |
59 | - | |
60 | -function _M:run() | |
61 | - self.flash = LogFlasher.new(0, 0, self.w, 20, nil, nil, nil, {255,255,255}, {0,0,0}) | |
62 | - self.logdisplay = LogDisplay.new(0, self.h * 0.8, self.w * 0.5, self.h * 0.2, nil, nil, nil, {255,255,255}, "/data/gfx/ui/message-log.png") | |
63 | - self.player_display = PlayerDisplay.new(0, 220, 200, self.h * 0.8 - 220, {30,30,0}) | |
64 | - self.hotkeys_display = HotkeysDisplay.new(nil, self.w * 0.5, self.h * 0.8, self.w * 0.5, self.h * 0.2, "/data/gfx/ui/talents-list.png") | |
65 | - self.npcs_display = ActorsSeenDisplay.new(nil, self.w * 0.5, self.h * 0.8, self.w * 0.5, self.h * 0.2, "/data/gfx/ui/talents-list.png") | |
66 | - self.tooltip = Tooltip.new(nil, nil, {255,255,255}, {30,30,30}) | |
67 | - self.flyers = FlyingText.new() | |
68 | - self:setFlyingText(self.flyers) | |
69 | - self.minimap_bg, self.minimap_bg_w, self.minimap_bg_h = core.display.loadImage("/data/gfx/ui/minimap.png"):glTexture() | |
70 | - self:createSeparators() | |
71 | - | |
72 | - self.log = function(style, ...) if type(style) == "number" then self.logdisplay(...) self.flash(style, ...) else self.logdisplay(style, ...) self.flash(self.flash.NEUTRAL, style, ...) end end | |
73 | - self.logSeen = function(e, style, ...) if e and self.level.map.seens(e.x, e.y) then self.log(style, ...) end end | |
74 | - self.logPlayer = function(e, style, ...) if e == self.player then self.log(style, ...) end end | |
75 | - | |
76 | - self.log(self.flash.GOOD, "Welcome to #00FF00#the Pits of Angband!") | |
77 | - | |
78 | - -- Setup inputs | |
79 | - self:setupCommands() | |
80 | - self:setupMouse() | |
81 | - | |
82 | - -- Starting from here we create a new game | |
83 | - if not self.player then self:newGame() end | |
84 | - | |
85 | - self.hotkeys_display.actor = self.player | |
86 | - self.npcs_display.actor = self.player | |
87 | - | |
88 | - -- Setup the targetting system | |
89 | - engine.interface.GameTargeting.init(self) | |
90 | - | |
91 | - -- Ok everything is good to go, activate the game in the engine! | |
92 | - self:setCurrent() | |
93 | - | |
94 | - if self.level then self:setupDisplayMode() end | |
95 | -end | |
96 | - | |
97 | -function _M:newGame() | |
98 | - self.player = Player.new{name=self.player_name, game_ender=true} | |
99 | - Map:setViewerActor(self.player) | |
100 | - self:setupDisplayMode() | |
101 | - | |
102 | - self.creating_player = true | |
103 | - local birth = Birther.new(nil, self.player, {"base", "race", "class" }, function() | |
104 | - self:changeLevel(1, "dungeon") | |
105 | - print("[PLAYER BIRTH] resolve...") | |
106 | - self.player:resolve() | |
107 | - self.player:resolve(nil, true) | |
108 | - self.player.energy.value = self.energy_to_act | |
109 | - self.paused = true | |
110 | - self.creating_player = false | |
111 | - print("[PLAYER BIRTH] resolved!") | |
112 | - end) | |
113 | - self:registerDialog(birth) | |
114 | -end | |
115 | - | |
116 | -function _M:loaded() | |
117 | - engine.GameTurnBased.loaded(self) | |
118 | - Zone:setup{npc_class="mod.class.NPC", grid_class="mod.class.Grid", object_class="mod.class.Object", ood_factor=7} | |
119 | - Map:setViewerActor(self.player) | |
120 | - Map:setViewPort(200, 20, self.w - 200, math.floor(self.h * 0.80) - 20, 12, 16, "/data/font/FSEX300.ttf", 16, true) | |
121 | - self.key = engine.KeyBind.new() | |
122 | -end | |
123 | - | |
124 | -function _M:createSeparators() | |
125 | - self.bottom_separator, self.bottom_separator_w, self.bottom_separator_h = self:createVisualSeparator("horizontal", self.w) | |
126 | - self.split_separator, self.split_separator_w, self.split_separator_h = self:createVisualSeparator("vertical", math.floor(self.h * 0.2)) | |
127 | - self.player_separator, self.player_separator_w, self.player_separator_h = self:createVisualSeparator("vertical", math.floor(self.h * 0.8) - 20) | |
128 | -end | |
129 | - | |
130 | -function _M:setupDisplayMode() | |
131 | - Map:setViewPort(200, 20, self.w - 200, math.floor(self.h * 0.80) - 20, 12, 16, "/data/font/FSEX300.ttf", 16, true) | |
132 | - Map:resetTiles() | |
133 | - Map.tiles.use_images = false | |
134 | - | |
135 | - if self.level then | |
136 | - self.level.map:recreate() | |
137 | - engine.interface.GameTargeting.init(self) | |
138 | - self.level.map:moveViewSurround(self.player.x, self.player.y, 8, 8) | |
139 | - end | |
140 | -end | |
141 | - | |
142 | -function _M:save() | |
143 | - return class.save(self, self:defaultSavedFields{}, true) | |
144 | -end | |
145 | - | |
146 | -function _M:getSaveDescription() | |
147 | - return { | |
148 | - name = self.player.name, | |
149 | - description = ([[Exploring level %d of %s.]]):format(self.level.level, self.zone.name), | |
150 | - } | |
151 | -end | |
152 | - | |
153 | -function _M:leaveLevel(level, lev, old_lev) | |
154 | - if level:hasEntity(self.player) then | |
155 | - level.exited = level.exited or {} | |
156 | - if lev > old_lev then | |
157 | - level.exited.down = {x=self.player.x, y=self.player.y} | |
158 | - else | |
159 | - level.exited.up = {x=self.player.x, y=self.player.y} | |
160 | - end | |
161 | - level.last_turn = game.turn | |
162 | - level:removeEntity(self.player) | |
163 | - end | |
164 | -end | |
165 | - | |
166 | -function _M:changeLevel(lev, zone) | |
167 | - local old_lev = (self.level and not zone) and self.level.level or -1000 | |
168 | - if zone then | |
169 | - if self.zone then | |
170 | - self.zone:leaveLevel(false, lev, old_lev) | |
171 | - self.zone:leave() | |
172 | - end | |
173 | - if type(zone) == "string" then | |
174 | - self.zone = Zone.new(zone) | |
175 | - else | |
176 | - self.zone = zone | |
177 | - end | |
178 | - end | |
179 | - self.zone:getLevel(self, lev, old_lev) | |
180 | - | |
181 | - if lev > old_lev then | |
182 | - self.player:move(self.level.default_up.x, self.level.default_up.y, true) | |
183 | - else | |
184 | - self.player:move(self.level.default_down.x, self.level.default_down.y, true) | |
185 | - end | |
186 | - self.level:addEntity(self.player) | |
187 | - | |
188 | --- self.level.map:setZoom(1.2, self.player.x, self.player.y) | |
189 | -end | |
190 | - | |
191 | -function _M:getPlayer() | |
192 | - return self.player | |
193 | -end | |
194 | - | |
195 | -function _M:tick() | |
196 | - if self.level then | |
197 | - self:targetOnTick() | |
198 | - | |
199 | - engine.GameTurnBased.tick(self) | |
200 | - -- Fun stuff: this can make the game realtime, although callit it in display() will make it work better | |
201 | - -- (since display is on a set FPS while tick() ticks as much as possible | |
202 | - -- engine.GameEnergyBased.tick(self) | |
203 | - end | |
204 | - -- When paused (waiting for player input) we return true: this means we wont be called again until an event wakes us | |
205 | - if self.paused and not savefile_pipe.saving then return true end | |
206 | -end | |
207 | - | |
208 | ---- Called every game turns | |
209 | --- Does nothing, you can override it | |
210 | -function _M:onTurn() | |
211 | - -- The following happens only every 10 game turns (once for every turn of 1 mod speed actors) | |
212 | - if self.turn % 10 ~= 0 then return end | |
213 | - | |
214 | - -- Process overlay effects | |
215 | - self.level.map:processEffects() | |
216 | -end | |
217 | - | |
218 | -function _M:display(nb_keyframe) | |
219 | - -- If switching resolution, blank everything but the dialog | |
220 | - if self.change_res_dialog then engine.GameTurnBased.display(self, nb_keyframe) return end | |
221 | - | |
222 | - -- Now the map, if any | |
223 | - if self.level and self.level.map and self.level.map.finished and self.player.x and self.player.y then | |
224 | - -- Display the map and compute FOV for the player if needed | |
225 | - if self.level.map.changed then | |
226 | - self.player:playerFOV() | |
227 | - end | |
228 | - | |
229 | - self.level.map:display(nil, nil, nb_keyframe) | |
230 | - | |
231 | - -- Display the targetting system if active | |
232 | - self.target:display() | |
233 | - | |
234 | - -- Minimap display | |
235 | - self.minimap_bg:toScreenFull(0, 20, 200, 200, self.minimap_bg_w, self.minimap_bg_h) | |
236 | - self.level.map:minimapDisplay(0, 20, util.bound(self.player.x - 25, 0, self.level.map.w - 50), util.bound(self.player.y - 25, 0, self.level.map.h - 50), 50, 50, 1) | |
237 | - end | |
238 | - | |
239 | - -- We display the player's interface | |
240 | - self.flash:toScreen(nb_keyframe) | |
241 | - self.logdisplay:toScreen() | |
242 | - self.player_display:toScreen() | |
243 | - if self.show_npc_list then | |
244 | - self.npcs_display:toScreen() | |
245 | - else | |
246 | - self.hotkeys_display:toScreen() | |
247 | - end | |
248 | - if self.player then self.player.changed = false end | |
249 | - | |
250 | - -- Separators | |
251 | - self.bottom_separator:toScreenFull(0, 20 - 3, self.w, 6, self.bottom_separator_w, self.bottom_separator_h) | |
252 | - self.bottom_separator:toScreenFull(0, self.h * 0.8 - 3, self.w, 6, self.bottom_separator_w, self.bottom_separator_h) | |
253 | - self.split_separator:toScreenFull(self.w * 0.5 - 3 - 15, self.h * 0.8, 6, self.h * 0.2, self.split_separator_w, self.split_separator_h) | |
254 | - self.split_separator:toScreenFull(self.w * 0.5 - 3, self.h * 0.8, 6, self.h * 0.2, self.split_separator_w, self.split_separator_h) | |
255 | - self.player_separator:toScreenFull(200 - 3, 20, 6, self.h * 0.8 - 20, self.player_separator_w, self.player_separator_h) | |
256 | - | |
257 | - -- Tooltip is displayed over all else | |
258 | - self:targetDisplayTooltip() | |
259 | - | |
260 | - engine.GameTurnBased.display(self, nb_keyframe) | |
261 | -end | |
262 | - | |
263 | ---- Setup the keybinds | |
264 | -function _M:setupCommands() | |
265 | - -- Make targeting work | |
266 | - self.normal_key = self.key | |
267 | - self:targetSetupKey() | |
268 | - | |
269 | - -- Debug mode | |
270 | - self.key:addCommands{ | |
271 | - [{"_a","ctrl"}] = function() if config.settings.cheat then game:registerDialog(require("mod.dialogs.debug.DebugMain").new()) end end, | |
272 | - } | |
273 | - | |
274 | - -- One key handled for normal function | |
275 | - self.key:addBinds | |
276 | - { | |
277 | - -- Movements | |
278 | - MOVE_LEFT = function() self.player:moveDir(4) end, | |
279 | - MOVE_RIGHT = function() self.player:moveDir(6) end, | |
280 | - MOVE_UP = function() self.player:moveDir(8) end, | |
281 | - MOVE_DOWN = function() self.player:moveDir(2) end, | |
282 | - MOVE_LEFT_UP = function() self.player:moveDir(7) end, | |
283 | - MOVE_LEFT_DOWN = function() self.player:moveDir(1) end, | |
284 | - MOVE_RIGHT_UP = function() self.player:moveDir(9) end, | |
285 | - MOVE_RIGHT_DOWN = function() self.player:moveDir(3) end, | |
286 | - MOVE_STAY = function() self.player:useEnergy() end, | |
287 | - | |
288 | - RUN_LEFT = function() self.player:runInit(4) end, | |
289 | - RUN_RIGHT = function() self.player:runInit(6) end, | |
290 | - RUN_UP = function() self.player:runInit(8) end, | |
291 | - RUN_DOWN = function() self.player:runInit(2) end, | |
292 | - RUN_LEFT_UP = function() self.player:runInit(7) end, | |
293 | - RUN_LEFT_DOWN = function() self.player:runInit(1) end, | |
294 | - RUN_RIGHT_UP = function() self.player:runInit(9) end, | |
295 | - RUN_RIGHT_DOWN = function() self.player:runInit(3) end, | |
296 | - | |
297 | - -- Hotkeys | |
298 | - HOTKEY_1 = function() self.player:activateHotkey(1) end, | |
299 | - HOTKEY_2 = function() self.player:activateHotkey(2) end, | |
300 | - HOTKEY_3 = function() self.player:activateHotkey(3) end, | |
301 | - HOTKEY_4 = function() self.player:activateHotkey(4) end, | |
302 | - HOTKEY_5 = function() self.player:activateHotkey(5) end, | |
303 | - HOTKEY_6 = function() self.player:activateHotkey(6) end, | |
304 | - HOTKEY_7 = function() self.player:activateHotkey(7) end, | |
305 | - HOTKEY_8 = function() self.player:activateHotkey(8) end, | |
306 | - HOTKEY_9 = function() self.player:activateHotkey(9) end, | |
307 | - HOTKEY_10 = function() self.player:activateHotkey(10) end, | |
308 | - HOTKEY_11 = function() self.player:activateHotkey(11) end, | |
309 | - HOTKEY_12 = function() self.player:activateHotkey(12) end, | |
310 | - HOTKEY_SECOND_1 = function() self.player:activateHotkey(13) end, | |
311 | - HOTKEY_SECOND_2 = function() self.player:activateHotkey(14) end, | |
312 | - HOTKEY_SECOND_3 = function() self.player:activateHotkey(15) end, | |
313 | - HOTKEY_SECOND_4 = function() self.player:activateHotkey(16) end, | |
314 | - HOTKEY_SECOND_5 = function() self.player:activateHotkey(17) end, | |
315 | - HOTKEY_SECOND_6 = function() self.player:activateHotkey(18) end, | |
316 | - HOTKEY_SECOND_7 = function() self.player:activateHotkey(19) end, | |
317 | - HOTKEY_SECOND_8 = function() self.player:activateHotkey(20) end, | |
318 | - HOTKEY_SECOND_9 = function() self.player:activateHotkey(21) end, | |
319 | - HOTKEY_SECOND_10 = function() self.player:activateHotkey(22) end, | |
320 | - HOTKEY_SECOND_11 = function() self.player:activateHotkey(23) end, | |
321 | - HOTKEY_SECOND_12 = function() self.player:activateHotkey(24) end, | |
322 | - HOTKEY_THIRD_1 = function() self.player:activateHotkey(25) end, | |
323 | - HOTKEY_THIRD_2 = function() self.player:activateHotkey(26) end, | |
324 | - HOTKEY_THIRD_3 = function() self.player:activateHotkey(27) end, | |
325 | - HOTKEY_THIRD_4 = function() self.player:activateHotkey(28) end, | |
326 | - HOTKEY_THIRD_5 = function() self.player:activateHotkey(29) end, | |
327 | - HOTKEY_THIRD_6 = function() self.player:activateHotkey(30) end, | |
328 | - HOTKEY_THIRD_7 = function() self.player:activateHotkey(31) end, | |
329 | - HOTKEY_THIRD_8 = function() self.player:activateHotkey(31) end, | |
330 | - HOTKEY_THIRD_9 = function() self.player:activateHotkey(33) end, | |
331 | - HOTKEY_THIRD_10 = function() self.player:activateHotkey(34) end, | |
332 | - HOTKEY_THIRD_11 = function() self.player:activateHotkey(35) end, | |
333 | - HOTKEY_THIRD_12 = function() self.player:activateHotkey(36) end, | |
334 | - HOTKEY_PREV_PAGE = function() self.player:prevHotkeyPage() end, | |
335 | - HOTKEY_NEXT_PAGE = function() self.player:nextHotkeyPage() end, | |
336 | - | |
337 | - -- Actions | |
338 | - CHANGE_LEVEL = function() | |
339 | - local e = self.level.map(self.player.x, self.player.y, Map.TERRAIN) | |
340 | - if self.player:enoughEnergy() and e.change_level then | |
341 | - self:changeLevel(e.change_zone and e.change_level or self.level.level + e.change_level, e.change_zone) | |
342 | - else | |
343 | - self.log("There is no way out of this level here.") | |
344 | - end | |
345 | - end, | |
346 | - | |
347 | - REST = function() | |
348 | - self.player:restInit() | |
349 | - end, | |
350 | - | |
351 | - PICKUP_FLOOR = function() | |
352 | - self.player:playerPickup() | |
353 | - end, | |
354 | - DROP_FLOOR = function() | |
355 | - self.player:playerDrop() | |
356 | - end, | |
357 | - SHOW_INVENTORY = function() | |
358 | - local d | |
359 | - local titleupdator = self.player:getEncumberTitleUpdator("Inventory") | |
360 | - d = self.player:showEquipInven(titleupdator(), nil, function(o, inven, item, button, event) | |
361 | - if not o then return end | |
362 | - local ud = require("mod.dialogs.UseItemDialog").new(event == "button", self.player, o, item, inven, function(_, _, _, stop) | |
363 | - d:generateList() | |
364 | - d.title = titleupdator() | |
365 | - if stop then self:unregisterDialog(d) end | |
366 | - end) | |
367 | - self:registerDialog(ud) | |
368 | - end) | |
369 | - end, | |
370 | - SHOW_EQUIPMENT = "SHOW_INVENTORY", | |
371 | - WEAR_ITEM = function() | |
372 | - self.player:playerWear() | |
373 | - end, | |
374 | - TAKEOFF_ITEM = function() | |
375 | - self.player:playerTakeoff() | |
376 | - end, | |
377 | - USE_ITEM = function() | |
378 | - self.player:playerUseItem() | |
379 | - end, | |
380 | - | |
381 | - USE_TALENTS = function() | |
382 | - self.player:useTalents() | |
383 | - end, | |
384 | - | |
385 | - SAVE_GAME = function() | |
386 | - self:saveGame() | |
387 | - end, | |
388 | - | |
389 | - SHOW_CHARACTER_SHEET = function() | |
390 | - self:registerDialog(require("mod.dialogs.CharacterSheet").new(self.player)) | |
391 | - end, | |
392 | - | |
393 | - -- Exit the game | |
394 | - QUIT_GAME = function() | |
395 | - self:onQuit() | |
396 | - end, | |
397 | - | |
398 | - EXIT = function() | |
399 | - local menu menu = require("engine.dialogs.GameMenu").new{ | |
400 | - "resume", | |
401 | - "keybinds", | |
402 | - "video", | |
403 | - "save", | |
404 | - "quit" | |
405 | - } | |
406 | - self:registerDialog(menu) | |
407 | - end, | |
408 | - | |
409 | - -- Lua console, you probably want to disable it for releases | |
410 | - LUA_CONSOLE = function() | |
411 | - self:registerDialog(DebugConsole.new()) | |
412 | - end, | |
413 | - | |
414 | - -- Toggle monster list | |
415 | - TOGGLE_NPC_LIST = function() | |
416 | - self.show_npc_list = not self.show_npc_list | |
417 | - self.player.changed = true | |
418 | - end, | |
419 | - | |
420 | - TACTICAL_DISPLAY = function() | |
421 | - if Map.view_faction then | |
422 | - self.always_target = nil | |
423 | - Map:setViewerFaction(nil) | |
424 | - else | |
425 | - self.always_target = true | |
426 | - Map:setViewerFaction("players") | |
427 | - end | |
428 | - end, | |
429 | - | |
430 | - LOOK_AROUND = function() | |
431 | - self.flash:empty(true) | |
432 | - self.flash(self.flash.GOOD, "Looking around... (direction keys to select interresting things, shift+direction keys to move freely)") | |
433 | - local co = coroutine.create(function() self.player:getTarget{type="hit", no_restrict=true, range=2000} end) | |
434 | - local ok, err = coroutine.resume(co) | |
435 | - if not ok and err then print(debug.traceback(co)) error(err) end | |
436 | - end, | |
437 | - } | |
438 | - self.key:setCurrent() | |
439 | -end | |
440 | - | |
441 | -function _M:setupMouse(reset) | |
442 | - if reset then self.mouse:reset() end | |
443 | - self.mouse:registerZone(Map.display_x, Map.display_y, Map.viewport.width, Map.viewport.height, function(button, mx, my, xrel, yrel, bx, by, event) | |
444 | - -- Handle targeting | |
445 | - if self:targetMouse(button, mx, my, xrel, yrel, event) then return end | |
446 | - | |
447 | - -- Handle the mouse movement/scrolling | |
448 | - self.player:mouseHandleDefault(self.key, self.key == self.normal_key, button, mx, my, xrel, yrel, event) | |
449 | - end) | |
450 | - -- Scroll message log | |
451 | - self.mouse:registerZone(self.logdisplay.display_x, self.logdisplay.display_y, self.w, self.h, function(button) | |
452 | - if button == "wheelup" then self.logdisplay:scrollUp(1) end | |
453 | - if button == "wheeldown" then self.logdisplay:scrollUp(-1) end | |
454 | - end, {button=true}) | |
455 | - -- Tooltip over the player pane | |
456 | - self.mouse:registerZone(self.player_display.display_x, self.player_display.display_y, self.player_display.w, self.player_display.h, function(button, mx, my, xrel, yrel, bx, by, event) | |
457 | - self.player_display.mouse:delegate(button, mx, my, xrel, yrel, bx, by, event) | |
458 | - end) | |
459 | - -- Use hotkeys with mouse | |
460 | - self.mouse:registerZone(self.hotkeys_display.display_x, self.hotkeys_display.display_y, self.w, self.h, function(button, mx, my, xrel, yrel, bx, by, event) | |
461 | - self.hotkeys_display:onMouse(button, mx, my, event == "button", function(text) self.tooltip:displayAtMap(nil, nil, self.w, self.h, tostring(text)) end) | |
462 | - end) | |
463 | - self.mouse:setCurrent() | |
464 | -end | |
465 | - | |
466 | ---- Ask if we realy want to close, if so, save the game first | |
467 | -function _M:onQuit() | |
468 | - self.player:restStop() | |
469 | - | |
470 | - if not self.quit_dialog then | |
471 | - self.quit_dialog = QuitDialog.new() | |
472 | - self:registerDialog(self.quit_dialog) | |
473 | - end | |
474 | -end | |
475 | - | |
476 | ---- Requests the game to save | |
477 | -function _M:saveGame() | |
478 | - -- savefile_pipe is created as a global by the engine | |
479 | - savefile_pipe:push(self.save_name, "game", self) | |
480 | - self.log("Saving game...") | |
481 | -end | |
482 | - | |
483 | --------------------------------------------------------------- | |
484 | --- UI stuff | |
485 | --------------------------------------------------------------- | |
486 | - | |
487 | ---- Create a visual separator | |
488 | -local _sep_left = core.display.loadImage("/data/gfx/ui/separator-left.png") _sep_left:alpha() | |
489 | -local _sep_right = core.display.loadImage("/data/gfx/ui/separator-right.png") _sep_right:alpha() | |
490 | -local _sep_horiz = core.display.loadImage("/data/gfx/ui/separator-hori.png") _sep_horiz:alpha() | |
491 | -local _sep_top = core.display.loadImage("/data/gfx/ui/separator-top.png") _sep_top:alpha() | |
492 | -local _sep_bottom = core.display.loadImage("/data/gfx/ui/separator-bottom.png") _sep_bottom:alpha() | |
493 | -local _sep_vert = core.display.loadImage("/data/gfx/ui/separator-vert.png") _sep_vert:alpha() | |
494 | -function _M:createVisualSeparator(dir, size) | |
495 | - if dir == "horizontal" then | |
496 | - local sep = core.display.newSurface(size, 6) | |
497 | - sep:erase(0, 0, 0) | |
498 | - sep:merge(_sep_left, 0, 0) | |
499 | - for i = 7, size - 7, 9 do sep:merge(_sep_horiz, i, 0) end | |
500 | - sep:merge(_sep_right, size - 6, 0) | |
501 | - return sep:glTexture() | |
502 | - else | |
503 | - local sep = core.display.newSurface(6, size) | |
504 | - sep:erase(0, 0, 0) | |
505 | - sep:merge(_sep_top, 0, 0) | |
506 | - for i = 7, size - 7, 9 do sep:merge(_sep_vert, 0, i) end | |
507 | - sep:merge(_sep_bottom, 0, size - 6) | |
508 | - return sep:glTexture() | |
509 | - end |
game/modules/angband/class/Grid.lua
deleted
100644 → 0
1 | --- ToME - Tales of Middle-Earth | |
2 | --- Copyright (C) 2009, 2010, 2011 Nicolas Casalini | |
3 | --- | |
4 | --- This program is free software: you can redistribute it and/or modify | |
5 | --- it under the terms of the GNU General Public License as published by | |
6 | --- the Free Software Foundation, either version 3 of the License, or | |
7 | --- (at your option) any later version. | |
8 | --- | |
9 | --- This program is distributed in the hope that it will be useful, | |
10 | --- but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | --- GNU General Public License for more details. | |
13 | --- | |
14 | --- You should have received a copy of the GNU General Public License | |
15 | --- along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | --- | |
17 | --- Nicolas Casalini "DarkGod" | |
18 | --- darkgod@te4.org | |
19 | - | |
20 | -require "engine.class" | |
21 | -require "engine.Grid" | |
22 | -local DamageType = require "engine.DamageType" | |
23 | - | |
24 | -module(..., package.seeall, class.inherit(engine.Grid)) | |
25 | - | |
26 | -function _M:init(t, no_default) | |
27 | - engine.Grid.init(self, t, no_default) | |
28 | -end | |
29 | - | |
30 | -function _M:block_move(x, y, e, act, couldpass) | |
31 | - -- Open doors | |
32 | - if self.door_opened and act then | |
33 | - game.level.map(x, y, engine.Map.TERRAIN, game.zone.grid_list[self.door_opened]) | |
34 | - return true | |
35 | - elseif self.door_opened and not couldpass then | |
36 | - return true | |
37 | - end | |
38 | - | |
39 | - -- Pass walls | |
40 | - if e and self.can_pass and e.can_pass then | |
41 | - for what, check in pairs(e.can_pass) do | |
42 | - if self.can_pass[what] and self.can_pass[what] <= check then return false end | |
43 | - end | |
44 | - end | |
45 | - | |
46 | - return self.does_block_move | |
47 | -end | |
48 | - | |
49 | -function _M:on_move(x, y, who, forced) | |
50 | - if forced then return end | |
51 | - if who.move_project and next(who.move_project) then | |
52 | - for typ, dam in pairs(who.move_project) do | |
53 | - DamageType:get(typ).projector(who, x, y, typ, dam) | |
54 | - end | |
55 | - end | |
56 | -end | |
57 | -function _M:tooltip() | |
58 | - if self.show_tooltip then | |
59 | - local name = ((self.show_tooltip == true) and self.name or self.show_tooltip) | |
60 | - if self.desc then | |
61 | - return self:getDisplayString()..name.."\n"..self.desc | |
62 | - else | |
63 | - return self:getDisplayString()..name | |
64 | - end | |
65 | - else | |
66 | - return self:getDisplayString()..self.name | |
67 | - end |
game/modules/angband/class/NPC.lua
deleted
100644 → 0
1 | --- ToME - Tales of Middle-Earth | |
2 | --- Copyright (C) 2009, 2010, 2011 Nicolas Casalini | |
3 | --- | |
4 | --- This program is free software: you can redistribute it and/or modify | |
5 | --- it under the terms of the GNU General Public License as published by | |
6 | --- the Free Software Foundation, either version 3 of the License, or | |
7 | --- (at your option) any later version. | |
8 | --- | |
9 | --- This program is distributed in the hope that it will be useful, | |
10 | --- but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | --- GNU General Public License for more details. | |
13 | --- | |
14 | --- You should have received a copy of the GNU General Public License | |
15 | --- along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | --- | |
17 | --- Nicolas Casalini "DarkGod" | |
18 | --- darkgod@te4.org | |
19 | - | |
20 | -require "engine.class" | |
21 | -local ActorAI = require "engine.interface.ActorAI" | |
22 | -local MonsterCombat = require "mod.class.interface.MonsterCombat" | |
23 | -local Faction = require "engine.Faction" | |
24 | -require "mod.class.Actor" | |
25 | - | |
26 | -module(..., package.seeall, class.inherit(mod.class.Actor, engine.interface.ActorAI, MonsterCombat)) | |
27 | - | |
28 | -function _M:init(t, no_default) | |
29 | - mod.class.Actor.init(self, t, no_default) | |
30 | - ActorAI.init(self, t) | |
31 | -end | |
32 | - | |
33 | -function _M:act() | |
34 | - -- Do basic actor stuff | |
35 | - if not mod.class.Actor.act(self) then return end | |
36 | - | |
37 | - -- Compute FOV, if needed | |
38 | - self:computeFOV(self.sight or 20) | |
39 | - | |
40 | - -- Let the AI think .... beware of Shub ! | |
41 | - -- If AI did nothing, use energy anyway | |
42 | - self:doAI() | |
43 | - if not self.energy.used then self:useEnergy() end | |
44 | -end | |
45 | - | |
46 | ---- Called by ActorLife interface | |
47 | --- We use it to pass aggression values to the AIs | |
48 | -function _M:onTakeHit(value, src) | |
49 | - if not self.ai_target.actor and src.targetable then | |
50 | - self.ai_target.actor = src | |
51 | - end | |
52 | - | |
53 | - return mod.class.Actor.onTakeHit(self, value, src) | |
54 | -end | |
55 | - | |
56 | -function _M:tooltip() | |
57 | - local str = mod.class.Actor.tooltip(self) | |
58 | - return str..([[ | |
59 | - | |
60 | -Target: %s | |
61 | -UID: %d]]):format( | |
62 | - self.ai_target.actor and self.ai_target.actor.name or "none", | |
63 | - self.uid) |
1 | --- ToME - Tales of Maj'Eyal | |
2 | --- Copyright (C) 2009, 2010, 2011 Nicolas Casalini | |
3 | --- | |
4 | --- This program is free software: you can redistribute it and/or modify | |
5 | --- it under the terms of the GNU General Public License as published by | |
6 | --- the Free Software Foundation, either version 3 of the License, or | |
7 | --- (at your option) any later version. | |
8 | --- | |
9 | --- This program is distributed in the hope that it will be useful, | |
10 | --- but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | --- GNU General Public License for more details. | |
13 | --- | |
14 | --- You should have received a copy of the GNU General Public License | |
15 | --- along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | --- | |
17 | --- Nicolas Casalini "DarkGod" | |
18 | --- darkgod@te4.org | |
19 | - | |
20 | -require "engine.class" | |
21 | -require "engine.Object" | |
22 | -require "engine.interface.ObjectActivable" | |
23 | -require "engine.interface.ObjectIdentify" | |
24 | - | |
25 | -local Stats = require("engine.interface.ActorStats") | |
26 | -local Talents = require("engine.interface.ActorTalents") | |
27 | -local DamageType = require("engine.DamageType") | |
28 | - | |
29 | -module(..., package.seeall, class.inherit( | |
30 | - engine.Object, | |
31 | - engine.interface.ObjectActivable, | |
32 | - engine.interface.ObjectIdentify, | |
33 | - engine.interface.ActorTalents | |
34 | -)) | |
35 | - | |
36 | -_M._noalpha = true | |
37 | - | |
38 | -function _M:init(t, no_default) | |
39 | - t.encumber = t.encumber or 0 | |
40 | - | |
41 | - engine.Object.init(self, t, no_default) | |
42 | - engine.interface.ObjectActivable.init(self, t) | |
43 | - engine.interface.ObjectIdentify.init(self, t) | |
44 | - engine.interface.ActorTalents.init(self, t) | |
45 | -end | |
46 | - | |
47 | ---- Can this object act at all | |
48 | --- Most object will want to anwser false, only recharging and stuff needs them | |
49 | -function _M:canAct() | |
50 | - if self.power_regen or self.use_talent then return true end | |
51 | - return false | |
52 | -end | |
53 | - | |
54 | ---- Do something when its your turn | |
55 | --- For objects this mostly is to recharge them | |
56 | --- By default, does nothing at all | |
57 | -function _M:act() | |
58 | - self:regenPower() | |
59 | - self:cooldownTalents() | |
60 | - self:useEnergy() | |
61 | -end | |
62 | - | |
63 | ---- Use the object (quaff, read, ...) | |
64 | -function _M:use(who, typ, inven, item) | |
65 | - inven = who:getInven(inven) | |
66 | - | |
67 | - if self.use_no_blind and who:attr("blind") then | |
68 | - game.logPlayer(who, "You cannot see!") | |
69 | - return | |
70 | - end | |
71 | - if self.use_no_silence and who:attr("silence") then | |
72 | - game.logPlayer(who, "You are silenced!") | |
73 | - return | |
74 | - end | |
75 | - if self:wornInven() and not self.wielded and not self.use_no_wear then | |
76 | - game.logPlayer(who, "You must wear this object to use it!") | |
77 | - return | |
78 | - end | |
79 | - if who:hasEffect(self.EFF_UNSTOPPABLE) then | |
80 | - game.logPlayer(who, "You can not use items during a battle frenzy!") | |
81 | - return | |
82 | - end | |
83 | - | |
84 | - local types = {} | |
85 | - if self:canUseObject() then types[#types+1] = "use" end | |
86 | - | |
87 | - if not typ and #types == 1 then typ = types[1] end | |
88 | - | |
89 | - if typ == "use" then | |
90 | - who:useEnergy(game.energy_to_act * (inven.use_speed or 1)) | |
91 | - if self.use_sound then game:playSoundNear(who, self.use_sound) end | |
92 | - return self:useObject(who, inven, item) | |
93 | - end | |
94 | -end | |
95 | - | |
96 | ---- Returns a tooltip for the object | |
97 | -function _M:tooltip() | |
98 | - return tostring(self:getDesc{do_color=true}) | |
99 | -end | |
100 | - | |
101 | ---- Describes an attribute, to expand object name | |
102 | -function _M:descAttribute(attr) | |
103 | - if attr == "MASTERY" then | |
104 | - local tms = {} | |
105 | - for ttn, i in pairs(self.wielder.talents_types_mastery) do | |
106 | - local tt = Talents.talents_types_def[ttn] | |
107 | - local cat = tt.type:gsub("/.*", "") | |
108 | - local name = cat:capitalize().." / "..tt.name:capitalize() | |
109 | - tms[#tms+1] = ("%0.2f %s"):format(i, name) | |
110 | - end | |
111 | - return table.concat(tms, ",") | |
112 | - elseif attr == "STATBONUS" then | |
113 | - local stat, i = next(self.wielder.inc_stats) | |
114 | - return i > 0 and "+"..i or tostring(i) | |
115 | - elseif attr == "DAMBONUS" then | |
116 | - local stat, i = next(self.wielder.inc_damage) | |
117 | - return (i > 0 and "+"..i or tostring(i)).."%" | |
118 | - elseif attr == "RESIST" then | |
119 | - local stat, i = next(self.wielder.resists) | |
120 | - return (i > 0 and "+"..i or tostring(i)).."%" | |
121 | - elseif attr == "REGEN" then | |
122 | - local i = self.wielder.mana_regen or self.wielder.stamina_regen or self.wielder.life_regen | |
123 | - return ("%s%0.2f/turn"):format(i > 0 and "+" or "-", math.abs(i)) | |
124 | - elseif attr == "COMBAT" then | |
125 | - local c = self.combat | |
126 | - return c.dam.."-"..(c.dam*(c.damrange or 1.1)).." power, "..(c.apr or 0).." apr" | |
127 | - elseif attr == "COMBAT_DAMTYPE" then | |
128 | - local c = self.combat | |
129 | - return c.dam.."-"..(c.dam*(c.damrange or 1.1)).." power, "..(c.apr or 0).." apr, "..DamageType:get(c.damtype).name.." damage" | |
130 | - elseif attr == "ARMOR" then | |
131 | - return (self.wielder and self.wielder.combat_def or 0).." def, "..(self.wielder and self.wielder.combat_armor or 0).." armor" | |
132 | - elseif attr == "ATTACK" then | |
133 | - return (self.wielder and self.wielder.combat_atk or 0).." attack, "..(self.wielder and self.wielder.combat_apr or 0).." apr, "..(self.wielder and self.wielder.combat_dam or 0).." power" | |
134 | - elseif attr == "MONEY" then | |
135 | - return ("worth %0.2f"):format(self.money_value / 10) | |
136 | - elseif attr == "USE_TALENT" then | |
137 | - return self:getTalentFromId(self.use_talent.id).name:lower() | |
138 | - elseif attr == "DIGSPEED" then | |
139 | - return ("dig speed %d turns"):format(self.digspeed) | |
140 | - elseif attr == "CHARGES" then | |
141 | - if self.use_power then | |
142 | - return (" (%d/%d)"):format(math.floor(self.power / self.use_power.power), math.floor(self.max_power / self.use_power.power)) | |
143 | - else | |
144 | - return "" | |
145 | - end | |
146 | - end | |
147 | -end | |
148 | - | |
149 | ---- Gets the "power rank" of an object | |
150 | --- Possible values are 0 (normal, lore), 1 (ego), 2 (greater ego), 3 (artifact) | |
151 | -function _M:getPowerRank() | |
152 | - if self.unique then return 2 end | |
153 | - if self.egoed then return 1 end | |
154 | - return 0 | |
155 | -end | |
156 | - | |
157 | ---- Gets the color in which to display the object in lists | |
158 | -function _M:getDisplayColor() | |
159 | - if not self:isIdentified() then return {180, 180, 180}, "#B4B4B4#" end | |
160 | - if self.egoed then | |
161 | - return {0, 255, 128}, "#00FF80#" | |
162 | - elseif self.unique then | |
163 | - return {255, 215, 0}, "#FFD700#" | |
164 | - else return {255, 255, 255}, "#FFFFFF#" | |
165 | - end | |
166 | -end | |
167 | - | |
168 | -_M.tval_table = { | |
169 | - [1] = {"skeleton"}, | |
170 | - [2] = {"bottle"}, | |
171 | - [3] = {"junk"}, | |
172 | - [5] = {"spike"}, | |
173 | - [7] = {"chest"}, | |
174 | - [16] = {"shot", slot="QUIVER", show_weapon=true}, | |
175 | - [17] = {"arrow", slot="QUIVER", show_weapon=true}, | |
176 | - [18] = {"bolt", slot="QUIVER", show_weapon=true}, | |
177 | - [19] = {"bow", slot="SHOOTER"}, | |
178 | - [20] = {"digging"}, | |
179 | - [21] = {"hafted", slot="WEAPON", show_weapon=true}, | |
180 | - [22] = {"polearm", slot="WEAPON", show_weapon=true}, | |
181 | - [23] = {"sword", slot="WEAPON", show_weapon=true}, | |
182 | - [30] = {"boots", slot="FEET"}, | |
183 | - [31] = {"gloves", slot="HANDS"}, | |
184 | - [32] = {"helm", slot="HEAD"}, | |
185 | - [33] = {"crown", slot="HEAD"}, | |
186 | - [34] = {"shield", slot="SHIELD"}, | |
187 | - [35] = {"cloak", slot="CLOAK"}, | |
188 | - [36] = {"soft armor", slot="BODY"}, | |
189 | - [37] = {"hard armor", slot="BODY"}, | |
190 | - [38] = {"drag armor", slot="BODY"}, | |
191 | - [39] = {"light", slot="LITE", wielder={lite=2}}, | |
192 | - [40] = {"amulet", slot="NECK", name_gen=function(e) return "& Amulet~ of "..e.name end}, | |
193 | - [45] = {"ring", slot="FINGER", name_gen=function(e) return "& Ring~ of "..e.name end}, | |
194 | - [55] = {"staff", name_gen=function(e) return "& Staff~ of "..e.name end}, | |
195 | - [65] = {"wand", name_gen=function(e) return "& Wand~ of "..e.name end}, | |
196 | - [66] = {"rod", name_gen=function(e) return "& Rod~ of "..e.name end}, | |
197 | - [70] = {"scroll", name_gen=function(e) return "& Scroll~ of "..e.name end}, | |
198 | - [75] = {"potion", random_color=true, name_gen=function(e) return "& Potion~ of "..e.name end}, | |
199 | - [77] = {"flask"}, | |
200 | - [80] = {"food", random_color=true}, | |
201 | - [90] = {"magic book", name_gen=function(e) return "& Magic Book~ ["..e.name.."]" end}, | |
202 | - [91] = {"prayer book", name_gen=function(e) return "& Prayer Book~ ["..e.name.."]" end}, | |
203 | - [100] = {"gold"}, | |
204 | -} | |
205 | - | |
206 | ---- Gets the full name of the object | |
207 | -function _M:getName(t) | |
208 | - t = t or {} | |
209 | - local qty = self:getNumber() | |
210 | - local name = self.name | |
211 | - | |
212 | - if not self:isIdentified() and not t.force_id and self:getUnidentifiedName() then name = self:getUnidentifiedName() end | |
213 | - | |
214 | - -- To extend later | |
215 | - name = name:gsub("~", ""):gsub("&", "a"):gsub("#([^#]+)#", function(attr) | |
216 | - return self:descAttribute(attr) | |
217 | - end) | |
218 | - | |
219 | - if not t.no_add_name and self.add_name and self:isIdentified() then | |
220 | - name = name .. self.add_name:gsub("#([^#]+)#", function(attr) | |
221 | - return self:descAttribute(attr) | |
222 | - end) | |
223 | - end | |
224 | - | |
225 | - local tval = self.tval_table[self.tval] or {"misc"} | |
226 | - if tval.show_weapon and self.damage then | |
227 | - name = name.." ("..self.damage[1].."d"..self.damage[2]..")" | |
228 | - end | |
229 |