wrote basic building stuff, need to impliment more in the player.
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
# Nathan Hinton Jan 2026
|
||||
# Game file for the buildings
|
||||
|
||||
|
||||
require 'securerandom'
|
||||
|
||||
# Load the ships into a constant:
|
||||
require 'yaml'
|
||||
BUILDING_DATA = File.open('lib/game/data/buildings.yaml', 'r') do |fi|
|
||||
YAML.safe_load(fi.read())
|
||||
end
|
||||
|
||||
|
||||
class Building
|
||||
attr_reader :name
|
||||
|
||||
# Create a building. Requires a player and a planet to construct on.
|
||||
#
|
||||
# @param player [Player] The player who owns the building.
|
||||
# @param planet [Planet] The planet the building should be built on.
|
||||
# @param name [String] The name of the building to be built.
|
||||
def initialize(player, planet, name)
|
||||
@player = player
|
||||
@planet = planet
|
||||
@name = name
|
||||
@building_exist_time = 0
|
||||
@building_last_production_time = 0
|
||||
# Return error if the building does not exist
|
||||
@building = BUILDING_DATA[name]
|
||||
if @building.nil?
|
||||
raise BuildingError, "Invalid building name `#{name}`"
|
||||
end
|
||||
|
||||
# Check the player owns the planet
|
||||
if planet.owner != player
|
||||
raise BuildingError, 'Player does not own planet!'
|
||||
end
|
||||
|
||||
# Check the player has the resources
|
||||
resources = ['metal', 'crystals', 'fuel', 'credits']
|
||||
resources.each do |resource|
|
||||
if @player.player_resources[resource] < @building['build_cost'][resource]
|
||||
raise BuildingError, "Player does not have enough #{resource}!"
|
||||
end
|
||||
end
|
||||
|
||||
resources.each do |resource|
|
||||
@player.player_resources[resource] -= @building['build_cost'][resource]
|
||||
end
|
||||
|
||||
# Check that the player owns the needed buildings to construct:
|
||||
player_buildings = @player.all_buildings.map{|building| building.name}
|
||||
@building['required_buildings'].each do |required_building|
|
||||
unless player_buildings.include? required_building
|
||||
raise BuildingError, "Requires `#{required_building}` first"
|
||||
end
|
||||
end
|
||||
|
||||
# Check that the player owns the needed tech to construct:
|
||||
player_tech = @player.all_tech.map{|tech| tech.name}
|
||||
@building['required_tech'].each do |required_tech|
|
||||
unless player_tech.include? required_tech
|
||||
raise BuildingError, "Requires the tech of `#{required_tech}` first"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This is in charge of doing things like adding to the turn build power and
|
||||
# providing resources from buildings.
|
||||
def update(delta_time)
|
||||
@building_exist_time += delta_time
|
||||
# Incriment internal time count:
|
||||
# Do not produce resources if the building is not finished
|
||||
if @building_exist_time < @building['build_cost']['time']
|
||||
return # Exit
|
||||
end
|
||||
|
||||
# Do not produce resources if there are not enough resources for upkeep
|
||||
resources = ['metal', 'crystals', 'fuel', 'credits']
|
||||
resources.each do |resource|
|
||||
if @player.player_resources[resource * delta_time] < @building['upkeep'][resource * delta_time]
|
||||
raise BuildingWarning, "Player does not have enough #{resource} to produce from #{@name}!"
|
||||
end
|
||||
end
|
||||
|
||||
resources.each do |resource|
|
||||
@player.player_resources[resource * delta_time] -= @building['upkeep'][resource * delta_time]
|
||||
end
|
||||
@building_last_production_time += delta_time
|
||||
|
||||
# If the building is a resource production building we need to add the resources:
|
||||
if @building['classification'] == 'mining'
|
||||
if @building_last_production_time >= 1
|
||||
@building_last_production_time -= 1
|
||||
resources.each do |resource|
|
||||
# This resource production should jump
|
||||
@player.player_resources[resource] += @building['produces'][resource]
|
||||
end
|
||||
end
|
||||
elsif @building['classification'] == 'production'
|
||||
@player.ship_build_power += @building['produces']['ship_build_power']
|
||||
@player.research_tech_build_power += @building['produces']['research_tech_build_power']
|
||||
@player.military_tech_build_power += @building['produces']['military_tech_build_power']
|
||||
else
|
||||
raise BuildingError, 'Unknown classification for building type. Trying to add resources etc...'
|
||||
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 the buildings
|
||||
class BuildingError < StandardError
|
||||
end
|
||||
|
||||
# Warning class for the buildings
|
||||
class BuildingWarning < StandardError
|
||||
end
|
||||
@@ -1,163 +0,0 @@
|
||||
# Nathan Hinton 2 Jan 2025 Buildings for the game
|
||||
#
|
||||
|
||||
# Production buildings:
|
||||
Shipyard Level 1:
|
||||
classification: production
|
||||
faction: good
|
||||
production: # This is what is required to produce the building:
|
||||
metal:
|
||||
crystals:
|
||||
fuel:
|
||||
credits:
|
||||
time:
|
||||
upkeep:
|
||||
metal:
|
||||
crystals:
|
||||
fuel:
|
||||
credits:
|
||||
base_stats: []
|
||||
|
||||
Shipyard Level 2:
|
||||
classification: production
|
||||
faction: good
|
||||
production: # This is what is required to produce the building:
|
||||
metal:
|
||||
crystals:
|
||||
fuel:
|
||||
credits:
|
||||
time:
|
||||
upkeep:
|
||||
metal:
|
||||
crystals:
|
||||
fuel:
|
||||
credits:
|
||||
base_stats: []
|
||||
|
||||
Space Construction Station Level 1:
|
||||
classification: production
|
||||
faction: good
|
||||
production: # This is what is required to produce the building:
|
||||
metal:
|
||||
crystals:
|
||||
fuel:
|
||||
credits:
|
||||
time:
|
||||
upkeep:
|
||||
metal:
|
||||
crystals:
|
||||
fuel:
|
||||
credits:
|
||||
base_stats: []
|
||||
|
||||
Space Construction Station Level 2:
|
||||
classification: production
|
||||
faction: good
|
||||
production: # This is what is required to produce the building:
|
||||
metal:
|
||||
crystals:
|
||||
fuel:
|
||||
credits:
|
||||
time:
|
||||
upkeep:
|
||||
metal:
|
||||
crystals:
|
||||
fuel:
|
||||
credits:
|
||||
base_stats: []
|
||||
|
||||
Research Factory Level 1:
|
||||
classification: production
|
||||
faction: good
|
||||
production: # This is what is required to produce the building:
|
||||
metal:
|
||||
crystals:
|
||||
fuel:
|
||||
credits:
|
||||
time:
|
||||
upkeep:
|
||||
metal:
|
||||
crystals:
|
||||
fuel:
|
||||
credits:
|
||||
base_stats: []
|
||||
|
||||
Research Factory Level 2:
|
||||
classification: production
|
||||
faction: good
|
||||
production: # This is what is required to produce the building:
|
||||
metal:
|
||||
crystals:
|
||||
fuel:
|
||||
credits:
|
||||
time:
|
||||
upkeep:
|
||||
metal:
|
||||
crystals:
|
||||
fuel:
|
||||
credits:
|
||||
base_stats: []
|
||||
|
||||
Shipyard Level 1:
|
||||
classification: production
|
||||
faction: good
|
||||
production: # This is what is required to produce the building:
|
||||
metal:
|
||||
crystals:
|
||||
fuel:
|
||||
credits:
|
||||
time:
|
||||
upkeep:
|
||||
metal:
|
||||
crystals:
|
||||
fuel:
|
||||
credits:
|
||||
base_stats: []
|
||||
|
||||
Shipyard Level 1:
|
||||
classification: production
|
||||
faction: good
|
||||
production: # This is what is required to produce the building:
|
||||
metal:
|
||||
crystals:
|
||||
fuel:
|
||||
credits:
|
||||
time:
|
||||
upkeep:
|
||||
metal:
|
||||
crystals:
|
||||
fuel:
|
||||
credits:
|
||||
base_stats: []
|
||||
|
||||
Shipyard Level 1:
|
||||
classification: production
|
||||
faction: good
|
||||
production: # This is what is required to produce the building:
|
||||
metal:
|
||||
crystals:
|
||||
fuel:
|
||||
credits:
|
||||
time:
|
||||
upkeep:
|
||||
metal:
|
||||
crystals:
|
||||
fuel:
|
||||
credits:
|
||||
base_stats: []
|
||||
|
||||
Shipyard Level 1:
|
||||
classification: production
|
||||
faction: good
|
||||
production: # This is what is required to produce the building:
|
||||
metal:
|
||||
crystals:
|
||||
fuel:
|
||||
credits:
|
||||
time:
|
||||
upkeep:
|
||||
metal:
|
||||
crystals:
|
||||
fuel:
|
||||
credits:
|
||||
base_stats: []
|
||||
@@ -0,0 +1,328 @@
|
||||
# Nathan Hinton 2 Jan 2025 Buildings for the game
|
||||
#
|
||||
|
||||
# Production buildings:
|
||||
Shipyard Level 1:
|
||||
classification: production
|
||||
faction: good
|
||||
build_cost: # This is what is required to produce the building:
|
||||
metal: 1,000
|
||||
crystals: 1,000
|
||||
fuel: 1,000
|
||||
credits: 1,000
|
||||
time: 1,000
|
||||
upkeep:
|
||||
metal: 100
|
||||
crystals: 100
|
||||
fuel: 100
|
||||
credits: 100
|
||||
base_stats:
|
||||
hp: 1,000
|
||||
shield: 1,000
|
||||
armor: 30
|
||||
def: 30
|
||||
produces:
|
||||
ship_build_power: 100
|
||||
research_tech_build_power: 0
|
||||
military_tech_build_power: 0
|
||||
required_tech: []
|
||||
required_buildings: []
|
||||
|
||||
Shipyard Level 2:
|
||||
classification: production
|
||||
faction: good
|
||||
build_cost: # This is what is required to produce the building:
|
||||
metal: 2,000
|
||||
crystals: 2,000
|
||||
fuel: 2,000
|
||||
credits: 2,000
|
||||
time: 2,000
|
||||
upkeep:
|
||||
metal: 200
|
||||
crystals: 200
|
||||
fuel: 200
|
||||
credits: 200
|
||||
base_stats:
|
||||
hp: 1,000
|
||||
shield: 1,000
|
||||
armor: 30
|
||||
def: 30
|
||||
produces:
|
||||
ship_build_power: 200
|
||||
research_tech_build_power: 0
|
||||
military_tech_build_power: 0
|
||||
required_tech: []
|
||||
required_buildings: [Shipyard Level 1]
|
||||
|
||||
Space Construction Station Level 1:
|
||||
classification: production
|
||||
faction: good
|
||||
build_cost: # This is what is required to produce the building:
|
||||
metal: 2,000
|
||||
crystals: 2,000
|
||||
fuel: 2,000
|
||||
credits: 2,000
|
||||
time: 2,000
|
||||
upkeep:
|
||||
metal: 200
|
||||
crystals: 200
|
||||
fuel: 200
|
||||
credits: 200
|
||||
base_stats:
|
||||
hp: 1,000
|
||||
shield: 1,000
|
||||
armor: 30
|
||||
def: 30
|
||||
produces:
|
||||
ship_build_power: 200
|
||||
research_tech_build_power: 0
|
||||
military_tech_build_power: 0
|
||||
required_tech: [Anti Gravity Thrusters 1]
|
||||
required_buildings: [Shipyard Level 1]
|
||||
|
||||
Space Construction Station Level 2:
|
||||
classification: production
|
||||
faction: good
|
||||
build_cost: # This is what is required to produce the building:
|
||||
metal: 3,000
|
||||
crystals: 3,000
|
||||
fuel: 3,000
|
||||
credits: 3,000
|
||||
time: 3,000
|
||||
upkeep:
|
||||
metal: 300
|
||||
crystals: 300
|
||||
fuel: 300
|
||||
credits: 300
|
||||
base_stats:
|
||||
hp: 1,000
|
||||
shield: 1,000
|
||||
armor: 30
|
||||
def: 30
|
||||
produces:
|
||||
ship_build_power: 300
|
||||
research_tech_build_power: 0
|
||||
military_tech_build_power: 0
|
||||
required_tech: [Anti Gravity Thrusters 2]
|
||||
required_buildings: [Space Construction Station Level 1, Shipyard Level 2]
|
||||
|
||||
Research Factory Level 1:
|
||||
classification: production
|
||||
faction: good
|
||||
build_cost: # This is what is required to produce the building:
|
||||
metal: 1,000
|
||||
crystals: 1,000
|
||||
fuel: 1,000
|
||||
credits: 1,000
|
||||
time: 1,000
|
||||
upkeep:
|
||||
metal: 100
|
||||
crystals: 100
|
||||
fuel: 100
|
||||
credits: 100
|
||||
base_stats:
|
||||
hp: 1,000
|
||||
shield: 1,000
|
||||
armor: 30
|
||||
def: 30
|
||||
produces:
|
||||
ship_build_power: 0
|
||||
research_tech_build_power: 100
|
||||
military_tech_build_power: 0
|
||||
required_tech: []
|
||||
required_buildings: []
|
||||
|
||||
Research Factory Level 2:
|
||||
classification: production
|
||||
faction: good
|
||||
build_cost: # This is what is required to produce the building:
|
||||
metal: 2,000
|
||||
crystals: 2,000
|
||||
fuel: 2,000
|
||||
credits: 2,000
|
||||
time: 2,000
|
||||
upkeep:
|
||||
metal: 200
|
||||
crystals: 200
|
||||
fuel: 200
|
||||
credits: 200
|
||||
base_stats:
|
||||
hp: 1,000
|
||||
shield: 1,000
|
||||
armor: 30
|
||||
def: 30
|
||||
produces:
|
||||
ship_build_power: 0
|
||||
research_tech_build_power: 200
|
||||
military_tech_build_power: 0
|
||||
required_tech: []
|
||||
required_buildings: [Research Factory Level 1]
|
||||
|
||||
Military Factory Level 1:
|
||||
classification: production
|
||||
faction: good
|
||||
build_cost: # This is what is required to produce the building:
|
||||
metal: 2,000
|
||||
crystals: 2,000
|
||||
fuel: 2,000
|
||||
credits: 2,000
|
||||
time: 2,000
|
||||
upkeep:
|
||||
metal: 200
|
||||
crystals: 200
|
||||
fuel: 200
|
||||
credits: 200
|
||||
base_stats:
|
||||
hp: 1,000
|
||||
shield: 1,000
|
||||
armor: 30
|
||||
def: 30
|
||||
produces:
|
||||
ship_build_power: 0
|
||||
research_tech_build_power: 0
|
||||
military_tech_build_power: 100
|
||||
required_tech: []
|
||||
required_buildings: [Research Factory Level 1]
|
||||
|
||||
Military Factory Level 2:
|
||||
classification: production
|
||||
faction: good
|
||||
build_cost: # This is what is required to produce the building:
|
||||
metal: 3,000
|
||||
crystals: 3,000
|
||||
fuel: 3,000
|
||||
credits: 3,000
|
||||
time: 3,000
|
||||
upkeep:
|
||||
metal: 300
|
||||
crystals: 300
|
||||
fuel: 300
|
||||
credits: 300
|
||||
base_stats:
|
||||
hp: 1,000
|
||||
shield: 1,000
|
||||
armor: 30
|
||||
def: 30
|
||||
produces:
|
||||
ship_build_power: 0
|
||||
research_tech_build_power: 0
|
||||
military_tech_build_power: 200
|
||||
required_tech: []
|
||||
required_buildings: [Military Factory Level 1]
|
||||
|
||||
# Harvesting
|
||||
|
||||
# Each building will produce the primary resource at %60, a secondary resource
|
||||
# at %24, a terciary resource at %10 and a final resource at %6. Here is the
|
||||
# rotation of how they are related:
|
||||
|
||||
# metal -> crystal -> fuel -> credits
|
||||
|
||||
|
||||
Metal Mines 1:
|
||||
classification: mining
|
||||
faction: good
|
||||
build_cost: # This is what is required to produce the building:
|
||||
metal: 1,000
|
||||
crystals: 1,000
|
||||
fuel: 1,000
|
||||
credits: 1,000
|
||||
time: 1,000
|
||||
upkeep:
|
||||
metal: 100
|
||||
crystals: 100
|
||||
fuel: 100
|
||||
credits: 100
|
||||
base_stats:
|
||||
hp: 1,000
|
||||
shield: 1,000
|
||||
armor: 30
|
||||
def: 30
|
||||
produces:
|
||||
metal: 600
|
||||
crystals: 240
|
||||
fuel: 100
|
||||
credits: 60
|
||||
required_tech: []
|
||||
required_buildings: []
|
||||
|
||||
Crystal Collector 1:
|
||||
classification: mining
|
||||
faction: good
|
||||
build_cost: # This is what is required to produce the building:
|
||||
metal: 1,000
|
||||
crystals: 1,000
|
||||
fuel: 1,000
|
||||
credits: 1,000
|
||||
time: 1,000
|
||||
upkeep:
|
||||
metal: 100
|
||||
crystals: 100
|
||||
fuel: 100
|
||||
credits: 100
|
||||
base_stats:
|
||||
hp: 1,000
|
||||
shield: 1,000
|
||||
armor: 30
|
||||
def: 30
|
||||
produces:
|
||||
metal: 60
|
||||
crystals: 600
|
||||
fuel: 240
|
||||
credits: 100
|
||||
required_tech: []
|
||||
required_buildings: []
|
||||
|
||||
Fuel Refinery 1:
|
||||
classification: mining
|
||||
faction: good
|
||||
build_cost: # This is what is required to produce the building:
|
||||
metal: 1,000
|
||||
crystals: 1,000
|
||||
fuel: 1,000
|
||||
credits: 1,000
|
||||
time: 1,000
|
||||
upkeep:
|
||||
metal: 100
|
||||
crystals: 100
|
||||
fuel: 100
|
||||
credits: 100
|
||||
base_stats:
|
||||
hp: 1,000
|
||||
shield: 1,000
|
||||
armor: 30
|
||||
def: 30
|
||||
produces:
|
||||
metal: 100
|
||||
crystals: 60
|
||||
fuel: 600
|
||||
credits: 240
|
||||
required_tech: []
|
||||
required_buildings: []
|
||||
|
||||
Credit Center 1:
|
||||
classification: mining
|
||||
faction: good
|
||||
build_cost: # This is what is required to produce the building:
|
||||
metal: 1,000
|
||||
crystals: 1,000
|
||||
fuel: 1,000
|
||||
credits: 1,000
|
||||
time: 1,000
|
||||
upkeep:
|
||||
metal: 100
|
||||
crystals: 100
|
||||
fuel: 100
|
||||
credits: 100
|
||||
base_stats:
|
||||
hp: 1,000
|
||||
shield: 1,000
|
||||
armor: 30
|
||||
def: 30
|
||||
produces:
|
||||
metal: 240
|
||||
crystals: 100
|
||||
fuel: 60
|
||||
credits: 600
|
||||
required_tech: []
|
||||
required_buildings: []
|
||||
+9
-6
@@ -104,6 +104,7 @@ module Game
|
||||
# @param client [TCPSocket] The client socket
|
||||
# @param command [Hash] JSON parsed command from the client.
|
||||
# @option command [String] :player_id Required, The player ID
|
||||
# @option command [String] :faction Required, The faction the player should join as.
|
||||
#
|
||||
# @return [Hash] status hash that will be converted to JSON before being
|
||||
# sent back to the client
|
||||
@@ -231,10 +232,9 @@ module Game
|
||||
# @param msg [String] The error message
|
||||
# @return [String] JSON-encoded error response
|
||||
#
|
||||
def error_response(msg)
|
||||
{ 'type' => 'error', 'payload' => msg }.to_json
|
||||
def error_response(request_id, msg)
|
||||
{ 'type' => 'error', 'request_id', => id, 'payload' => msg }.to_json
|
||||
end
|
||||
alias error_response error_response
|
||||
|
||||
##
|
||||
# Return a JSON object that tells a client about the current
|
||||
@@ -274,6 +274,9 @@ module Game
|
||||
delta_time * (player_count / GAME_SPEED_FACTOR)
|
||||
@game_time += delta_time
|
||||
|
||||
# Order here is important, We must update the buildings first (To
|
||||
# accrew resources for this delta) Because planets hold the buildings
|
||||
# they must be first.
|
||||
@planets.each do |planet|
|
||||
planet.update(delta_time)
|
||||
end
|
||||
@@ -282,9 +285,9 @@ module Game
|
||||
ship.update(delta_time)
|
||||
end
|
||||
|
||||
#@players.each do |player|
|
||||
# player.update(delta_time)
|
||||
#end
|
||||
@players.each do |player|
|
||||
player.update(delta_time)
|
||||
end
|
||||
|
||||
# Perform game saves (Or not for now...)
|
||||
if (@game_time) > next_save
|
||||
|
||||
@@ -42,7 +42,6 @@ class Planet
|
||||
|
||||
# Function to return info to the client about a planet
|
||||
def info_update
|
||||
raise NotImplementedError, "Need to write tests for this function"
|
||||
return {
|
||||
'id' => @planet_id,
|
||||
'position' => @position
|
||||
|
||||
+2
-1
@@ -5,7 +5,7 @@ require 'securerandom'
|
||||
|
||||
# Load the ships into a constant:
|
||||
require 'yaml'
|
||||
SHIP_DATA = File.open('lib/game/ships.yaml', 'r') do |fi|
|
||||
SHIP_DATA = File.open('lib/game/data/ships.yaml', 'r') do |fi|
|
||||
YAML.safe_load(fi.read())
|
||||
end
|
||||
|
||||
@@ -50,6 +50,7 @@ class Ship
|
||||
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
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
# Nathan Hinton 11 Jan 2026
|
||||
|
||||
# Test file for the main game. This is testing that the client/server responses
|
||||
# are performed correctly.
|
||||
#
|
||||
# Here is how the tests are structured: There are several fields that need to
|
||||
# be filled in a request to the server. These fields are: type, domain,
|
||||
# request_id, payload, and player_id. In these tests the requrest_id will be
|
||||
# randomized and checked that the response matches to that id. The client may
|
||||
# use these id's however they wish. If there is an id passed in with a request,
|
||||
# the matching response will have the same id.
|
||||
#
|
||||
# The first describe level is the 'type' field.
|
||||
# The second describe level is the 'domain' field.
|
||||
# The third describe level is the 'payload' field.
|
||||
#
|
||||
# These tests are not intended to show *every* possible configuration and
|
||||
# combination of commands. They are simplified commands that will test the
|
||||
# basic workings of the server. They should be used as a guide for constructing
|
||||
# commands sent to the server though and are helpful in defining the interface
|
||||
# that we will use.
|
||||
#
|
||||
# (Applicable to the second half of the file)
|
||||
# Note that the update, event and error types are meant to come *only* from
|
||||
# the server and not from the client. This means that those responses are
|
||||
# tested using other commands to create them. These are more 'behavioral'
|
||||
# tests than just demonstrations of how to construct requests and the
|
||||
# possible combinations of options.
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
require 'socket'
|
||||
require 'json'
|
||||
|
||||
HOSTNAME = 'localhost'
|
||||
PORT = 2000
|
||||
|
||||
RSpec.describe "app.rb" do
|
||||
let(:client) {TCPSocket.open(HOSTNAME, PORT)}
|
||||
it 'responds with an error when a non JSON request is sent' do
|
||||
client.puts 'this is non json test data'
|
||||
expect(JSON.parse(client.gets)).to eq({'type' => 'error', 'domain' => 'error', 'payload' => 'Server unable to decode JSON'})
|
||||
end
|
||||
|
||||
describe 'type: hello' do
|
||||
describe 'domain: player' do
|
||||
describe 'payload: player_id, faction' do
|
||||
it 'Connects the player:' do
|
||||
client.puts({'type' => 'hello', 'domain' => 'player', 'payload' => {'player_id' => 'test_player', 'faction' => 'good'}}.to_json)
|
||||
expect(JSON.parse(client.gets)).to eq('')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'type: query' do
|
||||
end
|
||||
|
||||
describe 'type: command' do
|
||||
end
|
||||
|
||||
# Note that the update, event and error types are meant to come *only* from
|
||||
# the server and not from the client. This means that those responses are
|
||||
# tested using other commands to create them. These are more 'behavioral'
|
||||
# tests than just demonstrations of how to construct requests and the
|
||||
# possible combinations of options.
|
||||
|
||||
describe 'type: update' do
|
||||
end
|
||||
|
||||
describe 'type: event' do
|
||||
end
|
||||
|
||||
describe 'type: error' do
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,252 @@
|
||||
# Nathan Hinton Jan 8 2026
|
||||
# Test file for the buildings in the game
|
||||
|
||||
require 'game/building'
|
||||
|
||||
RSpec.describe Building do
|
||||
let(:player) {instance_double(
|
||||
'Player',
|
||||
ship_build_power: 0,
|
||||
research_tech_build_power: 0,
|
||||
military_tech_build_power: 0,
|
||||
player_resources: {
|
||||
'metal' => 20_000,
|
||||
'crystals' => 20_000,
|
||||
'fuel' => 20_000,
|
||||
'credits' => 20_000},
|
||||
all_buildings: [],
|
||||
all_tech: []
|
||||
)}
|
||||
|
||||
let(:planet) {instance_double(
|
||||
'Planet',
|
||||
owner: player
|
||||
)}
|
||||
|
||||
let(:anti_gravity_thrusters_1) {instance_double('Tech',
|
||||
name: 'Anti Gravity Thrusters 1'
|
||||
)}
|
||||
let(:anti_gravity_thrusters_2) {instance_double('Tech',
|
||||
name: 'Anti Gravity Thrusters 2'
|
||||
)}
|
||||
|
||||
|
||||
before(:all) do
|
||||
end
|
||||
|
||||
describe '#initialize & #validate_building' do
|
||||
it 'Can construct any of level one mining buildings' do
|
||||
expect{Building.new(player, planet, 'Metal Mines 1')}.to_not raise_error
|
||||
end
|
||||
|
||||
it 'Can construct basic factory buildings' do
|
||||
expect{Building.new(player, planet, 'Shipyard Level 1')}.to_not raise_error
|
||||
end
|
||||
|
||||
it 'Can construct second level factory buildings' do
|
||||
allow(player).to receive(:all_buildings).and_return([Building.new(player, planet, 'Shipyard Level 1')])
|
||||
expect{Building.new(player, planet, 'Shipyard Level 2')}.to_not raise_error
|
||||
end
|
||||
|
||||
it 'Can construct third level (dependency check) buildings' do
|
||||
allow(player).to receive(:all_tech).and_return([anti_gravity_thrusters_1, anti_gravity_thrusters_2]) # Required tech for buildings
|
||||
allow(player).to receive(:all_buildings).and_return([Building.new(player, planet, 'Shipyard Level 1')]) # Building the second level requires the first first :)
|
||||
allow(player).to receive(:all_buildings).and_return([Building.new(player, planet, 'Shipyard Level 2'), Building.new(player, planet, 'Space Construction Station Level 1')])
|
||||
expect{Building.new(player, planet, 'Space Construction Station Level 2')}.to_not raise_error
|
||||
end
|
||||
|
||||
it 'Raises an error when trying to build a building that does not have the required buildings' do
|
||||
expect{Building.new(player, planet, 'Shipyard Level 2')}.to raise_error(BuildingError, 'Requires `Shipyard Level 1` first')
|
||||
end
|
||||
|
||||
it 'Raises an error when trying to build a building that does not have the required tech' do
|
||||
allow(player).to receive(:all_buildings).and_return([Building.new(player, planet, 'Shipyard Level 1')]) # Building the second level requires the first first :)
|
||||
expect{Building.new(player, planet, 'Space Construction Station Level 1')}.to raise_error(BuildingError, 'Requires the tech of `Anti Gravity Thrusters 1` first')
|
||||
end
|
||||
|
||||
it 'Raises an error when the player does not own the planet' do
|
||||
allow(planet).to receive(:owner).and_return(nil)
|
||||
expect{Building.new(player, planet, 'Shipyard Level 1')}.to raise_error(BuildingError, 'Player does not own planet!')
|
||||
end
|
||||
|
||||
it 'Raises an error if the player does not have the required credits' do
|
||||
allow(player).to receive(:player_resources).and_return(
|
||||
{
|
||||
'metal' => 20_000,
|
||||
'crystals' => 20_000,
|
||||
'fuel' => 20_000,
|
||||
'credits' => 0}
|
||||
)
|
||||
expect{Building.new(player, planet, 'Shipyard Level 1')}.to raise_error(BuildingError, 'Player does not have enough credits!')
|
||||
end
|
||||
|
||||
it 'Raises an error if the player does not have enough metal' do
|
||||
allow(player).to receive(:player_resources).and_return(
|
||||
{
|
||||
'metal' => 0,
|
||||
'crystals' => 20_000,
|
||||
'fuel' => 20_000,
|
||||
'credits' => 20_000}
|
||||
)
|
||||
expect{Building.new(player, planet, 'Shipyard Level 1')}.to raise_error(BuildingError, 'Player does not have enough metal!')
|
||||
end
|
||||
|
||||
it 'Raises an error if the player does not have enough fuel' do
|
||||
allow(player).to receive(:player_resources).and_return(
|
||||
{
|
||||
'metal' => 20_000,
|
||||
'crystals' => 20_000,
|
||||
'fuel' => 0,
|
||||
'credits' => 20_000}
|
||||
)
|
||||
expect{Building.new(player, planet, 'Shipyard Level 1')}.to raise_error(BuildingError, 'Player does not have enough fuel!')
|
||||
end
|
||||
|
||||
it 'Raises an error if the player does not have enough crystals' do
|
||||
allow(player).to receive(:player_resources).and_return(
|
||||
{
|
||||
'metal' => 20_000,
|
||||
'crystals' => 0,
|
||||
'fuel' => 20_000,
|
||||
'credits' => 20_000}
|
||||
)
|
||||
expect{Building.new(player, planet, 'Shipyard Level 1')}.to raise_error(BuildingError, 'Player does not have enough crystals!')
|
||||
end
|
||||
|
||||
it 'Raises an error if the building does not exist' do
|
||||
expect{Building.new(player, planet, 'billy bob joe')}.to raise_error(BuildingError, 'Invalid building name `billy bob joe`')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update/#produce_resources' do
|
||||
|
||||
before(:each) do
|
||||
allow(player).to receive(:ship_build_power=)
|
||||
allow(player).to receive(:research_tech_build_power=)
|
||||
allow(player).to receive(:military_tech_build_power=)
|
||||
end
|
||||
|
||||
describe 'Harvesting building produces resources' do
|
||||
it 'Metal Mines' do
|
||||
building = Building.new(player, planet, 'Metal Mines 1')
|
||||
# Ensure the building is built:
|
||||
building.instance_variable_set(:@building_exist_time, 10000)
|
||||
building.update(1.0)
|
||||
expect(player.player_resources).to eq(
|
||||
{
|
||||
'metal' => 19_500,
|
||||
'crystals' => 19_140,
|
||||
'fuel' => 19_000,
|
||||
'credits' => 18_960
|
||||
})
|
||||
end
|
||||
it 'Crystal Collector' do
|
||||
building = Building.new(player, planet, 'Crystal Collector 1')
|
||||
# Ensure the building is built:
|
||||
building.instance_variable_set(:@building_exist_time, 10000)
|
||||
building.update(1.0)
|
||||
expect(player.player_resources).to eq(
|
||||
{
|
||||
'crystals' => 19_500,
|
||||
'fuel' => 19_140,
|
||||
'credits' => 19_000,
|
||||
'metal' => 18_960
|
||||
})
|
||||
end
|
||||
it 'Fuel Refinery' do
|
||||
building = Building.new(player, planet, 'Fuel Refinery 1')
|
||||
# Ensure the building is built:
|
||||
building.instance_variable_set(:@building_exist_time, 10000)
|
||||
building.update(1.0)
|
||||
expect(player.player_resources).to eq(
|
||||
{
|
||||
'fuel' => 19_500,
|
||||
'credits' => 19_140,
|
||||
'metal' => 19_000,
|
||||
'crystals' => 18_960
|
||||
})
|
||||
end
|
||||
it 'Credit Center' do
|
||||
building = Building.new(player, planet, 'Credit Center 1')
|
||||
# Ensure the building is built:
|
||||
building.instance_variable_set(:@building_exist_time, 10000)
|
||||
building.update(1.0)
|
||||
expect(player.player_resources).to eq(
|
||||
{
|
||||
'credits' => 19_500,
|
||||
'metal' => 19_140,
|
||||
'crystals' => 19_000,
|
||||
'fuel' => 18_960
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
it 'Does not produce when there are not enough resources for upkeep' do
|
||||
start_resources = {
|
||||
'metal' => 1_010,
|
||||
'crystals' => 1_020,
|
||||
'fuel' => 1_030,
|
||||
'credits' => 1_040}
|
||||
|
||||
allow(player).to receive(:player_resources).and_return(start_resources)
|
||||
building = Building.new(player, planet, 'Credit Center 1')
|
||||
building.instance_variable_set(:@building_exist_time, 10000)
|
||||
expect{building.update(1.0)}.to raise_error(BuildingWarning, 'Player does not have enough metal to produce from Credit Center 1!')
|
||||
expect(player.player_resources).to eq(start_resources)
|
||||
end
|
||||
|
||||
it 'does not produce when it is not yet finished constructing' do
|
||||
building = Building.new(player, planet, 'Metal Mines 1')
|
||||
building.update(1.0)
|
||||
expect(player.player_resources).to eq(
|
||||
{
|
||||
'metal' => 19_000,
|
||||
'crystals' => 19_000,
|
||||
'fuel' => 19_000,
|
||||
'credits' => 19_000
|
||||
})
|
||||
end
|
||||
|
||||
it 'Having shipyard buildings allows the production of ships' do
|
||||
building = Building.new(player, planet, 'Shipyard Level 1')
|
||||
building.instance_variable_set(:@building_exist_time, 10000)
|
||||
building.update(1.0)
|
||||
expect(player).to have_received(:ship_build_power=).with(100)
|
||||
end
|
||||
|
||||
it 'Having research tech buildings allows the production of tech' do
|
||||
building = Building.new(player, planet, 'Research Factory Level 1')
|
||||
building.instance_variable_set(:@building_exist_time, 10000)
|
||||
building.update(1.0)
|
||||
expect(player).to have_received(:research_tech_build_power=).with(100)
|
||||
end
|
||||
|
||||
it 'Having military tech buildings allows the production of military tech' do
|
||||
allow(player).to receive(:all_buildings).and_return([Building.new(player, planet, 'Research Factory Level 1')])
|
||||
building = Building.new(player, planet, 'Military Factory Level 1')
|
||||
building.instance_variable_set(:@building_exist_time, 10000)
|
||||
building.update(1.0)
|
||||
expect(player).to have_received(:military_tech_build_power=).with(100)
|
||||
end
|
||||
|
||||
it 'Is in production for the right amount of time' do
|
||||
building = Building.new(player, planet, 'Metal Mines 1')
|
||||
building.update(1000.0)
|
||||
expect(player.player_resources).to eq(
|
||||
{
|
||||
'metal' => 19_000,
|
||||
'crystals' => 19_000,
|
||||
'fuel' => 19_000,
|
||||
'credits' => 19_000
|
||||
})
|
||||
building.update(1.0)
|
||||
expect(player.player_resources).to eq(
|
||||
{
|
||||
'metal' => 19_500,
|
||||
'crystals' => 19_140,
|
||||
'fuel' => 19_000,
|
||||
'credits' => 18_960
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -70,7 +70,7 @@ module Game
|
||||
|
||||
it 're-connects the player and returns success' do
|
||||
cmd = { 'payload' => { 'player_id' => player_id, 'faction' => 'good' } }
|
||||
expect(game.player_connect(client_socket, cmd)).to eq('status' => 'success')
|
||||
expect(game.player_connect(client_socket, cmd)).to eq({"payload"=>"success", "type"=>"update"})
|
||||
expect(existing_player).to have_received(:connect).with(client_socket)
|
||||
end
|
||||
end
|
||||
@@ -103,7 +103,7 @@ module Game
|
||||
it 'creates a new player, connects them, and adds them to #players' do
|
||||
cmd = { 'payload' => { 'player_id' => player_id, 'faction' => 'evil'} }
|
||||
response = game.player_connect(client_socket, cmd)
|
||||
expect(response).to eq('status' => 'success')
|
||||
expect(response).to eq({"payload"=>"success", "type"=>"update"})
|
||||
expect(game.players).to include(an_object_having_attributes(player_id:))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -61,6 +61,13 @@ RSpec.describe Planet do
|
||||
end
|
||||
end
|
||||
|
||||
describe '#info_update' do
|
||||
it 'returns the correct data about the planet to the player' do
|
||||
data = planet.info_update
|
||||
expect(data.keys).to eq(['id', 'position'])
|
||||
end
|
||||
end
|
||||
|
||||
describe '#save_to_file' do
|
||||
it 'saves the planet to a file' do
|
||||
expect{planet.save_to_file}.to_not raise_error
|
||||
|
||||
@@ -166,7 +166,7 @@ RSpec.describe Player do
|
||||
|
||||
before do
|
||||
subject.create_new(credits, metal, crystals, fuel)
|
||||
subject.player_planets << double('planet')
|
||||
subject.player_planets << double('planet', info_update: 'test_data')
|
||||
subject.player_ships << double('ship')
|
||||
end
|
||||
|
||||
@@ -177,7 +177,7 @@ RSpec.describe Player do
|
||||
'request_id' => request_id,
|
||||
'payload' => {
|
||||
'resources' => subject.player_resources,
|
||||
'planets' => subject.player_planets,
|
||||
'planets' => ['test_data'],
|
||||
'ships' => subject.player_ships
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,9 @@ RSpec.describe Ship do
|
||||
expect(ship.owner).to eq 'nathan'
|
||||
expect(ship.position).to eq [0, 2, 4]
|
||||
end
|
||||
end
|
||||
|
||||
describe '#validate_creation' do
|
||||
it 'Fails to create a ship when the name is invalid' do
|
||||
expect{Ship.new('nathan', 0, 2, 4, 'billy bob joe')}.to raise_error ShipError, "invalid ship name 'billy bob joe'"
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user