doom 0.5.0 → 0.8.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 +4 -4
- data/README.md +43 -21
- data/bin/doom +10 -5
- data/lib/doom/game/combat.rb +325 -13
- data/lib/doom/game/intermission.rb +248 -0
- data/lib/doom/game/item_pickup.rb +40 -4
- data/lib/doom/game/menu.rb +342 -0
- data/lib/doom/game/monster_ai.rb +494 -0
- data/lib/doom/game/player_state.rb +53 -1
- data/lib/doom/game/sector_actions.rb +376 -15
- data/lib/doom/game/sound_engine.rb +201 -0
- data/lib/doom/platform/gosu_window.rb +589 -49
- data/lib/doom/render/font.rb +78 -0
- data/lib/doom/render/renderer.rb +395 -18
- data/lib/doom/render/screen_melt.rb +71 -0
- data/lib/doom/render/weapon_renderer.rb +11 -12
- data/lib/doom/version.rb +1 -1
- data/lib/doom/wad/reader.rb +52 -0
- data/lib/doom/wad/sound.rb +85 -0
- data/lib/doom/wad/sprite.rb +34 -8
- data/lib/doom/wad/texture.rb +1 -1
- data/lib/doom/wad_downloader.rb +10 -1
- data/lib/doom.rb +48 -4
- metadata +10 -3
|
@@ -7,13 +7,12 @@ module Doom
|
|
|
7
7
|
# Weapon is rendered above the status bar
|
|
8
8
|
WEAPON_AREA_HEIGHT = SCREEN_HEIGHT - StatusBar::STATUS_BAR_HEIGHT
|
|
9
9
|
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# We scale for our 240px screen vs DOOM's 200px.
|
|
10
|
+
# Chocolate Doom R_DrawPSprite weapon positioning:
|
|
11
|
+
# centery = viewheight/2 (view area excluding status bar)
|
|
12
|
+
# texturemid = centery - (WEAPONTOP - spritetopoffset)
|
|
13
|
+
# dc_yl = centery - texturemid (first visible row)
|
|
15
14
|
WEAPONTOP = 32
|
|
16
|
-
|
|
15
|
+
VIEW_CENTERY = (SCREEN_HEIGHT - StatusBar::STATUS_BAR_HEIGHT) / 2 # 104
|
|
17
16
|
|
|
18
17
|
def initialize(hud_graphics, player_state)
|
|
19
18
|
@gfx = hud_graphics
|
|
@@ -26,7 +25,7 @@ module Doom
|
|
|
26
25
|
return unless weapon_data
|
|
27
26
|
|
|
28
27
|
# Get the appropriate frame
|
|
29
|
-
sprite = if @player.attacking && weapon_data[:fire]
|
|
28
|
+
sprite = if @player.attacking && weapon_data[:fire]&.any?
|
|
30
29
|
frame = @player.attack_frame.clamp(0, weapon_data[:fire].length - 1)
|
|
31
30
|
weapon_data[:fire][frame]
|
|
32
31
|
else
|
|
@@ -39,11 +38,11 @@ module Doom
|
|
|
39
38
|
bob_x = @player.attacking ? 0 : @player.weapon_bob_x.to_i
|
|
40
39
|
bob_y = @player.attacking ? 0 : @player.weapon_bob_y.to_i
|
|
41
40
|
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
41
|
+
# Chocolate Doom on 200px: dc_yl = WEAPONTOP - topoffset
|
|
42
|
+
# Our view area is 208px (240-32 status bar) vs DOOM's 168px (200-32)
|
|
43
|
+
# Offset by half the extra height to keep weapon centered in view
|
|
45
44
|
x = 1 - sprite.left_offset + bob_x
|
|
46
|
-
y =
|
|
45
|
+
y = WEAPONTOP - sprite.top_offset + 20 + bob_y
|
|
47
46
|
|
|
48
47
|
draw_weapon_sprite(framebuffer, sprite, x, y)
|
|
49
48
|
|
|
@@ -90,7 +89,7 @@ module Doom
|
|
|
90
89
|
# Flash uses same positioning as weapon sprite (built-in offsets)
|
|
91
90
|
# Same positioning formula as weapon sprite
|
|
92
91
|
flash_x = 1 - flash_sprite.left_offset
|
|
93
|
-
flash_y =
|
|
92
|
+
flash_y = WEAPONTOP - flash_sprite.top_offset + 20
|
|
94
93
|
|
|
95
94
|
draw_weapon_sprite(framebuffer, flash_sprite, flash_x, flash_y)
|
|
96
95
|
end
|
data/lib/doom/version.rb
CHANGED
data/lib/doom/wad/reader.rb
CHANGED
|
@@ -45,8 +45,60 @@ module Doom
|
|
|
45
45
|
@directory[start_idx + 1...end_idx]
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
def pwad?
|
|
49
|
+
@type == PWAD
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def iwad?
|
|
53
|
+
@type == IWAD
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Merge a PWAD on top of this IWAD.
|
|
57
|
+
# PWAD lumps override IWAD lumps with the same name.
|
|
58
|
+
# Map lumps (between map markers) are replaced as a group.
|
|
59
|
+
def merge_pwad(pwad)
|
|
60
|
+
raise Error, "Can only merge a PWAD" unless pwad.pwad?
|
|
61
|
+
@lump_cache.clear
|
|
62
|
+
|
|
63
|
+
pwad.directory.each do |pwad_entry|
|
|
64
|
+
# Check if this lump already exists in the IWAD
|
|
65
|
+
existing_idx = @directory.index { |e| e.name == pwad_entry.name }
|
|
66
|
+
if existing_idx
|
|
67
|
+
# Replace it -- but we need to read from the PWAD file
|
|
68
|
+
@directory[existing_idx] = pwad_entry
|
|
69
|
+
else
|
|
70
|
+
# Append new lump
|
|
71
|
+
@directory << pwad_entry
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Keep the PWAD file open for reading its lumps
|
|
76
|
+
@pwad_files ||= []
|
|
77
|
+
@pwad_files << pwad
|
|
78
|
+
@num_lumps = @directory.size
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Override read_lump_at to check if entry belongs to a PWAD file
|
|
82
|
+
def read_lump_at(entry)
|
|
83
|
+
# Try PWAD files first (they may own this entry)
|
|
84
|
+
(@pwad_files || []).each do |pwad|
|
|
85
|
+
if pwad.directory.include?(entry)
|
|
86
|
+
return pwad.read_lump_own(entry)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
@file.seek(entry.offset)
|
|
90
|
+
@file.read(entry.size)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Read a lump that belongs to this WAD's own file
|
|
94
|
+
def read_lump_own(entry)
|
|
95
|
+
@file.seek(entry.offset)
|
|
96
|
+
@file.read(entry.size)
|
|
97
|
+
end
|
|
98
|
+
|
|
48
99
|
def close
|
|
49
100
|
@file.close
|
|
101
|
+
(@pwad_files || []).each(&:close)
|
|
50
102
|
end
|
|
51
103
|
|
|
52
104
|
private
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'tmpdir'
|
|
4
|
+
|
|
5
|
+
module Doom
|
|
6
|
+
module Wad
|
|
7
|
+
# Loads DOOM sound effects from WAD and converts to WAV for Gosu playback.
|
|
8
|
+
# DOOM sound format: 8-byte header (2 format, 2 sample_rate, 4 num_samples)
|
|
9
|
+
# followed by unsigned 8-bit PCM samples.
|
|
10
|
+
class SoundManager
|
|
11
|
+
def initialize(wad)
|
|
12
|
+
@wad = wad
|
|
13
|
+
@cache = {} # name => Gosu::Sample
|
|
14
|
+
@temp_dir = File.join(Dir.tmpdir, "doom_rb_sounds_#{Process.pid}")
|
|
15
|
+
Dir.mkdir(@temp_dir) unless Dir.exist?(@temp_dir)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Get or load a sound effect. Returns a Gosu::Sample or nil.
|
|
19
|
+
def [](name)
|
|
20
|
+
return @cache[name] if @cache.key?(name)
|
|
21
|
+
|
|
22
|
+
lump_name = name.start_with?('DS') ? name : "DS#{name}"
|
|
23
|
+
entry = @wad.find_lump(lump_name)
|
|
24
|
+
return @cache[name] = nil unless entry
|
|
25
|
+
|
|
26
|
+
data = @wad.read_lump_at(entry)
|
|
27
|
+
return @cache[name] = nil if data.size < 8
|
|
28
|
+
|
|
29
|
+
# Parse DOOM sound header
|
|
30
|
+
_format = data[0, 2].unpack1('v')
|
|
31
|
+
sample_rate = data[2, 2].unpack1('v')
|
|
32
|
+
num_samples = data[4, 4].unpack1('V')
|
|
33
|
+
|
|
34
|
+
# PCM data starts at offset 8, skip 16 padding bytes at start and end
|
|
35
|
+
pcm_start = 8 + 16
|
|
36
|
+
pcm_end = 8 + num_samples - 16
|
|
37
|
+
pcm_data = data[pcm_start...pcm_end]
|
|
38
|
+
return @cache[name] = nil unless pcm_data && pcm_data.size > 0
|
|
39
|
+
|
|
40
|
+
# Convert to WAV file for Gosu
|
|
41
|
+
wav_path = File.join(@temp_dir, "#{lump_name}.wav")
|
|
42
|
+
write_wav(wav_path, pcm_data, sample_rate) unless File.exist?(wav_path)
|
|
43
|
+
|
|
44
|
+
@cache[name] = Gosu::Sample.new(wav_path)
|
|
45
|
+
rescue => e
|
|
46
|
+
@cache[name] = nil
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def cleanup
|
|
50
|
+
FileUtils.rm_rf(@temp_dir) if @temp_dir && Dir.exist?(@temp_dir)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
# Write unsigned 8-bit PCM data as a WAV file
|
|
56
|
+
def write_wav(path, pcm_data, sample_rate)
|
|
57
|
+
num_samples = pcm_data.size
|
|
58
|
+
data_size = num_samples
|
|
59
|
+
file_size = 36 + data_size
|
|
60
|
+
|
|
61
|
+
File.open(path, 'wb') do |f|
|
|
62
|
+
# RIFF header
|
|
63
|
+
f.write("RIFF")
|
|
64
|
+
f.write([file_size].pack('V'))
|
|
65
|
+
f.write("WAVE")
|
|
66
|
+
|
|
67
|
+
# fmt chunk
|
|
68
|
+
f.write("fmt ")
|
|
69
|
+
f.write([16].pack('V')) # chunk size
|
|
70
|
+
f.write([1].pack('v')) # PCM format
|
|
71
|
+
f.write([1].pack('v')) # mono
|
|
72
|
+
f.write([sample_rate].pack('V')) # sample rate
|
|
73
|
+
f.write([sample_rate].pack('V')) # byte rate (sample_rate * 1 * 1)
|
|
74
|
+
f.write([1].pack('v')) # block align
|
|
75
|
+
f.write([8].pack('v')) # bits per sample
|
|
76
|
+
|
|
77
|
+
# data chunk
|
|
78
|
+
f.write("data")
|
|
79
|
+
f.write([data_size].pack('V'))
|
|
80
|
+
f.write(pcm_data)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
data/lib/doom/wad/sprite.rb
CHANGED
|
@@ -120,6 +120,12 @@ module Doom
|
|
|
120
120
|
48 => 'ELEC', # Tall tech column
|
|
121
121
|
35 => 'CBRA', # Candelabra
|
|
122
122
|
|
|
123
|
+
# Dead bodies / gore decorations
|
|
124
|
+
10 => 'PLAY', # Bloody mess
|
|
125
|
+
12 => 'PLAY', # Bloody mess 2
|
|
126
|
+
15 => 'PLAY', # Dead player
|
|
127
|
+
24 => 'POL5', # Pool of blood and flesh
|
|
128
|
+
|
|
123
129
|
# Barrels
|
|
124
130
|
2035 => 'BAR1', # Exploding barrel
|
|
125
131
|
|
|
@@ -136,6 +142,17 @@ module Doom
|
|
|
136
142
|
16 => 'CYBR', # Cyberdemon
|
|
137
143
|
}.freeze
|
|
138
144
|
|
|
145
|
+
# Things that use a specific frame instead of 'A'
|
|
146
|
+
# From DOOM info.h mobjinfo spawnstate:
|
|
147
|
+
# MT_MISC10 (type 10) -> S_PLAY_XDIE9 = PLAY W (gibbed mess)
|
|
148
|
+
# MT_MISC12 (type 12) -> S_PLAY_DIE7 = PLAY N (dead body)
|
|
149
|
+
# MT_MISC15 (type 15) -> S_PLAY_DIE7 = PLAY N (dead body)
|
|
150
|
+
THING_DEFAULT_FRAME = {
|
|
151
|
+
10 => 'W', # Bloody mess (gibbed)
|
|
152
|
+
12 => 'N', # Bloody mess 2 (dead body flat)
|
|
153
|
+
15 => 'N', # Dead player (dead body flat)
|
|
154
|
+
}.freeze
|
|
155
|
+
|
|
139
156
|
def initialize(wad)
|
|
140
157
|
@wad = wad
|
|
141
158
|
@cache = {}
|
|
@@ -154,8 +171,9 @@ module Doom
|
|
|
154
171
|
prefix = THING_SPRITES[thing_type]
|
|
155
172
|
return nil unless prefix
|
|
156
173
|
|
|
157
|
-
|
|
158
|
-
|
|
174
|
+
frame = THING_DEFAULT_FRAME[thing_type] || 'A'
|
|
175
|
+
sprite = load_sprite_frame(prefix, frame, 0) ||
|
|
176
|
+
load_sprite_frame(prefix, frame, 1)
|
|
159
177
|
|
|
160
178
|
@cache[thing_type] = sprite
|
|
161
179
|
sprite
|
|
@@ -173,18 +191,21 @@ module Doom
|
|
|
173
191
|
prefix = THING_SPRITES[thing_type]
|
|
174
192
|
return nil unless prefix
|
|
175
193
|
|
|
194
|
+
frame = THING_DEFAULT_FRAME[thing_type] || 'A'
|
|
195
|
+
|
|
176
196
|
# Check for rotation 0 (all angles) sprite first
|
|
177
|
-
sprite = load_sprite_frame(prefix,
|
|
197
|
+
sprite = load_sprite_frame(prefix, frame, 0)
|
|
178
198
|
return sprite if sprite
|
|
179
199
|
|
|
180
200
|
# Calculate rotation frame (1-8)
|
|
181
|
-
#
|
|
182
|
-
|
|
201
|
+
# DOOM: rot = (R_PointToAngle(thing) - thing->angle + ANG45/2*9) >> 29
|
|
202
|
+
# Rotation 1=front (viewer faces monster's front), 5=back
|
|
203
|
+
angle_diff = viewer_angle - (thing_angle * Math::PI / 180.0) + Math::PI
|
|
183
204
|
angle_diff = angle_diff % (2 * Math::PI)
|
|
184
205
|
angle_diff += 2 * Math::PI if angle_diff < 0
|
|
185
206
|
rotation = ((angle_diff + Math::PI / 8) / (Math::PI / 4)).to_i % 8 + 1
|
|
186
207
|
|
|
187
|
-
load_sprite_frame(prefix,
|
|
208
|
+
load_sprite_frame(prefix, frame, rotation) || @cache[thing_type]
|
|
188
209
|
end
|
|
189
210
|
|
|
190
211
|
# Get a specific frame (for death animations, etc.)
|
|
@@ -196,8 +217,8 @@ module Doom
|
|
|
196
217
|
sprite = load_sprite_frame(prefix, frame_letter, 0)
|
|
197
218
|
return sprite if sprite
|
|
198
219
|
|
|
199
|
-
# Try with calculated rotation
|
|
200
|
-
angle_diff = viewer_angle - (thing_angle * Math::PI / 180.0)
|
|
220
|
+
# Try with calculated rotation (same formula as get_rotated)
|
|
221
|
+
angle_diff = viewer_angle - (thing_angle * Math::PI / 180.0) + Math::PI
|
|
201
222
|
angle_diff = angle_diff % (2 * Math::PI)
|
|
202
223
|
angle_diff += 2 * Math::PI if angle_diff < 0
|
|
203
224
|
rotation = ((angle_diff + Math::PI / 8) / (Math::PI / 4)).to_i % 8 + 1
|
|
@@ -205,6 +226,11 @@ module Doom
|
|
|
205
226
|
load_sprite_frame(prefix, frame_letter, rotation)
|
|
206
227
|
end
|
|
207
228
|
|
|
229
|
+
# Get a frame by explicit prefix (for barrel explosions where prefix differs from thing type)
|
|
230
|
+
def get_frame_by_prefix(prefix, frame_letter)
|
|
231
|
+
load_sprite_frame(prefix, frame_letter, 0)
|
|
232
|
+
end
|
|
233
|
+
|
|
208
234
|
private
|
|
209
235
|
|
|
210
236
|
def build_sprite_index
|
data/lib/doom/wad/texture.rb
CHANGED
|
@@ -148,7 +148,7 @@ module Doom
|
|
|
148
148
|
def precompute_columns
|
|
149
149
|
@width.times do |x|
|
|
150
150
|
posts = @columns[x]
|
|
151
|
-
pixels = Array.new(@height
|
|
151
|
+
pixels = Array.new(@height) # nil = transparent
|
|
152
152
|
posts.each do |post|
|
|
153
153
|
td = post.top_delta
|
|
154
154
|
post.pixels.each_with_index do |color, i|
|
data/lib/doom/wad_downloader.rb
CHANGED
|
@@ -66,7 +66,16 @@ module Doom
|
|
|
66
66
|
uri = URI.parse(SHAREWARE_URL)
|
|
67
67
|
downloaded = 0
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
ssl_opts = { use_ssl: uri.scheme == 'https' }
|
|
70
|
+
# Workaround for SSL certificate issues on some systems
|
|
71
|
+
begin
|
|
72
|
+
Net::HTTP.start(uri.host, uri.port, **ssl_opts) { |h| h.head(uri) }
|
|
73
|
+
rescue OpenSSL::SSL::SSLError
|
|
74
|
+
puts "SSL certificate verification failed, retrying without verification..."
|
|
75
|
+
ssl_opts[:verify_mode] = OpenSSL::SSL::VERIFY_NONE
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
Net::HTTP.start(uri.host, uri.port, **ssl_opts) do |http|
|
|
70
79
|
request = Net::HTTP::Get.new(uri)
|
|
71
80
|
|
|
72
81
|
http.request(request) do |response|
|
data/lib/doom.rb
CHANGED
|
@@ -17,7 +17,14 @@ require_relative 'doom/game/animations'
|
|
|
17
17
|
require_relative 'doom/game/item_pickup'
|
|
18
18
|
require_relative 'doom/game/combat'
|
|
19
19
|
require_relative 'doom/game/sector_effects'
|
|
20
|
+
require_relative 'doom/game/monster_ai'
|
|
21
|
+
require_relative 'doom/game/menu'
|
|
22
|
+
require_relative 'doom/game/intermission'
|
|
23
|
+
require_relative 'doom/wad/sound'
|
|
24
|
+
require_relative 'doom/game/sound_engine'
|
|
25
|
+
require_relative 'doom/render/font'
|
|
20
26
|
require_relative 'doom/render/renderer'
|
|
27
|
+
require_relative 'doom/render/screen_melt'
|
|
21
28
|
require_relative 'doom/render/status_bar'
|
|
22
29
|
require_relative 'doom/render/weapon_renderer'
|
|
23
30
|
require_relative 'doom/platform/gosu_window'
|
|
@@ -26,11 +33,26 @@ module Doom
|
|
|
26
33
|
class Error < StandardError; end
|
|
27
34
|
|
|
28
35
|
class << self
|
|
29
|
-
def run(wad_path, map_name: 'E1M1')
|
|
36
|
+
def run(wad_path, map_name: 'E1M1', rubykaigi: false)
|
|
30
37
|
puts "Loading WAD: #{wad_path}"
|
|
31
38
|
wad = Wad::Reader.new(wad_path)
|
|
32
39
|
puts " #{wad.type}: #{wad.num_lumps} lumps"
|
|
33
40
|
|
|
41
|
+
# If it's a PWAD, we need a base IWAD for resources (palette, textures, etc.)
|
|
42
|
+
if wad.pwad?
|
|
43
|
+
iwad_path = find_iwad
|
|
44
|
+
raise Error, "PWAD requires a base IWAD (doom1.wad). Place it in the current directory or ~/.doom/" unless iwad_path
|
|
45
|
+
puts " PWAD detected, loading base IWAD: #{iwad_path}"
|
|
46
|
+
base_wad = Wad::Reader.new(iwad_path)
|
|
47
|
+
base_wad.merge_pwad(wad)
|
|
48
|
+
wad = base_wad
|
|
49
|
+
|
|
50
|
+
# Auto-detect map name from PWAD lumps
|
|
51
|
+
pwad_map = wad.directory.find { |e| e.name =~ /^(E\dM\d|MAP\d\d)$/ }
|
|
52
|
+
map_name = pwad_map.name if pwad_map
|
|
53
|
+
puts " Using map: #{map_name}"
|
|
54
|
+
end
|
|
55
|
+
|
|
34
56
|
puts 'Loading palette...'
|
|
35
57
|
palette = Wad::Palette.load(wad)
|
|
36
58
|
|
|
@@ -77,14 +99,36 @@ module Doom
|
|
|
77
99
|
player_state = Game::PlayerState.new
|
|
78
100
|
status_bar = Render::StatusBar.new(hud_graphics, player_state)
|
|
79
101
|
weapon_renderer = Render::WeaponRenderer.new(hud_graphics, player_state)
|
|
80
|
-
|
|
102
|
+
sound_mgr = Wad::SoundManager.new(wad)
|
|
103
|
+
sound_engine = Game::SoundEngine.new(sound_mgr)
|
|
104
|
+
sector_actions = Game::SectorActions.new(map, sound_engine)
|
|
81
105
|
sector_effects = Game::SectorEffects.new(map)
|
|
82
106
|
item_pickup = Game::ItemPickup.new(map, player_state)
|
|
83
|
-
combat = Game::Combat.new(map, player_state, sprites)
|
|
107
|
+
combat = Game::Combat.new(map, player_state, sprites, {}, sound_engine)
|
|
108
|
+
monster_ai = Game::MonsterAI.new(map, combat, player_state, sprites, {}, sound_engine)
|
|
109
|
+
doom_font = Render::Font.new(wad, hud_graphics)
|
|
110
|
+
menu = Game::Menu.new(wad, hud_graphics, doom_font)
|
|
111
|
+
|
|
112
|
+
# RubyKaigi mode: god mode, no aggression, benchmark HUD
|
|
113
|
+
if rubykaigi
|
|
114
|
+
menu.options[:rubykaigi_mode] = true
|
|
115
|
+
menu.options[:god_mode] = true
|
|
116
|
+
end
|
|
84
117
|
|
|
85
118
|
puts 'Starting game window...'
|
|
86
|
-
window = Platform::GosuWindow.new(renderer, palette, map, player_state, status_bar, weapon_renderer, sector_actions, animations, sector_effects, item_pickup, combat)
|
|
119
|
+
window = Platform::GosuWindow.new(renderer, palette, map, player_state, status_bar, weapon_renderer, sector_actions, animations, sector_effects, item_pickup, combat, monster_ai, menu, sound_engine)
|
|
87
120
|
window.show
|
|
88
121
|
end
|
|
122
|
+
|
|
123
|
+
private
|
|
124
|
+
|
|
125
|
+
def find_iwad
|
|
126
|
+
candidates = [
|
|
127
|
+
File.join(Dir.pwd, 'doom1.wad'),
|
|
128
|
+
File.join(Dir.pwd, 'doom.wad'),
|
|
129
|
+
File.join(Dir.home, '.doom', 'doom1.wad'),
|
|
130
|
+
]
|
|
131
|
+
candidates.find { |p| File.exist?(p) }
|
|
132
|
+
end
|
|
89
133
|
end
|
|
90
134
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: doom
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chris Hasinski
|
|
@@ -65,13 +65,19 @@ files:
|
|
|
65
65
|
- lib/doom.rb
|
|
66
66
|
- lib/doom/game/animations.rb
|
|
67
67
|
- lib/doom/game/combat.rb
|
|
68
|
+
- lib/doom/game/intermission.rb
|
|
68
69
|
- lib/doom/game/item_pickup.rb
|
|
70
|
+
- lib/doom/game/menu.rb
|
|
71
|
+
- lib/doom/game/monster_ai.rb
|
|
69
72
|
- lib/doom/game/player_state.rb
|
|
70
73
|
- lib/doom/game/sector_actions.rb
|
|
71
74
|
- lib/doom/game/sector_effects.rb
|
|
75
|
+
- lib/doom/game/sound_engine.rb
|
|
72
76
|
- lib/doom/map/data.rb
|
|
73
77
|
- lib/doom/platform/gosu_window.rb
|
|
78
|
+
- lib/doom/render/font.rb
|
|
74
79
|
- lib/doom/render/renderer.rb
|
|
80
|
+
- lib/doom/render/screen_melt.rb
|
|
75
81
|
- lib/doom/render/status_bar.rb
|
|
76
82
|
- lib/doom/render/weapon_renderer.rb
|
|
77
83
|
- lib/doom/version.rb
|
|
@@ -81,10 +87,11 @@ files:
|
|
|
81
87
|
- lib/doom/wad/palette.rb
|
|
82
88
|
- lib/doom/wad/patch.rb
|
|
83
89
|
- lib/doom/wad/reader.rb
|
|
90
|
+
- lib/doom/wad/sound.rb
|
|
84
91
|
- lib/doom/wad/sprite.rb
|
|
85
92
|
- lib/doom/wad/texture.rb
|
|
86
93
|
- lib/doom/wad_downloader.rb
|
|
87
|
-
homepage: https://github.com/khasinski/doom
|
|
94
|
+
homepage: https://github.com/khasinski/doom
|
|
88
95
|
licenses:
|
|
89
96
|
- GPL-2.0
|
|
90
97
|
metadata: {}
|
|
@@ -102,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
102
109
|
- !ruby/object:Gem::Version
|
|
103
110
|
version: '0'
|
|
104
111
|
requirements: []
|
|
105
|
-
rubygems_version: 4.0.
|
|
112
|
+
rubygems_version: 4.0.6
|
|
106
113
|
specification_version: 4
|
|
107
114
|
summary: Doom engine port in pure Ruby
|
|
108
115
|
test_files: []
|