Files
space_game_server/lib/game/ship.rb
T

148 lines
4.4 KiB
Ruby

# Nathan Hinton 30 Dec 2025
# Ship file for the game
require 'securerandom'
# Load the ships into a constant:
require 'yaml'
SHIP_DATA = File.open('lib/game/data/ships.yaml', 'r') do |fi|
YAML.safe_load(fi.read())
end
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
class ShipError < StandardError
end