summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErik Schilling <ablu.erikschilling@googlemail.com>2013-05-05 10:35:36 +0200
committerErik Schilling <ablu.erikschilling@googlemail.com>2013-05-12 09:58:12 +0200
commit323b14db576e9fec6f714f907aec07264a47d57a (patch)
tree72b9bffe52b7ae5b249bc348730fa81740bd8bc4
parentd64e1c6d41362c5305a1b5f06fc34d9794f82a88 (diff)
downloadmanaserv-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.xml11
-rw-r--r--example/attributes.xml11
-rw-r--r--example/monsters.xml3
-rw-r--r--example/scripts/main.lua2
-rw-r--r--example/scripts/monster/basic_ai.lua141
-rw-r--r--example/scripts/monster/settings.lua28
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,
+ },
+}