diff options
author | Erik Schilling <ablu.erikschilling@googlemail.com> | 2013-05-05 10:35:36 +0200 |
---|---|---|
committer | Erik Schilling <ablu.erikschilling@googlemail.com> | 2013-05-12 09:58:12 +0200 |
commit | 323b14db576e9fec6f714f907aec07264a47d57a (patch) | |
tree | 72b9bffe52b7ae5b249bc348730fa81740bd8bc4 | |
parent | d64e1c6d41362c5305a1b5f06fc34d9794f82a88 (diff) | |
download | manaserv-323b14db576e9fec6f714f907aec07264a47d57a.tar.gz manaserv-323b14db576e9fec6f714f907aec07264a47d57a.tar.xz manaserv-323b14db576e9fec6f714f907aec07264a47d57a.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.
-rw-r--r-- | example/abilities.xml | 11 | ||||
-rw-r--r-- | example/attributes.xml | 11 | ||||
-rw-r--r-- | example/monsters.xml | 3 | ||||
-rw-r--r-- | example/scripts/main.lua | 2 | ||||
-rw-r--r-- | example/scripts/monster/basic_ai.lua | 141 | ||||
-rw-r--r-- | example/scripts/monster/settings.lua | 28 |
6 files changed, 168 insertions, 28 deletions
diff --git a/example/abilities.xml b/example/abilities.xml index 0cbcd23..5b8a380 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 425dd96..0ab2626 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="Monster attack damage" + desc="damage the monster deals per hit" + modifiable="false" + scope="monster" + minimum="0" /> </attributes> diff --git a/example/monsters.xml b/example/monsters.xml index 0a4e779..6881c65 100644 --- a/example/monsters.xml +++ b/example/monsters.xml @@ -111,6 +111,9 @@ exp<TAG>: Tells how much experience point a monster is giving up magical-defence="0" gender="female" /> + <attribute id="21" value="10" /> + <attribute id="22" value="10" /> + <ability id="2" /> </monster> <monster id="4" name="Green Slime"> diff --git a/example/scripts/main.lua b/example/scripts/main.lua index 7093f11..8a4c8af 100644 --- a/example/scripts/main.lua +++ b/example/scripts/main.lua @@ -12,6 +12,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 9c35f42..40fa851 100644 --- a/example/scripts/monster/basic_ai.lua +++ b/example/scripts/monster/basic_ai.lua @@ -7,6 +7,8 @@ local STROLL_TIMEOUT = 20 local STROLL_TIMEOUT_RANDOMNESS = 10 +local TARGET_SEARCH_DELAY = 10 + -- Wrapping the monster update callback in order to do the stroll ai here local old_on_update = MonsterClass.on_update local update_functions = {} @@ -14,18 +16,38 @@ function MonsterClass:on_update(callback) update_functions[self] = callback end -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,55 +57,98 @@ 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 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 + + -- Call other update functions local monsterclass = get_monster_class(mob:monster_id()) local update_function = update_functions[monsterclass] if update_function then @@ -91,7 +156,27 @@ local function stroll_update(mob, tick) 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_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 + +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 + old_on_update(monsterclass, update) end diff --git a/example/scripts/monster/settings.lua b/example/scripts/monster/settings.lua new file mode 100644 index 0000000..b095a2d --- /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, + }, +} |