151 lines
4.6 KiB
Ruby
151 lines
4.6 KiB
Ruby
# Represents a space-faring vessel owned by a player.
|
|
# Handles movement and validation of ship creation.
|
|
|
|
require 'securerandom'
|
|
|
|
# Load the ships into a constant:
|
|
require 'yaml'
|
|
# Configuration data for all available ships
|
|
SHIP_DATA = File.open('lib/game/data/ships.yaml', 'r') do |fi|
|
|
YAML.safe_load(fi.read())
|
|
end
|
|
|
|
# Represents a space-faring vessel owned by a player.
|
|
class Ship
|
|
|
|
attr_reader :owner, :position
|
|
|
|
# Ships are built by a player so we should *always* know what player is
|
|
# owning a ship
|
|
#
|
|
# @param player [Player] The player who owns the ship
|
|
# @param position_x [Float] The starting x position of the ship.
|
|
# @param position_y [Float] The starting y position of the ship.
|
|
# @param position_z [Float] The starting z position of the ship.
|
|
def initialize(player, position_x, position_y, position_z, name)
|
|
@owner = player
|
|
@ship_id = SecureRandom.hex
|
|
@position = [position_x, position_y, position_z]
|
|
@target = @position
|
|
@speed = 1
|
|
@ship_info = validate_creation(name)
|
|
end
|
|
|
|
# Validates that the ship name exists and it is unlocked by the player (Has
|
|
# the right buildings and tech to actually create). This means that you might
|
|
# be able to start a ship however when it is 'finished' if a required
|
|
# building has been removed it will fail to finish properly. In this case the
|
|
# player resources should be refunded (with some lost) and the ship creation
|
|
# will raise an error.
|
|
def validate_creation(name)
|
|
ship = SHIP_DATA[name]
|
|
raise ShipError, "invalid ship name '#{name}'" if ship.nil?
|
|
# Validate that the owner has the correct tech:
|
|
ship['required_tech'].each do |tech_needed|
|
|
if !(@owner.researched_tech.include? tech_needed)
|
|
raise ShipError, "Player needs the tech of '#{tech_needed}'"
|
|
end
|
|
end
|
|
# Validate the buildings:
|
|
ship['required_buildings'].each do |building_needed|
|
|
if !(@owner.buildings.include? building_needed)
|
|
raise ShipError, "Player needs the building of '#{building_needed}' to build this ship"
|
|
end
|
|
end
|
|
return ship
|
|
end
|
|
|
|
# Teleport the ship to a given position. Really only should be used for admin
|
|
# stuff.
|
|
#
|
|
# @param position_x [Float] The new x position of the ship.
|
|
# @param position_y [Float] The new y position of the ship.
|
|
# @param position_z [Float] The new z position of the ship.
|
|
def teleport(position_x, position_y, position_z)
|
|
@position = [position_x, position_y, position_z]
|
|
end
|
|
|
|
# Sets the target position of a ship.
|
|
#
|
|
# @param position_x [Float] The new x position of the ship.
|
|
# @param position_y [Float] The new y position of the ship.
|
|
# @param position_z [Float] The new z position of the ship.
|
|
def move(position_x, position_y, position_z)
|
|
@target = [position_x, position_y, position_z]
|
|
end
|
|
|
|
# Contains the logic to move a ship
|
|
#
|
|
# @param delta_time [Float] The delta time elapsed in the game
|
|
def update(delta_time)
|
|
# Movement logic:
|
|
if @position == @target
|
|
# Do nothing
|
|
else
|
|
# Calculate the difference of the position and the target
|
|
x_dist = @target[0] - @position[0]
|
|
y_dist = @target[1] - @position[1]
|
|
z_dist = @target[2] - @position[2]
|
|
total_dist = Math.sqrt(x_dist**2 + y_dist**2 + z_dist**2)
|
|
speed = (@speed/total_dist) * delta_time
|
|
|
|
new_x = @position[0] + (x_dist * speed)
|
|
new_y = @position[1] + (y_dist * speed)
|
|
new_z = @position[2] + (z_dist * speed)
|
|
|
|
if x_dist > 0 # Going right
|
|
if new_x > @target[0]
|
|
new_x = @target[0]
|
|
end
|
|
elsif x_dist < 0 # Going left
|
|
if new_x < @target[0]
|
|
new_x = @target[0]
|
|
end
|
|
end
|
|
|
|
if y_dist > 0 # Going right
|
|
if new_y > @target[1]
|
|
new_y = @target[1]
|
|
end
|
|
elsif y_dist < 0 # Going left
|
|
if new_y < @target[1]
|
|
new_y = @target[1]
|
|
end
|
|
end
|
|
|
|
if z_dist > 0 # Going right
|
|
if new_z > @target[2]
|
|
new_z = @target[2]
|
|
end
|
|
elsif z_dist < 0 # Going left
|
|
if new_z < @target[2]
|
|
new_z = @target[2]
|
|
end
|
|
end
|
|
@position = [new_x, new_y, new_z]
|
|
end
|
|
end
|
|
|
|
# Save a player to a file
|
|
def save_to_file
|
|
File.open("game_data/#{self.planet_id}.save", 'wb') do |fi|
|
|
# Load resources for the player:
|
|
fi.write(Marshal.dump(self))
|
|
end
|
|
return self.planet_id
|
|
end
|
|
|
|
# Load a player from a file
|
|
def self.load_from_save(fname)
|
|
File.open("game_data/#{fname}_ship_.save", 'rb') do |fi|
|
|
# Load resources for the player:
|
|
Marshal.load(fi.read)
|
|
end
|
|
end
|
|
end
|
|
|
|
# Error class for ships
|
|
# Represents a space-faring vessel owned by a player.
|
|
class ShipError < StandardError
|
|
end
|