ship.lua

--- The main ship meta class.
-- @classmod Ship

Ship = {}





--------------------------------------------------------------------------------
--- Initialisation.
-- For creating and Initialising ShipCompass object.
-- @section initialisation
--------------------------------------------------------------------------------

--- Creates a new intance of the Ship class.
-- @tparam string _instanceName, should be identical to variable instance is assigned to.
-- @treturn table A new instance of the Ship class.
-- @usage thisShip = Ship:new()
function Ship:new(_instanceName)

    Ship.__index = Ship
    self = setmetatable({}, Ship)

    local _anchorRaised = false
    local _autorepairType = -1
    local _course = false
    local _crewBalance = true
    local _deckFire = false
    local _gangplankRaised = false
    local _hullHealth = -1
    local _instanceName = _instanceName
    local _isLeaking = false
    local _isRowing = false
    local _isSinking = false
    local _isTangled = false
    local _promptType = -1
    local _repairCooldown = false
    local _repairingHull = false
    local _repairingSails = false
    local _requestedCourse = false
    local _sailFire = false
    local _sailHealth = 100
    local _sailSetting = -1
    local _seaState = -1
    local _speed = -1
    local _type = -1
    local _windDirection = false
    local _windSpeed = -1

    _handlers = _handlers or {}
    if _instanceName then
        if _handlers[self._instanceName] then killAnonymousEventHandler(_handlers[self._instanceName]) end
        _handlers[self._instanceName] = registerAnonymousEventHandler("ship prompt captured", "_handlers["..self._instanceName.."]")
    end

    return self

end





--------------------------------------------------------------------------------
--- Repair methods.
-- Methods to handle repairing.
-- @section repair
--------------------------------------------------------------------------------

--- Runs autorepair routine, and issues repair orders if necessary.
-- Immediately returns if already repairing, so can be called on every prompt.
-- Check functionality on this. Ugly, but it should work.
-- @usage thisShip:runAutorepair()
function Ship:runAutorepair()

    if svo.conf.paused then return end

    local _repairHull = false
    local _repairSails = false

    if self._autoRepair == 0 then return end
    if self._repairCooldown then return end

    ---------------

    if self._hullHealth < 95 and not self._repairingHull then
        _repairHull = true
    end

    if self._sailHealth < 95 and not self._repairingSails and self._autoRepair == 2 then
        _repairSails = true
    end

    if _repairHull and not _repairSails then
        send("ship repair hull")
        self._repairCooldown = true
        tempTimer(1.0, function() self._repairCooldown = false end)
    elseif not _repairHull and _repairSails then
        send("ship repair sails")
        self._repairCooldown = true
        tempTimer(1.0, function() self._repairCooldown = false end)
    elseif _repairHull and _repairSails then
        send("ship repair all")
        self._repairCooldown = true
        tempTimer(1.0, function() self._repairCooldown = false end)
    end
end

--- Gets the current autorepair type for the ship.
-- @treturn int 0 = no repair, 1 = hull repair, 2 = all repair
-- @usage local autorepairType = Ship:getAutorepairType()
function Ship:getAutorepairType()
    return self._autorepairType
end

--- True if on cooldown between repair attempts.
-- @treturn bool True, if on cooldown.
-- @usage local repairCooldown = Ship:getRepairCooldown()
function Ship:getRepairCooldown()
    return self._repairCooldown
end

--- True if crew is repairing hull.
-- @treturn bool True, if repairing hull.
-- @usage local repairingHull = Ship:isRepairingHull()
function Ship:isRepairingHull()
    return self._repairingHull
end

--- True if crew is repairing sails.
-- @treturn bool True, if repairing sails.
-- @usage local repairingSails = Ship:isRepairingSails()
function Ship:isRepairingSails()
    return self._repairingSails
end

--- Sets the autorepair type for the ship.
-- @tparam int autorepairType 0 = repair none, 1 = repair hull, 2 = repair both
-- @usage outShip:setAutorepairType(1)
function Ship:setAutorepairType(autorepairType)
    self._autorepairType = autoRepairType
end

--- Enable or disable autorepair cooldown.
-- Will automatically disable itself after three seconds enabled.
-- @tparam bool _cooldown **true** to enable crew cooldown timer, **false** to disable it early.
-- @todo Make it not double-disable.
function Ship:setRepairCooldown(_cooldown)
    self._repairCooldown = _coolDown or false
if _cooldown then tempTimer(3, function() self:setRepairCooldown(false) end) end
end

--- Set if crew is repairing hull.
-- @tparam bool _keepRepairing True, if repairing hull.
function Ship:repairHull(_keepRepairing)
    self._repairingHull = _keepRepairing or false
end

--- Set if crew is repairing sails.
-- @tparam bool _keepRepairing True, if repairing sails.
function Ship:repairSails(_keepRepairing)
    self._repairingSails = _keepRepairing or false
end





--------------------------------------------------------------------------------
--- Prompt methods.
-- Methods to handle the various ship prompts.
-- @section prompt
--------------------------------------------------------------------------------

--- Processes a ship prompt line in-object, instead of using complex triggers.
-- Reads both Battle and Cryptic prompts, and populates the instance's attributes accordingly.
-- To enable, simply use a trigger to pass the prompt
-- @tparam string _promptString The full ship prompt line from the game.
-- @treturn event,table Raises ship prompt processed event. Prompt data passed along as a table.
function Ship:processPrompt(_promptString)

    local _searchString = ""
    if string.match(_promptString, "(%w+)") == "Sl" then
        _searchString = "^= Sl (.*) %- hp (.*),Hl: (.*),Wd (%w+)@(%d+)kts,Cr/Sp (%w+)@(%d+),Sea (%w+)(.*)$"
    elseif string.match(_promptString, "(%w+)") == "S"  then
        _searchString = "^= S(.*)@h(.*),H(.*),W<%-(%w*)@(%d*)kts,C/S%->(%w+)@(%d+),(%w+)(.*)"
    end

    local promptCaptures = { string.match( _promptString, _searchString ) }

    local promptData = {}                                       -- EXAMPLE DATA
    promptData._sailSetting   = promptCaptures[1] or "error"    -- 75
    promptData._sailHealth    = promptCaptures[2] or "error"    -- 95
    promptData._hullHealth    = promptCaptures[3] or "error"    -- 87
    promptData._windDirection = promptCaptures[4] or "error"    -- "ne"
    promptData._windSpeed     = promptCaptures[5] or "error"    -- 20
    promptData._course        = promptCaptures[6] or "error"    -- "nw"
    promptData._speed         = promptCaptures[7] or "error"    -- 15
    promptData._seaState      = promptCaptures[8] or "error"    -- 3

    -------------

    promptData._rowing        = false

    if promptCaptures[9] then
        --promptData._requestedCourse = string.match(promptCaptures[9], "T%w*%->(%w+)") or false
        if string.find(promptCaptures[9], "R%w?w") then
            promptData._rowing = true
        end
    end

    ------------------------------------------------

    self:setCourse(promptData._course)
    self:setHullHealth(promptData._hullHealth)
    -- ? self:setRequestedCourse(promptData._requestedCourse)
    self:setRowing(promptData._rowing)
    self:setSailHealth(promptData._sailHealth)
    self:setSailSetting(promptData._sailSetting)
    self:setSeaState(promptData._seaState)
    self:setSpeed(promptData._speed)
    self:setWindDirection(promptData._windDirection)
    self:setWindSpeed(promptData._windSpeed)

    promptData._course        = self:getCourse()
    promptData._hullHealth    = self:getHullHealth()
    promptData._rowing        = self:isRowing()
    promptData._sailHealth    = self:getSailHealth()
    promptData._sailSetting   = self:getSailSetting()
    promptData._seaState      = self:getSeaState()
    promptData._speed         = self:getSpeed()
    promptData._windDirection = self:getWindDirection()
    promptData._windSpeed     = self:getWindSpeed()

    raiseEvent("ship done with prompt", promptData)

end





--------------------------------------------------------------------------------
--- Queries.
-- Methods to query about various states within the ship.
-- @section queries
--------------------------------------------------------------------------------

--- Retrieves anchor state.
-- @treturn bool True if anchor raised, false if anchor lowered.
-- @usage if not thisShip:isAnchorRaised() then send("ship raise anchor") end
function Ship:isAnchorRaised()
    return self._anchorRaised or false
end

--- Returns if ship is docked.
-- @treturn bool True, if ship is docked.
function Ship:isDocked()

    local _error = self:getError()

    if (_error >= 1) or (_error <= -1) then
        return false
    end

    if _error == 0 then
        for k, v in ipairs(uacs:getWaypointTable()) do
            if (v.type == "H") and (uacs:getEasting() == v.easting) and (uacs:getSouthing() == v.southing) then
                return true
            end
        end
    end

end

--- Retrieves gangplank state.
-- @treturn bool True if gangplank raised, false if gangplank lowered.
-- @usage if not thisShip:isGangplankRaised() then send("ship raise gangplank") end
function Ship:isGangplankRaised()
    return self._gangplankRaised or false
end

--- Returns if ship is grappled.
-- @treturn bool True, if ship is grappled.
-- @treturn table Key/value table containing grapplers and hooks per.
-- @todo Add functionality.
function Ship:isGrappled()
    return false, {["nope"] = 0, }
end

--- Returns if ship is leaking.
-- @treturn bool True, if ship is leaking.
-- @todo Add functionality.
function Ship:isLeaking()
    return false
end

--- Returns if ship is on fire.
-- @treturn int|bool false = no fire, 1 = deck fire, 2 = sails fire, 3 = deck and sails on fire.
function Ship:isOnFire()
    local _fireLevel = false
    if self._deckFire then _fireLevel = (_fireLevel + 1) or 1 end
    if self._sailFire then _fireLevel = (_fireLevel + 2) or 2 end
    return _fireLevel
end

--- True if ship is rowing.
-- @return bool
function Ship:isRowing()
    return self._isRowing
end

--- True if ship is sailing.
-- "Sailing" is defined as any sail setter beyond furled.
-- @return bool
function Ship:isSailing()
    return (self._sailSetting > 0)
end

--- Returns if ship is sinking.
-- @treturn bool True, if ship is sinking.
-- @todo Add functionality.
function Ship:isSinking()
    return(false)
end

--- Returns if ship is turning.
-- @treturn bool|string False, if not turning. Ordered course as string, otherwise.
function Ship:isTurning()
    return self_.requestedCourse
end





--------------------------------------------------------------------------------
--- Get methods.
-- Methods to retrieve various points of information about the ship.
-- @section get
--------------------------------------------------------------------------------

--- Gets the current course of the ship.
-- @treturn string Course as compass direction
function Ship:getCourse()
    return self._course
end

--- Gets the crew balance for the ship.
-- @treturn bool True, if have crew balance.
function Ship:getCrewBalance()
    return self._crewBalance
end

--- Gets the current hull health for the ship.
-- @treturn int Hull health, 1-100.
function Ship:getHullHealth()
    return self._hullHealth
end

--- Gets the current sail health for the ship.
-- @treturn int Sail health, 1-100.
function Ship:getSailHealth()
    return self._sailHealth
end

--- Gets the current sail setting for the ship.
-- @treturn int Sail setting, 0-100.
function Ship:getSailSetting()
    return self._sailSetting
end

--- Gets the current sea state around the ship.
-- @treturn int Sea state, 1-9.
function Ship:getSeaState()
    return self._seaState
end

--- Gets the current speed of the ship.
-- @treturn int Ship's current speed, in knots.
function Ship:getSpeed()
    return self._speed
end

--- Gets the current sea state around the ship.
-- @treturn int Sea state, 1-9.
function Ship:getWindSpeed()
    return self._windSpeed
end

--- Gets the current speed of the ship.
-- @treturn int Ship's current speed, in knots.
function Ship:getWindDirection()
    return self._windDirection
end






--------------------------------------------------------------------------------
--- Set methods.
-- Methods to retrieve various points of information about the ship.
-- @section set
--------------------------------------------------------------------------------

--- Sets whether the anchor is currently raised.
-- @tparam bool _isRaised True if anchor raised, false if anchor lowered.
-- @usage thisShip:setAnchorRaised(true)
function Ship:setAnchorRaised(_isRaised)
    self._anchorRaised = _isRaised or false
end

--- Sets whether the crew is on balance.
-- @tparam bool _onBalance True, if crew on balance.
-- @usage thisShip:setCrewBalance(false)
function Ship:setCrewBalance(_onBalance)
    self._crewBalance = _onBalance or false
end

--- Sets the current course of the Ship object.
-- Intended to simply document, after the prompt is processed.
-- @tparam string _captureGroup Direction as short compass heading.
-- @treturn bool True if successful.
function Ship:setCourse(_captureGroup)

    _captureGroup = string.lower(_captureGroup)

    local _validDirs = {
        ["n"]   = true,
        ["nne"] = true,
        ["ne"]  = true,
        ["ene"] = true,
        ["e"]   = true,
        ["ese"] = true,
        ["se"]  = true,
        ["sse"] = true,
        ["s"]   = true,
        ["ssw"] = true,
        ["sw"]  = true,
        ["wsw"] = true,
        ["w"]   = true,
        ["wnw"] = true,
        ["nw"]  = true,
        ["nnw"] = true,
    }

    assert(_validDirs[_captureGroup], "Ship:setCourse() - _captureGroup (".._captureGroup..") not in _validDirs!")

    self._course = _captureGroup

    return true

end

--- Sets whether the gangplank is currently raised.
-- @tparam bool _isRaised True if gangplank raised, false if gangplank lowered.
-- @usage thisShip:setGangplankRaised(false)
function Ship:setGangplankRaised(_isRaised) -- True if gangplank raised.
    self._gangplankRaised = _isRaised or false
end





--------------------------------------------------------------------------------
--- Internal functions.
-- Internal stuff. Not for external stuff.
-- @section ifunctions
--------------------------------------------------------------------------------

--- Sets the current hull health of the Ship object.
-- Can accept prompt symbols, integer percenage strings, and raw numbers.
-- @tparam string|int _captureGroup The argument to pass into the function. Strings such as ++ okay.
-- @treturn bool True, if successful
-- @treturn string The capture group passed into the function.
function Ship:setHullHealth(_captureGroup)

    local _captureGroup_type = type(_captureGroup)

    if _captureGroup_type == "string" then
        local _stringValues = {
            ["full"] = 100,
            ["++"] = 100,
            ["--"] = 0,
        }
        -- Try to match _captureGroup to a _stringValues entry,
        _captureGroup = _stringValues[_captureGroup] or tonumber(string.match(_captureGroup, "(%d+)%%")) or tonumber(_captureGroup)
        _captureGroup_type = type(_captureGroup)
    end

    -- Should darn well be a number between 0 and 100 at this point.
    assert((_captureGroup_type == "number"), "Ship:setHullHealth() - _captureGroup (".._captureGroup..") failed to return number!")
    assert((_captureGroup <= 100) and (_captureGroup >= 0), "Ship:setHullHealth() - _captureGroup (".._captureGroup..") is type number, but out of bounds!")

    self._hullHealth = _captureGroup

    return true, tostring(_captureGroup)

end


--- Sets the current rowing state of the Ship object.
-- @tparam string _captureGroup Capture Either full ship prompt line, or substring that would contain rowing flag.
function Ship:setRequestedCourse(_captureGroup)
    if type(_captureGroup) == "string" then
        self._isRowing = string.find(_captureGroup, "Row") or string.find(_captureGroup, "Rw") or false
    else
        return false
    end
end


--- Sets the current rowing state of the Ship object.
-- @tparam string _captureGroup Capture Either full ship prompt line, or substring that would contain rowing flag.
function Ship:setRowing(_captureGroup)
    if type(_captureGroup) == "boolean" then
        self._isRowing = _captureGroup
    elseif type(_captureGroup) == "string" then
        self._isRowing = string.find(_captureGroup, "Row") or string.find(_captureGroup, "Rw") or false
    else
        return false
    end
end

--- Sets the current sail health of the Ship object.
-- Can accept prompt symbols, integer percenage strings, and raw numbers.
-- Possible input examples: ++, --, or int`.
-- @tparam string|int _captureGroup The argument to pass into the function. Strings such as ++ okay.
-- @treturn bool True, if successful
-- @treturn string The capture group passed into the function.
function Ship:setSailHealth(_captureGroup)

    local _captureGroup_type = type(_captureGroup)

    if _captureGroup_type == "string" then
        _captureGroup = string.lower(_captureGroup)
        local _stringValues = {
            ["full"] = 100,
            ["++"] = 100,
            ["--"] = 0,
        }
        -- Try to match _captureGroup to a _stringValues entry,
        _captureGroup = _stringValues[_captureGroup] or tonumber(string.match(_captureGroup, "(%d+)")) or tonumber(_captureGroup)
        _captureGroup_type = type(_captureGroup)
        end

    -- Should darn well be a number between 0 and 100 at this point.
    assert((_captureGroup_type == "number"), "Ship:setSailHealth() - _captureGroup (".._captureGroup..") failed to return number!")
    assert((_captureGroup <= 100) and (_captureGroup >= 0), "Ship:setSailHealth() - _captureGroup (".._captureGroup..") is type number, but out of bounds!")

    self._sailHealth = _captureGroup

    return true, _captureGroup

end

--- Sets the current sail setting of the Ship object.
-- Can accept prompt symbols, integer percenage strings, and raw numbers.
-- Possible input examples: ++, --, or int`.
-- @tparam string|int _captureGroup The argument to pass into the function. Strings such as ++ okay.
-- @treturn bool True, if successful
-- @treturn string The capture group passed into the function.
function Ship:setSailSetting(_captureGroup)

    local _captureGroup = string.lower( _captureGroup )
    local _captureGroup_type = type(_captureGroup)

    if _captureGroup_type == "string" then
        local _stringValues = {
            ["full"] = 100,
            ["furl"] = 0,
            ["++"] = 100,
            ["--"] = 0,
        }
        -- Try to match _captureGroup to a _stringValues entry,
        _captureGroup = _stringValues[_captureGroup] or tonumber(string.match(_captureGroup, "(%d+)%%")) or tonumber(_captureGroup)
        _captureGroup_type = type(_captureGroup)
    end

    -- Should darn well be a number between 0 and 100 at this point.
    assert((_captureGroup_type == "number"), "Ship:setSailSetting() - _captureGroup (".._captureGroup..") failed to return number!")
    assert((_captureGroup <= 100) and (_captureGroup >= 0), "Ship:setSailSetting() - _captureGroup (".._captureGroup..") is type number, but out of bounds!")

    self._sailSetting = _captureGroup

    return true, _captureGroup

end

--- Sets the current sea state of the Ship object.
-- @tparam string|int _captureGroup Sea state as either descriptor or Roman numerals as string, or raw number input.
-- @treturn bool True, if successful
-- @treturn string The capture group passed into the function.
function Ship:setSeaState(_captureGroup)

    local _seaStateChart = {
        ["glassy"]      = 1,
        ["smooth"]      = 2,
        ["calm"]        = 3,
        ["choppy"]      = 4,
        ["whitecapped"] = 5,
        ["rough"]       = 6,
        ["stormy"]      = 7,
        ["tempestuous"] = 8,
        ["raging"]      = 9,
        ["i"]    = 1,
        ["ii"]   = 2,
        ["iii"]  = 3,
        ["iv"]   = 4,
        ["v"]    = 5,
        ["vi"]   = 6,
        ["vii"]  = 7,
        ["viii"] = 8,
        ["ix"]   = 9,
    }

    _captureGroup = tonumber(_captureGroup) or _seaStateChart[string.lower(_captureGroup)] or - 1
    assert((type(_captureGroup) == "number") and (_captureGroup <= 100) and (_captureGroup >= 0), "Ship:setSeaState() - _captureGroup (".._captureGroup..") not a real sea state!")
    self._seaState = _captureGroup

    return true, _captureGroup

end

--- Sets the current speed of the Ship object.
-- @tparam int|string _captureGroup
function Ship:setSpeed(_captureGroup)
    _captureGroup = tonumber(_captureGroup)
    assert((type(_captureGroup) == "number") and (_captureGroup <= 100) and (_captureGroup >= 0), "Ship:setSpeed() - _captureGroup (".._captureGroup..") isn't a number, oops!")
    self._speed = _captureGroup
end

--- Sets the current wind direction of the Ship object.
-- @tparam string _captureGroup String direction to pass to the Navigator.
-- @return bool True if successful.
function Ship:setWindDirection(_captureGroup)

    _captureGroup = string.lower(_captureGroup)

    local _validDirs = {
        ["n"]   = true,
        ["nne"] = true,
        ["ne"]  = true,
        ["ene"] = true,
        ["e"]   = true,
        ["ese"] = true,
        ["se"]  = true,
        ["sse"] = true,
        ["s"]   = true,
        ["ssw"] = true,
        ["sw"]  = true,
        ["wsw"] = true,
        ["w"]   = true,
        ["wnw"] = true,
        ["nw"]  = true,
        ["nnw"] = true,
    }

    assert(_validDirs[_captureGroup], "Ship:setWindDirection() - _captureGroup (".._captureGroup..") not in _validDirs!")

    self._windDirection = _captureGroup

    return true

end

--- Sets the current wind speed of the Ship object.
-- @tparam string _captureGroup
-- @todo Peek over a bit
function Ship:setWindSpeed (_captureGroup)
    self._windSpeed = tonumber(_captureGroup)
end
generated by LDoc 1.4.3 Last updated 2021-01-24 20:08:44