123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- local modpath = minetest.get_modpath("markov_macaws")
- local settings = Settings(modpath .. "/markov_macaws.conf")
- local S = minetest.get_translator("markov_macaws")
- local function parse_num(str)
- return 0 + str
- end
- local HEAR_DISTANCE = parse_num(settings:get("hear_distance"))
- local PARROT_TALK_CHANCE = parse_num(settings:get("talk_chance"))
- local PARROT_TALK_CHANCE_FRIEND = parse_num(settings:get("talk_chance_friend"))
- local function get_players_inside_radius(pos, radius)
- local inrad = {}
-
- local connected = minetest.get_connected_players()
- for i, player in ipairs(connected)
- do
- local ppos = player:get_pos()
- if vector.distance(pos, ppos) < radius
- then
- table.insert(inrad, player)
- end
- end
- return inrad
- end
- local prefix = "<" .. S("Parrot") .. "> "
- local function set_nametag(self, str)
- local objprops = self.object:get_properties()
- objprops.nametag = str
- self.object:set_properties(objprops)
- end
- local function talk(self)
- end
- local function sign(x)
- return x < 0 and -1 or (x == 0 and 0 or 1)
- end
- local function lq_emote(self)
- local start_time = 0
- local func = function(self)
- start_time = start_time + self.dtime
- mobkit.animate(self, "emote")
- if start_time > 0.5
- then
- return true
- end
- end
- mobkit.queue_low(self, func)
- end
- local function hq_interact_with_friend(self, prty, friend)
- local friend_yvel_history = {}
- local hpointer = 0
- local track_count = 4
- local iterations = 0
-
- local hopping = false
-
- --if close, watch friend
- local func = function(self)
- --track player
- if mobkit.timer(self, 0.1)
- then
- iterations = iterations + 1
- hpointer = (hpointer + 1) % track_count
- friend_yvel_history[hpointer + 1] = sign(friend:get_player_velocity().y)
- hopping = false
- for i = 1, track_count
- do
- local index1 = (hpointer + i) % track_count + 1
- local index2 = (hpointer + i - 1) % track_count + 1
- local vel1 = friend_yvel_history[index1]
- local vel2 = friend_yvel_history[index2]
-
- hopping = hopping or
- (vel1 ~= vel2 and
- vel1 ~= 0 and
- vel2 ~= 0)
- end
- end
- --animate if player is hopping
- if mobkit.is_queue_empty_low(self) and self.isonground
- then
- if hopping
- then
- lq_emote(self)
- else
- mobkit.lq_idle(self, 0.5)
-
- if math.random() < 0.1 and iterations > track_count
- then
- return true
- end
- end
- end
- end
- mobkit.queue_high(self, func, prty)
- end
- --TODO: use low level queue properly
- local function choose_action(self)
- local pos = self.object:get_pos()
- local in_rad = get_players_inside_radius(pos, HEAR_DISTANCE)
-
- local fav = nil
- local fav_rel = -math.huge
- for i, player in ipairs(in_rad)
- do
- local name = player:get_player_name()
-
- if self.player_relations[name] > fav_rel
- then
- fav_rel = self.player_relations[name]
- fav = player
- end
- end
- if fav
- then
- local favpos = fav:get_pos()
- --run if best player is bad and close
- local dist = vector.distance(favpos, pos)
- if fav_rel / dist < -0.5
- then
- mobkit.hq_runfrom(self, 20, fav)
- return true
- end
- if fav_rel > 7
- then
- if dist > 5
- then
- mobkit.hq_goto(self, 10, favpos)
- else
- if math.random(2) < 1
- then
- mobkit.hq_roam(self,0)
- else
- hq_interact_with_friend(self, 10, fav)
- end
- end
- return true, true
- end
- end
- end
- local function lq_make_sound(self, sound)
- local timer = 0
- mobkit.make_sound(self, sound)
-
- local func = function()
- timer = timer + self.dtime
- if timer > 0.5
- then
- return true
- end
- end
- mobkit.queue_low(self, func)
- end
- local function lq_talk(self)
- local sentence = self.talker:get_sentence()
-
- --if the parrot knows no words it doesn't talk
- if sentence == ""
- then
- return
- end
-
- set_nametag(self, sentence)
-
- --add '<Parrot>' in front of sentence
- sentence = minetest.colorize(self.color, prefix) .. sentence
- local pos = self.object:get_pos()
-
-
- mobkit.make_sound(self, "talk")
- --send chat message to nearby players
- for i, p in ipairs(get_players_inside_radius(pos, HEAR_DISTANCE))
- do
- local name = p:get_player_name()
- minetest.chat_send_player(name, sentence)
- end
-
- --make nametag disappear again
- local timer = 0
- local func = function()
- timer = timer + self.dtime
- if timer > 1
- then
- set_nametag(self, "")
- return true
- end
- end
- mobkit.queue_low(self, func)
- end
- local function parrot_brain(self)
- if self.hp <= 0
- then
- mobkit.clear_queue_high(self)
- mobkit.hq_die(self)
- return
- end
-
- if mobkit.timer(self,1)
- then
- local prty = mobkit.get_queue_priority(self)
-
-
- local talk_chance = PARROT_TALK_CHANCE
-
- --interact with player
- local chose_action, friend
- if prty < 10
- then
- chose_action, friend = choose_action(self)
- end
- if friend
- then
- --talk chance is increased if a friend is nearby
- talk_chance = PARROT_TALK_CHANCE_FRIEND
- end
- if math.random(100) < talk_chance
- then
- lq_talk(self)
- elseif math.random(100) < talk_chance
- then
- lq_make_sound(self, "playful")
- end
-
- if chose_action
- then
- return
- end
-
-
- if prty < 20 and self.isinliquid then
- mobkit.hq_liquid_recovery(self, 20)
- return
- end
-
- local pos = self.object:get_pos()
-
-
- if mobkit.is_queue_empty_high(self) then
- mobkit.hq_roam(self, 0)
- end
- end
- end
- return parrot_brain
|