--[[
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