--[[ lama is a MUD server made in Lua. Copyright (C) 2013 Curtis Erickson This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. ]] --- Cloneable:MapObject that holds data for mobile creatures. -- @author milkmanjack module("obj.Mob", package.seeall) local MapObject = require("obj.MapObject") local CharacterData = require("obj.CharacterData") local Event = require("obj.Event") --- Cloneable:MapObject that holds data for mobile creatures. -- @class table -- @name Mob -- @field keywords Keywords for the creature. -- @field name Name of the creature. -- @field description A complete description of the creature. -- @field level Experience level of the creature. -- @field experience Experience accumulated this level. -- @field race Mob's race. -- @field class Mob's class. -- @field health Current health. -- @field mana Current mana. -- @field moves Current moves. -- @field player The Player we're associated with. -- @field characterData Character data for this mob. -- @field victim The Mob we're fighting. -- @field combatEvent The event managing our combat rounds. local Mob = MapObject:clone() -- mob data, bro. Mob.keywords = "mob" Mob.name = "mob" Mob.description = "It's a mob." Mob.level = 1 Mob.experience = 0 Mob.race = require("obj.Race") Mob.class = require("obj.Class") Mob.health = 100 Mob.mana = 100 Mob.moves = 100 Mob.player = nil -- this is a cross-reference to a player that is controlling us. -- combat stuff Mob.victim = nil -- a mob we're fighting Mob.combatEvent = nil -- current event for combat processing --- Assigns a character data table. function Mob:initialize() self.characterData = CharacterData:new() end --- Takes a step in the given direction. -- @param direction Direction to step in. -- @return true on successful step.<br/>false otherwise. function Mob:step(direction) local oldLoc, newLoc = self:getLoc(), self.map:getStep(self, direction) if newLoc and newLoc:permitEntrance(self) then self:sendMessage(string.format("You take a step to the %s.", Direction.name(direction)), MessageMode.MOVEMENT) -- alert room to our entrance for i,v in ipairs(newLoc:getContents()) do v:sendMessage(string.format("%s has entered from the %s.", self:getName(), Direction.name(Direction.reverse(direction))), MessageMode.MOVEMENT) end self:move(newLoc) -- alert previous room to our exit for i,v in ipairs(oldLoc:getContents()) do v:sendMessage(string.format("%s has left to the %s.", self:getName(), Direction.name(direction)), MessageMode.MOVEMENT) end return true end return false end --- Shows a description of the room the mob inhabits to the mob. function Mob:showRoom() local location = self:getLoc() local msg = string.format("%s (%d,%d,%d)\n %s", location:getName(), location:getX(), location:getY(), location:getZ(), location:getDescription()) for i,v in ipairs(location:getContents()) do if v:isCloneOf(Mob) and v ~= self then msg = string.format("%s%s %s is here", msg, "\n", v:getName()) end end -- non-mobs. later this'll be Items for i,v in ipairs(location:getContents()) do if not v:isCloneOf(Mob) then msg = string.format("%s%sA %s is here.", msg, "\n", v:getName()) end end self:sendMessage(msg, MessageMode.INFO) end --- Get the Mob's level. function Mob:getLevel() return self.level end --- Get the Mob's experience. function Mob:getExperience() return self.experience end --- Get the Mob's race. function Mob:getRace() return self.race end --- Get the Mob's class. function Mob:getClass() return self.class end --- Get the Mob's current health. -- @return Mob's health. function Mob:getHealth() return self.health end --- Get the Mob's base health.<br/> -- Base health being the health provided by theirs race, class, and constitution. -- @return Mob's base health. function Mob:getBaseHealth() return self.race:getHealthForLevel(self.level) + self.class:getHealthForLevel(self.level) + (self:getConstitution() * Attribute.healthPerConstitution) end --- Get the Mob's max health.<br/> -- Max health being the health provided by their race, class, constitution, equipment, and enhancements. -- @return Mob's max health. function Mob:getMaxHealth() return self:getBaseHealth() end --- Restores the Mob's health to max. function Mob:restoreHealth() self.health = self:getMaxHealth() end --- Modifies the Mob's health, keeping it between 0 and their max health. function Mob:modifyHealth(amount) self.health = math.min(math.max(0, self.health + amount), self:getMaxHealth()) end --- Get the Mob's current mana. -- @return Mob's mana. function Mob:getMana() return self.mana end --- Get the Mob's base mana.<br/> -- Base mana being the mana provided by their race, class, and intelligence. -- @return Mob's base mana. function Mob:getBaseMana() return self.race:getManaForLevel(self.level) + self.class:getManaForLevel(self.level) + (self:getIntelligence() * Attribute.manaPerIntelligence) end --- Get the Mob's max mana.<br/> -- Max mana being the mana provided by their race, class, intelligence, equipment, and enhancements. -- @return Mob's max mana. function Mob:getMaxMana() return self:getBaseMana() end --- Restores the Mob's mana to max. function Mob:restoreMana() self.mana = self:getMaxMana() end --- Modifies the Mob's mana, keeping it between 0 and their max mana. function Mob:modifyMana(amount) self.mana = math.min(math.max(0, self.mana + amount), self:getMaxMana()) end --- Get the Mob's current moves. -- @return Mob's moves. function Mob:getMoves() return self.moves end --- Get the Mob's base moves.<br/> -- Base moves being the moves provided by their race, class, and constitution. -- @return Mob's base moves. function Mob:getBaseMoves() return self.race:getMovesForLevel(self.level) + self.class:getMovesForLevel(self.level) + (self:getConstitution() * Attribute.movesPerConstitution) end --- Get the Mob's max moves.<br/> -- Max moves being the moves provided by their race, class, constitution, equipment, and enhancements. -- @return Mob's max moves. function Mob:getMaxMoves() return self:getBaseMoves() end --- Restores the Mob's moves to max. function Mob:restoreMoves() self.moves = self:getMaxMoves() end --- Modifies the Mob's moves, keeping it between 0 and their max moves. function Mob:modifyMoves(amount) self.moves = math.min(math.max(0, self.moves + amount), self:getMaxMoves()) end --- Get the Mob's base strength.<br/> -- Base strength being the strength provided by their race and class. -- @return Mob's base strength. function Mob:getBaseStrength() return self.race:getStrengthForLevel(self.level) + self.class:getStrengthForLevel(self.level) end --- Get the Mob's current strength.<br/> -- Current strength being the strength provided by their race, class, equipment, and enhancements. -- @return Mob's base strength. function Mob:getStrength() return self:getBaseStrength() end --- Get the Mob's base agility.<br/> -- Base agility being the agility provided by their race and class. -- @return Mob's base agility. function Mob:getBaseAgility() return self.race:getAgilityForLevel(self.level) + self.class:getAgilityForLevel(self.level) end --- Get the Mob's current agility.<br/> -- Current agility being the agility provided by their race, class, equipment, and enhancements. -- @return Mob's base agility. function Mob:getAgility() return self:getBaseAgility() end --- Get the Mob's base dexterity.<br/> -- Base dexterity being the dexterity provided by their race and class. -- @return Mob's base dexterity. function Mob:getBaseDexterity() return self.race:getDexterityForLevel(self.level) + self.class:getDexterityForLevel(self.level) end --- Get the Mob's current dexterity.<br/> -- Current dexterity being the dexterity provided by their race, class, equipment, and enhancements. -- @return Mob's base dexterity. function Mob:getDexterity() return self:getBaseDexterity() end --- Get the Mob's base constitution.<br/> -- Base constitution being the constitution provided by their race and class. -- @return Mob's base constitution. function Mob:getBaseConstitution() return self.race:getConstitutionForLevel(self.level) + self.class:getConstitutionForLevel(self.level) end --- Get the Mob's current constitution.<br/> -- Current constitution being the constitution provided by their race, class, equipment, and enhancements. -- @return Mob's base constitution. function Mob:getConstitution() return self:getBaseConstitution() end --- Get the Mob's base intelligence.<br/> -- Base intelligence being the intelligence provided by their race and class. -- @return Mob's base intelligence. function Mob:getBaseIntelligence() return self.race:getIntelligenceForLevel(self.level) + self.class:getIntelligenceForLevel(self.level) end --- Get the Mob's current intelligence.<br/> -- Current intelligence being the intelligence provided by their race, class, equipment, and enhancements. -- @return Mob's base intelligence. function Mob:getIntelligence() return self:getBaseIntelligence() end --- Engage another mob in combat. -- @param target The mob to begin fighting. function Mob:engage(target) self.victim = target if not self.combatEvent then self.combatEvent = Event:new(Game.time()+4, function() self:combatRound() end, true, 0, 4) Game.queue(self.combatEvent) end end --- Disengage the current target. function Mob:disengage() self.victim = nil Game.deque(self.combatEvent) end --- One hit. -- @param victim Mob to hit. function Mob:oneHit(victim) if self.victim == nil then self:engage(victim) end if victim:getVictim() == nil then victim:engage(self) end self:sendMessage(string.format("You hit %s!", victim:getName()), MessageMode.COMBAT) victim:sendMessage(string.format("%s hits you!", self:getName()), MessageMode.COMBAT) end --- Mob combat round. function Mob:combatRound() if not self.victim or self.victim:getLoc() ~= self:getLoc() then self:disengage() return end self:oneHit(self.victim) end --- Shortcut to player:send(data,i,j) function Mob:send(data, i, j) if self.player then return self.player:send(data,i,j) end end --- Shortcut to player:sendString(str) function Mob:sendString(str) if self.player then return self.player:sendString(str) end end --- Shortcut to player:setMessageMode(mode) function Mob:setMessageMode(mode) if self.player then self.player:setMessageMode(mode) end end --- Shortcut to player:sendMessage(msg, mode, autobreak) function Mob:sendMessage(msg, mode, autobreak) if self.player then self.player:sendMessage(msg, mode, autobreak) end end -- shortcut to player:askQuestion(msg) function Mob:askQuestion(msg) if self.player then self.player:askQuestion(msg) end end --- Assign the mob's password. -- @param password New password. function Mob:setPassword(password) self.characterData.password = password end --- Associate this Mob with the given Player. A Mob's Player -- shares a mututal reference with the Mob, so when the -- Mob's Player changes, so does the Player's Mob. -- @param player The player to associate with. function Mob:setPlayer(player) self.player = player -- make sure it's mutual if player:getMob() ~= self then player:setMob(self) end end --- De-associates this Mob from our current Player. function Mob:unsetPlayer() local oldPlayer = self.player self.player = nil -- make sure it's mutual if oldPlayer:getMob() == self then oldPlayer:unsetMob() end end --- Get the Mob's name. -- @return Mob's name. function Mob:getName() return self.name end --- Get the Mob's description. -- @return Mob's description. function Mob:getDescription() return self.description end --- Get the Mob's password. -- @return The password. function Mob:getPassword() return self.characterData.password end --- Shortcut to player:getMessageMode() function Mob:getMessageMode(mode) return self.player and self.player:getMessageMode() end --- Get current Player. -- @return Current Player, if any. function Mob:getPlayer() return self.player end --- Check if this Mob has a Player controlling it. -- @return true if this Mob is controlled by a Player.<br/>false otherwise. function Mob:isPlayerControlled() return self.player ~= nil end --- Get the Mob's current victim. -- @return Mob's victim. function Mob:getVictim() return self.victim end return Mob