diff options
author | Erik Schilling <ablu.erikschilling@googlemail.com> | 2013-05-05 10:35:36 +0200 |
---|---|---|
committer | Erik Schilling <ablu.erikschilling@googlemail.com> | 2013-08-26 22:56:47 +0200 |
commit | 9314e60fc37d4940d80a4c110ead5c0b8c324947 (patch) | |
tree | d0573aacf448d6eafc95080661955c5749be6f78 /example | |
parent | c3506577da37bb25cbb42bd534e74b05910d1580 (diff) | |
download | manaserv-9314e60fc37d4940d80a4c110ead5c0b8c324947.tar.gz manaserv-9314e60fc37d4940d80a4c110ead5c0b8c324947.tar.bz2 manaserv-9314e60fc37d4940d80a4c110ead5c0b8c324947.tar.xz manaserv-9314e60fc37d4940d80a4c110ead5c0b8c324947.zip |
Added a first very basic monster ai version
The ai is similar to the old c++ version. Only the target searching is
executed every 10 ticks only now to prevent performance issues with too
many lua calls.
Diffstat (limited to 'example')
-rw-r--r-- | example/abilities.xml | 11 | ||||
-rw-r--r-- | example/attributes.xml | 11 | ||||
-rw-r--r-- | example/monsters.xml | 2 | ||||
-rw-r--r-- | example/scripts/callbacks.lua | 24 | ||||
-rw-r--r-- | example/scripts/main.lua | 5 | ||||
-rw-r--r-- | example/scripts/monster/basic_ai.lua | 148 | ||||
-rw-r--r-- | example/scripts/monster/settings.lua | 28 |
7 files changed, 191 insertions, 38 deletions
diff --git a/example/abilities.xml b/example/abilities.xml index 0cbcd23c..5b8a3806 100644 --- a/example/abilities.xml +++ b/example/abilities.xml @@ -12,4 +12,15 @@ useaction="attack" /> </ability-category> + <ability-category name="Monster attack"> + <ability + id="2" + name="Basic Monster strike" + rechargeable="true" + needed="100" + rechargeattribute="21" + target="being" + useaction="attack" + /> + </ability-category> </abilities> diff --git a/example/attributes.xml b/example/attributes.xml index 425dd961..fd91b066 100644 --- a/example/attributes.xml +++ b/example/attributes.xml @@ -179,4 +179,15 @@ minimum="0" maximum="100" /> <!-- End of core-attributes definition --> + <attribute id="21" name="Monster attack speed" + desc="Attackspeed of the monster. 0 = no attacks, 100 = one per tick, 10 = one per second" + modifiable="false" + scope="monster" + minimum="0" + maximum="100" /> + <attribute id="22" name="XP" + desc="The experience of this character." + modifiable="false" + scope="character" + minimum="0" /> </attributes> diff --git a/example/monsters.xml b/example/monsters.xml index 0a4e779e..6ae92451 100644 --- a/example/monsters.xml +++ b/example/monsters.xml @@ -111,6 +111,8 @@ exp<TAG>: Tells how much experience point a monster is giving up magical-defence="0" gender="female" /> + <attribute id="21" value="10" /> + <ability id="2" /> </monster> <monster id="4" name="Green Slime"> diff --git a/example/scripts/callbacks.lua b/example/scripts/callbacks.lua new file mode 100644 index 00000000..af27e1a5 --- /dev/null +++ b/example/scripts/callbacks.lua @@ -0,0 +1,24 @@ +--[[
+
+ Allows to assign multiple functions to some callbacks
+
+--]]
+
+local monsterclass_update_old_callback = MonsterClass.on_update
+local monsterclass_update_callbacks = {}
+
+local function on_monsterclass_update(monsterclass, entity, tick)
+ for _, func in ipairs(monsterclass_update_callbacks[monsterclass]) do
+ func(entity, tick)
+ end
+end
+
+function MonsterClass:on_update(func)
+ if not monsterclass_update_callbacks[self] then
+ monsterclass_update_old_callback(self, function(entity, tick)
+ on_monsterclass_update(self, entity, tick)
+ end)
+ monsterclass_update_callbacks[self] = {}
+ end
+ table.insert(monsterclass_update_callbacks[self], func)
+end
diff --git a/example/scripts/main.lua b/example/scripts/main.lua index 7093f112..cb657510 100644 --- a/example/scripts/main.lua +++ b/example/scripts/main.lua @@ -5,6 +5,9 @@ --]] +-- Global functions: +require "scripts/callbacks" + -- At the moment the event handlers are split up over the following files: require "scripts/global_events" require "scripts/abilities" @@ -12,6 +15,8 @@ require "scripts/crafting" require "scripts/attributes" require "scripts/items/candy" + +require "scripts/monster/basic_ai" require "scripts/monster/testmonster" require "scripts/status/jump" diff --git a/example/scripts/monster/basic_ai.lua b/example/scripts/monster/basic_ai.lua index 9c35f42c..385099cc 100644 --- a/example/scripts/monster/basic_ai.lua +++ b/example/scripts/monster/basic_ai.lua @@ -7,25 +7,40 @@ local STROLL_TIMEOUT = 20 local STROLL_TIMEOUT_RANDOMNESS = 10 --- Wrapping the monster update callback in order to do the stroll ai here -local old_on_update = MonsterClass.on_update -local update_functions = {} -function MonsterClass:on_update(callback) - update_functions[self] = callback -end +local TARGET_SEARCH_DELAY = 10 -local stroll_timer = {} +local mob_stati = {} local angerlist = {} local mob_config = require "scripts/monster/settings" -local function find_target(mob, config) +local function calculate_position_priority(x1, y1, x2, y2, anger, range) + if math.floor(x1 / TILESIZE) == math.floor(x2 / TILESIZE) and + math.floor(y1 / TILESIZE) == math.floor(y2 / TILESIZE) + then + -- Both on the same tile + return anger * range + end + + local path_length = get_path_length(x1, y1, x2, y2, range, "w") + return (range - path_length) * anger +end + +local function update_attack_ai(mob, tick) + local config = mob_config[mob:name()] + local target local target_priority local attack_x, attack_y + local mob_status = mob_stati[mob] + local timer = mob_status.update_target_timer + if timer and timer > tick then + return false + end + for _, being in ipairs(get_beings_in_circle(mob, config.trackrange)) do - if being:type() == OBJECT_CHARACTER + if being:type() == TYPE_CHARACTER and being:action() ~= ACTION_DEAD then local anger = angerlist[being] or 0 @@ -35,63 +50,120 @@ local function find_target(mob, config) local possible_attack_positions = { { - x = being:x() - config.attack_distance or TILESIZE, - y = being:y() + x = being:x() - config.attack_distance, + y = being:y(), }, { - - x = being:x() - y = being:y() - config.attack_distance or TILESIZE, + x = being:x(), + y = being:y() - config.attack_distance, }, { - - x = being:x() + config.attack_distance or TILESIZE, + x = being:x() + config.attack_distance, y = being:y(), }, { - - x = being:x() - y = being:y() + config.attack_distance or TILESIZE, + x = being:x(), + y = being:y() + config.attack_distance, }, } for _, point in ipairs(possible_attack_positions) do - local priority = calculate_position_priority(mob:position(), point.x, point.y) + local priority = calculate_position_priority(mob:x(), + mob:y(), + point.x, + point.y, + anger, + config.trackrange) + + if priority > 0 and (not target or priority > target_priority) + then + target = being + target_priority = priority + attack_x, attack_y = point.x, point.y + end end - - - end end -end -local function stroll_update(mob, tick) - local stroll_tick = stroll_timer[mob] - local mobconfig = mob_config[mob:name()] + mob_status.update_target_timer = tick + TARGET_SEARCH_DELAY + if not target then + return false + end - local trackrange = mobconfig and mobconfig.trackrange or nil + local x, y = mob:position() + if x == attack_x and y == attack_y then + mob:use_ability(config.ability_id, target) + else + mob:walk(attack_x, attack_y) + end + return true +end + +local function update_stroll_timer(mob_status, tick) + + mob_status.stroll_timer = tick + STROLL_TIMEOUT + + math.random(STROLL_TIMEOUT_RANDOMNESS) +end +local function update_stroll(mob, tick) + local mobconfig = mob_config[mob:name()] + local mob_status = mob_stati[mob] local strollrange = mobconfig and mobconfig.strollrange or nil - if (not stroll_tick or stroll_tick <= tick) and strollrange then + if (not mob_status.stroll_timer or mob_status.stroll_timer <= tick) and + strollrange + then local x, y = mob:position() local destination_x = math.random(x - strollrange, x + strollrange) local destination_y = math.random(y - strollrange, y + strollrange) if is_walkable(destination_x, destination_y) then mob:walk(destination_x, destination_y) end - stroll_timer[mob] = tick + STROLL_TIMEOUT - + math.random(STROLL_TIMEOUT_RANDOMNESS) + update_stroll_timer(mob_status, tick) + end +end + +local function remove_mob(mob) + mob_stati[mob] = nil +end + +local function update(mob, tick) + local mob_status = mob_stati[mob] + if not mob_status then + mob_status = {} + mob_stati[mob] = mob_status + on_remove(mob, remove_mob) + end + + local stop_stroll = update_attack_ai(mob, tick) + if stop_stroll then + update_stroll_timer(mob_status, tick) + else + update_stroll(mob, tick) end +end - local monsterclass = get_monster_class(mob:monster_id()) - local update_function = update_functions[monsterclass] - if update_function then - return update_function(mob, tick) +local function mob_attack(mob, target, ability_id) + local hp = target:base_attribute(ATTR_HP) + local config = mob_config[mob:name()] + local dealt_damage = math.min(hp, config.damage) + if dealt_damage > 0 then + local v = hp - dealt_damage + target:set_base_attribute(ATTR_HP, hp - dealt_damage) + target:add_hit_taken(dealt_damage) end end --- Register all update functions for strolling -for _, monsterclass in ipairs(get_monster_classes()) do - old_on_update(monsterclass, stroll_update) +local function mob_recharged(mob, ability_id) + mob_stati[mob].update_target_timer = 0 -- Enforce looking for new target +end + +local mob_attack_ability = + get_ability_info("Monster attack_Basic Monster strike") +mob_attack_ability:on_use(mob_attack) +mob_attack_ability:on_recharged(mob_recharged) + +-- Register all update functions for the ai +for _, monsterclass in pairs(get_monster_classes()) do + monsterclass:on_update(update) end diff --git a/example/scripts/monster/settings.lua b/example/scripts/monster/settings.lua new file mode 100644 index 00000000..b095a2d7 --- /dev/null +++ b/example/scripts/monster/settings.lua @@ -0,0 +1,28 @@ +return { + ["Maggot"] = { + strollrange = TILESIZE, + aggressive = false, + trackrange = 5 * TILESIZE, + attack_distance = TILESIZE, + }, + ["Scorpion"] = { + strollrange = 2 * TILESIZE, + aggressive = false, + trackrange = 5 * TILESIZE, + attack_distance = TILESIZE, + }, + ["Red Scorpion"] = { + strollrange = TILESIZE, + aggressive = true, + trackrange = 5 * TILESIZE, + attack_distance = TILESIZE, + ability_id = 2, + damage = 1, + }, + ["Green Slime"] = { + strollrange = TILESIZE, + aggressive = true, + trackrange = 5 * TILESIZE, + attack_distance = TILESIZE, + }, +} |