termfront 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +41 -0
- data/LICENSE +21 -0
- data/LICENSE.txt +21 -0
- data/README.md +160 -0
- data/Rakefile +12 -0
- data/data/audio/THIRD_PARTY_NOTICES.md +45 -0
- data/data/audio/beep_02.ogg +0 -0
- data/data/audio/button1.ogg +0 -0
- data/data/audio/complete.ogg +0 -0
- data/data/audio/manifest.json +17 -0
- data/data/audio/mission_bgm.wav +0 -0
- data/data/audio/mission_clear_se.wav +0 -0
- data/data/audio/on.ogg +0 -0
- data/data/audio/page_se.wav +0 -0
- data/data/audio/sector.mp3 +0 -0
- data/data/audio/sfx_22b.ogg +0 -0
- data/data/audio/shield_alarm_se.wav +0 -0
- data/data/audio/shield_regen_se.wav +0 -0
- data/data/audio/shoot_01.ogg +0 -0
- data/data/audio/terminal_se.wav +0 -0
- data/data/audio/title.mp3 +0 -0
- data/data/audio/title_bgm.wav +0 -0
- data/data/audio/victory.mp3 +0 -0
- data/data/events/corridor_sweep.json +27 -0
- data/data/events/final_push.json +40 -0
- data/data/events/stronghold.json +27 -0
- data/data/events/the_gauntlet.json +27 -0
- data/data/events/training_grounds.json +31 -0
- data/exe/termfront +6 -0
- data/exe/termfront-server +7 -0
- data/lib/termfront/audio_manager.rb +225 -0
- data/lib/termfront/config.rb +38 -0
- data/lib/termfront/demo_player.rb +181 -0
- data/lib/termfront/drop_item/base.rb +26 -0
- data/lib/termfront/drop_item/weapon.rb +38 -0
- data/lib/termfront/enemy/base.rb +133 -0
- data/lib/termfront/enemy/crawler.rb +18 -0
- data/lib/termfront/enemy/executor.rb +18 -0
- data/lib/termfront/game.rb +637 -0
- data/lib/termfront/input.rb +75 -0
- data/lib/termfront/map.rb +72 -0
- data/lib/termfront/mission/base.rb +81 -0
- data/lib/termfront/mission/corridor_sweep.rb +41 -0
- data/lib/termfront/mission/event_loader.rb +87 -0
- data/lib/termfront/mission/event_runtime.rb +37 -0
- data/lib/termfront/mission/final_push.rb +44 -0
- data/lib/termfront/mission/stronghold.rb +45 -0
- data/lib/termfront/mission/the_gauntlet.rb +38 -0
- data/lib/termfront/mission/training.rb +38 -0
- data/lib/termfront/mission/training_grounds.rb +37 -0
- data/lib/termfront/network/client.rb +865 -0
- data/lib/termfront/network/connection.rb +101 -0
- data/lib/termfront/network/server.rb +620 -0
- data/lib/termfront/network/wavesfight_client.rb +364 -0
- data/lib/termfront/opponent.rb +24 -0
- data/lib/termfront/player.rb +147 -0
- data/lib/termfront/projectile.rb +44 -0
- data/lib/termfront/remote_enemy.rb +21 -0
- data/lib/termfront/renderer.rb +707 -0
- data/lib/termfront/scene_player.rb +164 -0
- data/lib/termfront/sprite.rb +73 -0
- data/lib/termfront/terminal_output.rb +63 -0
- data/lib/termfront/title_screen.rb +299 -0
- data/lib/termfront/version.rb +5 -0
- data/lib/termfront/weapon/assault_rifle.rb +15 -0
- data/lib/termfront/weapon/base.rb +44 -0
- data/lib/termfront/weapon/pistol.rb +15 -0
- data/lib/termfront/weapon/shock_pistol.rb +15 -0
- data/lib/termfront/weapon/shock_rifle.rb +15 -0
- data/lib/termfront.rb +51 -0
- data/sig/termfront.rbs +4 -0
- metadata +119 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Termfront
|
|
4
|
+
class Map
|
|
5
|
+
attr_reader :grid, :width, :height
|
|
6
|
+
|
|
7
|
+
def initialize(rows)
|
|
8
|
+
@grid = rows.map { |r| r.is_a?(Array) ? r : r.chars }
|
|
9
|
+
@height = @grid.size
|
|
10
|
+
@width = @grid[0].size
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def wall_at?(fx, fy)
|
|
14
|
+
ix = fx.floor
|
|
15
|
+
iy = fy.floor
|
|
16
|
+
return true if iy < 0 || iy >= @height || ix < 0 || ix >= @width
|
|
17
|
+
|
|
18
|
+
@grid[iy][ix] == "#"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def blocked?(px, py, radius = Config::PLAYER_RADIUS)
|
|
22
|
+
wall_at?(px - radius, py - radius) || wall_at?(px + radius, py - radius) ||
|
|
23
|
+
wall_at?(px - radius, py + radius) || wall_at?(px + radius, py + radius)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def line_of_sight?(x1, y1, x2, y2)
|
|
27
|
+
dx = x2 - x1
|
|
28
|
+
dy = y2 - y1
|
|
29
|
+
dist = Math.sqrt(dx * dx + dy * dy)
|
|
30
|
+
return true if dist < 0.01
|
|
31
|
+
|
|
32
|
+
dx /= dist
|
|
33
|
+
dy /= dist
|
|
34
|
+
|
|
35
|
+
mx = x1.floor
|
|
36
|
+
my = y1.floor
|
|
37
|
+
ddx = dx == 0 ? 1e30 : (1.0 / dx).abs
|
|
38
|
+
ddy = dy == 0 ? 1e30 : (1.0 / dy).abs
|
|
39
|
+
|
|
40
|
+
if dx < 0
|
|
41
|
+
step_x = -1
|
|
42
|
+
sd_x = (x1 - mx) * ddx
|
|
43
|
+
else
|
|
44
|
+
step_x = 1
|
|
45
|
+
sd_x = (mx + 1.0 - x1) * ddx
|
|
46
|
+
end
|
|
47
|
+
if dy < 0
|
|
48
|
+
step_y = -1
|
|
49
|
+
sd_y = (y1 - my) * ddy
|
|
50
|
+
else
|
|
51
|
+
step_y = 1
|
|
52
|
+
sd_y = (my + 1.0 - y1) * ddy
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
loop do
|
|
56
|
+
if sd_x < sd_y
|
|
57
|
+
return true if sd_x > dist
|
|
58
|
+
|
|
59
|
+
sd_x += ddx
|
|
60
|
+
mx += step_x
|
|
61
|
+
else
|
|
62
|
+
return true if sd_y > dist
|
|
63
|
+
|
|
64
|
+
sd_y += ddy
|
|
65
|
+
my += step_y
|
|
66
|
+
end
|
|
67
|
+
return false if my < 0 || my >= @height || mx < 0 || mx >= @width
|
|
68
|
+
return false if @grid[my][mx] == "#"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Termfront
|
|
4
|
+
module Mission
|
|
5
|
+
class Base
|
|
6
|
+
def id
|
|
7
|
+
self.class.name.split("::").last
|
|
8
|
+
.gsub(/([a-z0-9])([A-Z])/, '\1_\2')
|
|
9
|
+
.downcase
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def name = raise(NotImplementedError)
|
|
13
|
+
def briefing = raise(NotImplementedError)
|
|
14
|
+
def map_data = raise(NotImplementedError)
|
|
15
|
+
def spawn = raise(NotImplementedError)
|
|
16
|
+
def weapon_defs = raise(NotImplementedError)
|
|
17
|
+
def enemy_defs = raise(NotImplementedError)
|
|
18
|
+
|
|
19
|
+
def events_path
|
|
20
|
+
File.expand_path("../../../data/events/#{id}.json", __dir__)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def event_definitions
|
|
24
|
+
@event_definitions ||= EventLoader.load_file(events_path)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def build_terminals
|
|
28
|
+
terminal_ids = event_definitions.filter_map do |event|
|
|
29
|
+
trigger = event[:trigger]
|
|
30
|
+
trigger[:terminal_id] if trigger[:type] == :terminal_used
|
|
31
|
+
end.uniq
|
|
32
|
+
|
|
33
|
+
map_data.each_with_index.filter_map do |row, y|
|
|
34
|
+
row.chars.each_with_index.filter_map do |cell, x|
|
|
35
|
+
next unless cell == "*"
|
|
36
|
+
|
|
37
|
+
{ id: (terminal_ids.shift || :"terminal_#{x}_#{y}"), x: x + 0.5, y: y + 0.5 }
|
|
38
|
+
end
|
|
39
|
+
end.flatten
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def build_map
|
|
43
|
+
Map.new(map_data)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def build_weapons
|
|
47
|
+
weapon_defs.map { |type, ammo| Weapon::Base.build(type, ammo) }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def build_enemies(difficulty_index)
|
|
51
|
+
enemies = enemy_defs.map do |ed|
|
|
52
|
+
type = ed[4]
|
|
53
|
+
Enemy::Base.build(type, ed, difficulty_index)
|
|
54
|
+
end
|
|
55
|
+
if difficulty_index
|
|
56
|
+
extra = Enemy::Base::DIFFICULTIES[difficulty_index][:extra_enemies]
|
|
57
|
+
enemies += Enemy::Base.generate_extras(enemy_defs, extra, difficulty_index)
|
|
58
|
+
end
|
|
59
|
+
enemies
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class << self
|
|
63
|
+
def campaign
|
|
64
|
+
@campaign ||= []
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def wavesfight
|
|
68
|
+
@wavesfight ||= []
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def register(klass)
|
|
72
|
+
campaign << klass
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def register_wavesfight(klass)
|
|
76
|
+
wavesfight << klass
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Termfront
|
|
4
|
+
module Mission
|
|
5
|
+
class CorridorSweep < Base
|
|
6
|
+
def name = "Corridor Sweep"
|
|
7
|
+
def briefing = "Sweep the original facility. Expect resistance."
|
|
8
|
+
|
|
9
|
+
def map_data
|
|
10
|
+
[
|
|
11
|
+
"########################",
|
|
12
|
+
"#..........#...........#",
|
|
13
|
+
"#..........#...........#",
|
|
14
|
+
"#..........#...........#",
|
|
15
|
+
"#..........#...........#",
|
|
16
|
+
"#......................#",
|
|
17
|
+
"#..........####........#",
|
|
18
|
+
"#......................#",
|
|
19
|
+
"#..............#.......#",
|
|
20
|
+
"#..............#.......#",
|
|
21
|
+
"########################"
|
|
22
|
+
]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def spawn = [10.0, 6.0, 0.0]
|
|
26
|
+
def weapon_defs = [[:ar, 60], [:pistol, nil]]
|
|
27
|
+
|
|
28
|
+
def enemy_defs
|
|
29
|
+
[
|
|
30
|
+
[16.5, 1.5, 16.5, 4.5, :executor],
|
|
31
|
+
[5.5, 8.5, 9.5, 8.5, :crawler],
|
|
32
|
+
[20.5, 5.5, 20.5, 9.5, :crawler],
|
|
33
|
+
[3.5, 2.5, 3.5, 4.5, :crawler]
|
|
34
|
+
]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
Base.register(CorridorSweep)
|
|
39
|
+
Base.register_wavesfight(CorridorSweep)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module Termfront
|
|
6
|
+
module Mission
|
|
7
|
+
module EventLoader
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def load_file(path)
|
|
11
|
+
return [] unless File.file?(path)
|
|
12
|
+
|
|
13
|
+
doc = JSON.parse(File.read(path))
|
|
14
|
+
events = doc.fetch("events") do
|
|
15
|
+
raise ArgumentError, "event file #{path} is missing top-level events array"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
unless events.is_a?(Array)
|
|
19
|
+
raise ArgumentError, "event file #{path} must define events as an array"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
events.map.with_index do |event, index|
|
|
23
|
+
validate_event!(event, path, index)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def validate_event!(event, path, index)
|
|
28
|
+
unless event.is_a?(Hash)
|
|
29
|
+
raise ArgumentError, "event #{index} in #{path} must be an object"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
id = event["id"]
|
|
33
|
+
trigger = event["trigger"]
|
|
34
|
+
actions = event["actions"]
|
|
35
|
+
|
|
36
|
+
raise ArgumentError, "event #{index} in #{path} is missing id" if blank?(id)
|
|
37
|
+
raise ArgumentError, "event #{id} in #{path} is missing trigger" unless trigger.is_a?(Hash)
|
|
38
|
+
raise ArgumentError, "event #{id} in #{path} is missing actions" unless actions.is_a?(Array) && !actions.empty?
|
|
39
|
+
|
|
40
|
+
trigger_type = trigger["type"]
|
|
41
|
+
raise ArgumentError, "event #{id} in #{path} trigger is missing type" if blank?(trigger_type)
|
|
42
|
+
|
|
43
|
+
normalized_actions = actions.map.with_index do |action, action_index|
|
|
44
|
+
validate_action!(action, path, id, action_index)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
normalized_trigger = symbolize_keys(trigger).merge(type: trigger_type.to_sym)
|
|
48
|
+
normalized_trigger[:terminal_id] = normalized_trigger[:terminal_id].to_sym if normalized_trigger[:terminal_id].is_a?(String)
|
|
49
|
+
|
|
50
|
+
{
|
|
51
|
+
id: id,
|
|
52
|
+
once: event.fetch("once", true),
|
|
53
|
+
trigger: normalized_trigger,
|
|
54
|
+
actions: normalized_actions
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def validate_action!(action, path, event_id, index)
|
|
59
|
+
unless action.is_a?(Hash)
|
|
60
|
+
raise ArgumentError, "action #{index} in event #{event_id} (#{path}) must be an object"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
type = action["type"]
|
|
64
|
+
raise ArgumentError, "action #{index} in event #{event_id} (#{path}) is missing type" if blank?(type)
|
|
65
|
+
|
|
66
|
+
symbolize_keys(action).merge(type: type.to_sym)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def symbolize_keys(value)
|
|
70
|
+
case value
|
|
71
|
+
when Array
|
|
72
|
+
value.map { |item| symbolize_keys(item) }
|
|
73
|
+
when Hash
|
|
74
|
+
value.each_with_object({}) do |(key, item), memo|
|
|
75
|
+
memo[key.to_sym] = symbolize_keys(item)
|
|
76
|
+
end
|
|
77
|
+
else
|
|
78
|
+
value
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def blank?(value)
|
|
83
|
+
value.nil? || value == ""
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "set"
|
|
4
|
+
|
|
5
|
+
module Termfront
|
|
6
|
+
module Mission
|
|
7
|
+
class EventRuntime
|
|
8
|
+
def initialize(events)
|
|
9
|
+
@events = events
|
|
10
|
+
@fired = Set.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def trigger(type, payload = {})
|
|
14
|
+
normalized_type = type.to_sym
|
|
15
|
+
normalized_payload = payload.transform_keys(&:to_sym)
|
|
16
|
+
|
|
17
|
+
@events.filter_map do |event|
|
|
18
|
+
next if event[:once] && @fired.include?(event[:id])
|
|
19
|
+
next unless matches?(event[:trigger], normalized_type, normalized_payload)
|
|
20
|
+
|
|
21
|
+
@fired << event[:id] if event[:once]
|
|
22
|
+
event
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def matches?(trigger, type, payload)
|
|
29
|
+
return false unless trigger[:type] == type
|
|
30
|
+
|
|
31
|
+
trigger.all? do |key, value|
|
|
32
|
+
key == :type || payload[key] == value
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Termfront
|
|
4
|
+
module Mission
|
|
5
|
+
class FinalPush < Base
|
|
6
|
+
def name = "Final Push"
|
|
7
|
+
def briefing = "Storm the fortress. Maximum resistance. Good luck."
|
|
8
|
+
|
|
9
|
+
def map_data
|
|
10
|
+
[
|
|
11
|
+
"##########################",
|
|
12
|
+
"#............#...........#",
|
|
13
|
+
"#............#...........#",
|
|
14
|
+
"#............#...........#",
|
|
15
|
+
"#...........*............#",
|
|
16
|
+
"#............#...........#",
|
|
17
|
+
"#............#..####..####",
|
|
18
|
+
"####..########..#........#",
|
|
19
|
+
"#...............#........#",
|
|
20
|
+
"#...........*...#........#",
|
|
21
|
+
"#...............#........#",
|
|
22
|
+
"##########################"
|
|
23
|
+
]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def spawn = [2.5, 2.5, 0.0]
|
|
27
|
+
def weapon_defs = [[:ar, 60], [:pistol, nil]]
|
|
28
|
+
|
|
29
|
+
def enemy_defs
|
|
30
|
+
[
|
|
31
|
+
[8.5, 2.5, 8.5, 5.5, :executor],
|
|
32
|
+
[4.5, 9.5, 4.5, 8.5, :crawler],
|
|
33
|
+
[10.5, 9.5, 10.5, 8.5, :crawler],
|
|
34
|
+
[18.5, 2.5, 18.5, 5.5, :executor],
|
|
35
|
+
[22.5, 8.5, 22.5, 10.5, :executor],
|
|
36
|
+
[16.5, 9.5, 16.5, 8.5, :crawler]
|
|
37
|
+
]
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
Base.register(FinalPush)
|
|
42
|
+
Base.register_wavesfight(FinalPush)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Termfront
|
|
4
|
+
module Mission
|
|
5
|
+
class Stronghold < Base
|
|
6
|
+
def name = "Stronghold"
|
|
7
|
+
def briefing = "Multi-room stronghold. Executors guard the inner rooms."
|
|
8
|
+
|
|
9
|
+
def map_data
|
|
10
|
+
[
|
|
11
|
+
"####################",
|
|
12
|
+
"#........#.........#",
|
|
13
|
+
"#........#.........#",
|
|
14
|
+
"#........#.........#",
|
|
15
|
+
"#...........*......#",
|
|
16
|
+
"#........#.........#",
|
|
17
|
+
"#........#.........#",
|
|
18
|
+
"####..####.........#",
|
|
19
|
+
"#........#.........#",
|
|
20
|
+
"#........#.........#",
|
|
21
|
+
"#................*.#",
|
|
22
|
+
"#........#.........#",
|
|
23
|
+
"#........#.........#",
|
|
24
|
+
"####################"
|
|
25
|
+
]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def spawn = [2.5, 2.5, 0.0]
|
|
29
|
+
def weapon_defs = [[:ar, 60], [:pistol, nil]]
|
|
30
|
+
|
|
31
|
+
def enemy_defs
|
|
32
|
+
[
|
|
33
|
+
[5.5, 5.5, 5.5, 2.5, :crawler],
|
|
34
|
+
[14.5, 2.5, 14.5, 5.5, :executor],
|
|
35
|
+
[3.5, 10.5, 3.5, 12.5, :crawler],
|
|
36
|
+
[14.5, 9.5, 14.5, 12.5, :executor],
|
|
37
|
+
[10.5, 11.5, 15.5, 11.5, :crawler]
|
|
38
|
+
]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
Base.register(Stronghold)
|
|
43
|
+
Base.register_wavesfight(Stronghold)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Termfront
|
|
4
|
+
module Mission
|
|
5
|
+
class TheGauntlet < Base
|
|
6
|
+
def name = "The Gauntlet"
|
|
7
|
+
def briefing = "A long corridor with enemies in every room."
|
|
8
|
+
|
|
9
|
+
def map_data
|
|
10
|
+
[
|
|
11
|
+
"##############################",
|
|
12
|
+
"#.....#.....#.....#.....#....#",
|
|
13
|
+
"#.....#.....#.....#.....#....#",
|
|
14
|
+
"#...........*...........*....#",
|
|
15
|
+
"#.....#.....#.....#.....#....#",
|
|
16
|
+
"#.....#.....#.....#.....#....#",
|
|
17
|
+
"#.....#.....#.....#.....#....#",
|
|
18
|
+
"##############################"
|
|
19
|
+
]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def spawn = [2.5, 3.5, 0.0]
|
|
23
|
+
def weapon_defs = [[:ar, 60], [:pistol, nil]]
|
|
24
|
+
|
|
25
|
+
def enemy_defs
|
|
26
|
+
[
|
|
27
|
+
[4.5, 2.5, 4.5, 5.5, :crawler],
|
|
28
|
+
[8.5, 5.5, 8.5, 2.5, :crawler],
|
|
29
|
+
[14.5, 2.5, 14.5, 5.5, :crawler],
|
|
30
|
+
[20.5, 5.5, 20.5, 2.5, :crawler],
|
|
31
|
+
[26.5, 2.5, 26.5, 5.5, :crawler]
|
|
32
|
+
]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
Base.register(TheGauntlet)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Termfront
|
|
4
|
+
module Mission
|
|
5
|
+
class Training < Base
|
|
6
|
+
def name = "Training"
|
|
7
|
+
def briefing = "Practice mode. Sweep the facility."
|
|
8
|
+
|
|
9
|
+
def map_data
|
|
10
|
+
[
|
|
11
|
+
"########################",
|
|
12
|
+
"#..........#...........#",
|
|
13
|
+
"#..........#...........#",
|
|
14
|
+
"#..........#...........#",
|
|
15
|
+
"#..........#...........#",
|
|
16
|
+
"#......................#",
|
|
17
|
+
"#..........####........#",
|
|
18
|
+
"#......................#",
|
|
19
|
+
"#..............#.......#",
|
|
20
|
+
"#..............#.......#",
|
|
21
|
+
"########################"
|
|
22
|
+
]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def spawn = [10.0, 6.0, 0.0]
|
|
26
|
+
def weapon_defs = [[:ar, 60], [:pistol, nil]]
|
|
27
|
+
|
|
28
|
+
def enemy_defs
|
|
29
|
+
[
|
|
30
|
+
[16.5, 1.5, 16.5, 4.5, :executor],
|
|
31
|
+
[5.5, 8.5, 9.5, 8.5, :crawler],
|
|
32
|
+
[20.5, 5.5, 20.5, 9.5, :crawler],
|
|
33
|
+
[3.5, 2.5, 3.5, 4.5, :crawler]
|
|
34
|
+
]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Termfront
|
|
4
|
+
module Mission
|
|
5
|
+
class TrainingGrounds < Base
|
|
6
|
+
def name = "Training Grounds"
|
|
7
|
+
def briefing = "Clear a small compound. Learn the basics."
|
|
8
|
+
|
|
9
|
+
def map_data
|
|
10
|
+
[
|
|
11
|
+
"################",
|
|
12
|
+
"#..............#",
|
|
13
|
+
"#..............#",
|
|
14
|
+
"#......##......#",
|
|
15
|
+
"#......##......#",
|
|
16
|
+
"#..............#",
|
|
17
|
+
"#..............#",
|
|
18
|
+
"#..............#",
|
|
19
|
+
"#..............#",
|
|
20
|
+
"################"
|
|
21
|
+
]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def spawn = [2.5, 5.0, 0.0]
|
|
25
|
+
def weapon_defs = [[:pistol, nil]]
|
|
26
|
+
|
|
27
|
+
def enemy_defs
|
|
28
|
+
[
|
|
29
|
+
[10.5, 3.5, 10.5, 6.5, :crawler],
|
|
30
|
+
[13.5, 7.5, 13.5, 2.5, :crawler]
|
|
31
|
+
]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
Base.register(TrainingGrounds)
|
|
36
|
+
end
|
|
37
|
+
end
|