doom 0.3.0 → 0.5.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 +1 -1
- data/lib/doom/game/animations.rb +97 -0
- data/lib/doom/game/combat.rb +244 -0
- data/lib/doom/game/item_pickup.rb +170 -0
- data/lib/doom/game/player_state.rb +313 -0
- data/lib/doom/game/sector_actions.rb +162 -0
- data/lib/doom/game/sector_effects.rb +179 -0
- data/lib/doom/platform/gosu_window.rb +706 -59
- data/lib/doom/render/renderer.rb +397 -136
- data/lib/doom/render/status_bar.rb +218 -0
- data/lib/doom/render/weapon_renderer.rb +99 -0
- data/lib/doom/version.rb +1 -1
- data/lib/doom/wad/colormap.rb +0 -6
- data/lib/doom/wad/flat.rb +0 -21
- data/lib/doom/wad/hud_graphics.rb +257 -0
- data/lib/doom/wad/sprite.rb +95 -22
- data/lib/doom/wad/texture.rb +23 -22
- data/lib/doom/wad_downloader.rb +2 -2
- data/lib/doom.rb +27 -2
- metadata +12 -6
data/lib/doom/wad/sprite.rb
CHANGED
|
@@ -140,6 +140,11 @@ module Doom
|
|
|
140
140
|
@wad = wad
|
|
141
141
|
@cache = {}
|
|
142
142
|
@rotation_cache = {}
|
|
143
|
+
|
|
144
|
+
# Build sprite lump index: maps "PREFIXframe_rotation" -> [lump_name, mirrored?]
|
|
145
|
+
# Handles combined lumps like SPOSA2A8 (rotation 2 normal, rotation 8 mirrored)
|
|
146
|
+
@sprite_index = {}
|
|
147
|
+
build_sprite_index
|
|
143
148
|
end
|
|
144
149
|
|
|
145
150
|
# Get default sprite (rotation 0 or 1)
|
|
@@ -149,9 +154,8 @@ module Doom
|
|
|
149
154
|
prefix = THING_SPRITES[thing_type]
|
|
150
155
|
return nil unless prefix
|
|
151
156
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
Sprite.load(@wad, "#{prefix}A1")
|
|
157
|
+
sprite = load_sprite_frame(prefix, 'A', 0) ||
|
|
158
|
+
load_sprite_frame(prefix, 'A', 1)
|
|
155
159
|
|
|
156
160
|
@cache[thing_type] = sprite
|
|
157
161
|
sprite
|
|
@@ -169,36 +173,105 @@ module Doom
|
|
|
169
173
|
prefix = THING_SPRITES[thing_type]
|
|
170
174
|
return nil unless prefix
|
|
171
175
|
|
|
172
|
-
# Check
|
|
173
|
-
|
|
174
|
-
if
|
|
175
|
-
return @rotation_cache[cache_key] if @rotation_cache[cache_key]
|
|
176
|
-
else
|
|
177
|
-
sprite = Sprite.load(@wad, cache_key)
|
|
178
|
-
@rotation_cache[cache_key] = sprite
|
|
179
|
-
return sprite if sprite
|
|
180
|
-
end
|
|
176
|
+
# Check for rotation 0 (all angles) sprite first
|
|
177
|
+
sprite = load_sprite_frame(prefix, 'A', 0)
|
|
178
|
+
return sprite if sprite
|
|
181
179
|
|
|
182
180
|
# Calculate rotation frame (1-8)
|
|
183
181
|
# Doom rotations: 1=front, 2=front-right, 3=right, etc. (clockwise)
|
|
184
|
-
# The angle we need is: viewer's angle to sprite - sprite's facing angle
|
|
185
182
|
angle_diff = viewer_angle - (thing_angle * Math::PI / 180.0)
|
|
186
|
-
|
|
187
|
-
# Normalize to 0-2π
|
|
188
183
|
angle_diff = angle_diff % (2 * Math::PI)
|
|
189
184
|
angle_diff += 2 * Math::PI if angle_diff < 0
|
|
185
|
+
rotation = ((angle_diff + Math::PI / 8) / (Math::PI / 4)).to_i % 8 + 1
|
|
186
|
+
|
|
187
|
+
load_sprite_frame(prefix, 'A', rotation) || @cache[thing_type]
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Get a specific frame (for death animations, etc.)
|
|
191
|
+
def get_frame(thing_type, frame_letter, viewer_angle, thing_angle)
|
|
192
|
+
prefix = THING_SPRITES[thing_type]
|
|
193
|
+
return nil unless prefix
|
|
190
194
|
|
|
191
|
-
#
|
|
192
|
-
|
|
193
|
-
|
|
195
|
+
# Death frames typically use rotation 0 (same from all angles)
|
|
196
|
+
sprite = load_sprite_frame(prefix, frame_letter, 0)
|
|
197
|
+
return sprite if sprite
|
|
198
|
+
|
|
199
|
+
# Try with calculated rotation
|
|
200
|
+
angle_diff = viewer_angle - (thing_angle * Math::PI / 180.0)
|
|
201
|
+
angle_diff = angle_diff % (2 * Math::PI)
|
|
202
|
+
angle_diff += 2 * Math::PI if angle_diff < 0
|
|
194
203
|
rotation = ((angle_diff + Math::PI / 8) / (Math::PI / 4)).to_i % 8 + 1
|
|
195
204
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
205
|
+
load_sprite_frame(prefix, frame_letter, rotation)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
private
|
|
209
|
+
|
|
210
|
+
def build_sprite_index
|
|
211
|
+
@wad.directory.each do |entry|
|
|
212
|
+
name = entry.name
|
|
213
|
+
next if name.length < 6
|
|
214
|
+
|
|
215
|
+
prefix = name[0, 4]
|
|
216
|
+
frame1 = name[4]
|
|
217
|
+
rot1 = name[5].to_i
|
|
218
|
+
|
|
219
|
+
# Register first frame+rotation
|
|
220
|
+
key = "#{prefix}#{frame1}#{rot1}"
|
|
221
|
+
@sprite_index[key] = [name, false]
|
|
222
|
+
|
|
223
|
+
# Check for mirrored second rotation (e.g., SPOSA2A8)
|
|
224
|
+
if name.length >= 8
|
|
225
|
+
frame2 = name[6]
|
|
226
|
+
rot2 = name[7].to_i
|
|
227
|
+
key2 = "#{prefix}#{frame2}#{rot2}"
|
|
228
|
+
@sprite_index[key2] = [name, true]
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def load_sprite_frame(prefix, frame, rotation)
|
|
234
|
+
key = "#{prefix}#{frame}#{rotation}"
|
|
235
|
+
return @rotation_cache[key] if @rotation_cache.key?(key)
|
|
236
|
+
|
|
237
|
+
index_entry = @sprite_index[key]
|
|
238
|
+
unless index_entry
|
|
239
|
+
@rotation_cache[key] = nil
|
|
240
|
+
return nil
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
lump_name, mirrored = index_entry
|
|
244
|
+
# Load the base sprite (may be shared by mirrored pair)
|
|
245
|
+
base = load_or_cache_lump(lump_name)
|
|
246
|
+
unless base
|
|
247
|
+
@rotation_cache[key] = nil
|
|
248
|
+
return nil
|
|
199
249
|
end
|
|
200
250
|
|
|
201
|
-
|
|
251
|
+
sprite = mirrored ? mirror_sprite(base) : base
|
|
252
|
+
@rotation_cache[key] = sprite
|
|
253
|
+
sprite
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def load_or_cache_lump(lump_name)
|
|
257
|
+
cache_key = "_lump_#{lump_name}"
|
|
258
|
+
return @rotation_cache[cache_key] if @rotation_cache.key?(cache_key)
|
|
259
|
+
|
|
260
|
+
sprite = Sprite.load(@wad, lump_name)
|
|
261
|
+
@rotation_cache[cache_key] = sprite
|
|
262
|
+
sprite
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def mirror_sprite(sprite)
|
|
266
|
+
# Flip columns horizontally, adjust left_offset
|
|
267
|
+
mirrored_columns = sprite.instance_variable_get(:@columns).reverse
|
|
268
|
+
mirrored_left = sprite.width - sprite.left_offset
|
|
269
|
+
Sprite.new(
|
|
270
|
+
"#{sprite.name}_M",
|
|
271
|
+
sprite.width, sprite.height,
|
|
272
|
+
mirrored_left, sprite.top_offset,
|
|
273
|
+
mirrored_columns
|
|
274
|
+
)
|
|
202
275
|
end
|
|
203
276
|
end
|
|
204
277
|
end
|
data/lib/doom/wad/texture.rb
CHANGED
|
@@ -12,21 +12,12 @@ module Doom
|
|
|
12
12
|
@width = width
|
|
13
13
|
@height = height
|
|
14
14
|
@patch_refs = patch_refs
|
|
15
|
-
@columns = nil
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def columns
|
|
19
|
-
@columns ||= build_columns
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def build_columns
|
|
23
|
-
# Will be built when patches are composited
|
|
24
|
-
nil
|
|
25
15
|
end
|
|
26
16
|
|
|
27
17
|
def self.load_all(wad)
|
|
28
18
|
pnames = load_pnames(wad)
|
|
29
19
|
textures = {}
|
|
20
|
+
texture_names = []
|
|
30
21
|
|
|
31
22
|
%w[TEXTURE1 TEXTURE2].each do |lump_name|
|
|
32
23
|
data = wad.read_lump(lump_name)
|
|
@@ -34,10 +25,11 @@ module Doom
|
|
|
34
25
|
|
|
35
26
|
parse_texture_lump(data).each do |tex|
|
|
36
27
|
textures[tex.name] = tex
|
|
28
|
+
texture_names << tex.name
|
|
37
29
|
end
|
|
38
30
|
end
|
|
39
31
|
|
|
40
|
-
{ textures: textures, pnames: pnames }
|
|
32
|
+
{ textures: textures, pnames: pnames, texture_names: texture_names }
|
|
41
33
|
end
|
|
42
34
|
|
|
43
35
|
def self.load_pnames(wad)
|
|
@@ -81,13 +73,14 @@ module Doom
|
|
|
81
73
|
end
|
|
82
74
|
|
|
83
75
|
class TextureManager
|
|
84
|
-
attr_reader :textures, :pnames, :patches
|
|
76
|
+
attr_reader :textures, :pnames, :patches, :texture_names
|
|
85
77
|
|
|
86
78
|
def initialize(wad)
|
|
87
79
|
@wad = wad
|
|
88
80
|
result = Texture.load_all(wad)
|
|
89
81
|
@textures = result[:textures]
|
|
90
82
|
@pnames = result[:pnames]
|
|
83
|
+
@texture_names = result[:texture_names]
|
|
91
84
|
@patches = {}
|
|
92
85
|
@composite_cache = {}
|
|
93
86
|
end
|
|
@@ -142,21 +135,29 @@ module Doom
|
|
|
142
135
|
@width = width
|
|
143
136
|
@height = height
|
|
144
137
|
@columns = columns
|
|
138
|
+
@column_cache = Array.new(width)
|
|
139
|
+
precompute_columns
|
|
145
140
|
end
|
|
146
141
|
|
|
147
|
-
def column_pixels(x,
|
|
148
|
-
x
|
|
149
|
-
|
|
150
|
-
|
|
142
|
+
def column_pixels(x, _height_needed = nil)
|
|
143
|
+
@column_cache[x & (@width - 1)]
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
private
|
|
151
147
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
148
|
+
def precompute_columns
|
|
149
|
+
@width.times do |x|
|
|
150
|
+
posts = @columns[x]
|
|
151
|
+
pixels = Array.new(@height, 0)
|
|
152
|
+
posts.each do |post|
|
|
153
|
+
td = post.top_delta
|
|
154
|
+
post.pixels.each_with_index do |color, i|
|
|
155
|
+
y = (td + i) % @height
|
|
156
|
+
pixels[y] = color
|
|
157
|
+
end
|
|
157
158
|
end
|
|
159
|
+
@column_cache[x] = pixels.freeze
|
|
158
160
|
end
|
|
159
|
-
pixels
|
|
160
161
|
end
|
|
161
162
|
end
|
|
162
163
|
end
|
data/lib/doom/wad_downloader.rb
CHANGED
|
@@ -7,8 +7,8 @@ require 'fileutils'
|
|
|
7
7
|
module Doom
|
|
8
8
|
# Downloads the shareware DOOM1.WAD if not present
|
|
9
9
|
class WadDownloader
|
|
10
|
-
#
|
|
11
|
-
SHAREWARE_URL = 'https://
|
|
10
|
+
# Doom shareware WAD v1.9 (freely distributable)
|
|
11
|
+
SHAREWARE_URL = 'https://raw.githubusercontent.com/Akbar30Bill/DOOM_wads/master/doom1.wad'
|
|
12
12
|
SHAREWARE_SIZE = 4_196_020 # Expected size in bytes
|
|
13
13
|
SHAREWARE_FILENAME = 'doom1.wad'
|
|
14
14
|
|
data/lib/doom.rb
CHANGED
|
@@ -9,8 +9,17 @@ require_relative 'doom/wad/flat'
|
|
|
9
9
|
require_relative 'doom/wad/patch'
|
|
10
10
|
require_relative 'doom/wad/texture'
|
|
11
11
|
require_relative 'doom/wad/sprite'
|
|
12
|
+
require_relative 'doom/wad/hud_graphics'
|
|
12
13
|
require_relative 'doom/map/data'
|
|
14
|
+
require_relative 'doom/game/player_state'
|
|
15
|
+
require_relative 'doom/game/sector_actions'
|
|
16
|
+
require_relative 'doom/game/animations'
|
|
17
|
+
require_relative 'doom/game/item_pickup'
|
|
18
|
+
require_relative 'doom/game/combat'
|
|
19
|
+
require_relative 'doom/game/sector_effects'
|
|
13
20
|
require_relative 'doom/render/renderer'
|
|
21
|
+
require_relative 'doom/render/status_bar'
|
|
22
|
+
require_relative 'doom/render/weapon_renderer'
|
|
14
23
|
require_relative 'doom/platform/gosu_window'
|
|
15
24
|
|
|
16
25
|
module Doom
|
|
@@ -39,6 +48,9 @@ module Doom
|
|
|
39
48
|
puts 'Loading sprites...'
|
|
40
49
|
sprites = Wad::SpriteManager.new(wad)
|
|
41
50
|
|
|
51
|
+
puts 'Loading HUD graphics...'
|
|
52
|
+
hud_graphics = Wad::HudGraphics.new(wad)
|
|
53
|
+
|
|
42
54
|
puts "Loading map #{map_name}..."
|
|
43
55
|
map = Map::MapData.load(wad, map_name)
|
|
44
56
|
puts " #{map.vertices.size} vertices, #{map.linedefs.size} linedefs"
|
|
@@ -53,12 +65,25 @@ module Doom
|
|
|
53
65
|
player_start = Map::Thing.new(0, 0, 90, 1, 0)
|
|
54
66
|
end
|
|
55
67
|
|
|
68
|
+
puts 'Initializing animations...'
|
|
69
|
+
flat_names = flats.map(&:name)
|
|
70
|
+
animations = Game::Animations.new(textures.texture_names, flat_names)
|
|
71
|
+
|
|
56
72
|
puts 'Creating renderer...'
|
|
57
|
-
renderer = Render::Renderer.new(wad, map, textures, palette, colormap, flats, sprites)
|
|
73
|
+
renderer = Render::Renderer.new(wad, map, textures, palette, colormap, flats, sprites, animations)
|
|
58
74
|
renderer.set_player(player_start.x, player_start.y, 41, player_start.angle)
|
|
59
75
|
|
|
76
|
+
puts 'Setting up player state and HUD...'
|
|
77
|
+
player_state = Game::PlayerState.new
|
|
78
|
+
status_bar = Render::StatusBar.new(hud_graphics, player_state)
|
|
79
|
+
weapon_renderer = Render::WeaponRenderer.new(hud_graphics, player_state)
|
|
80
|
+
sector_actions = Game::SectorActions.new(map)
|
|
81
|
+
sector_effects = Game::SectorEffects.new(map)
|
|
82
|
+
item_pickup = Game::ItemPickup.new(map, player_state)
|
|
83
|
+
combat = Game::Combat.new(map, player_state, sprites)
|
|
84
|
+
|
|
60
85
|
puts 'Starting game window...'
|
|
61
|
-
window = Platform::GosuWindow.new(renderer, palette, map)
|
|
86
|
+
window = Platform::GosuWindow.new(renderer, palette, map, player_state, status_bar, weapon_renderer, sector_actions, animations, sector_effects, item_pickup, combat)
|
|
62
87
|
window.show
|
|
63
88
|
end
|
|
64
89
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: doom
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chris Hasinski
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: gosu
|
|
@@ -64,12 +63,21 @@ files:
|
|
|
64
63
|
- README.md
|
|
65
64
|
- bin/doom
|
|
66
65
|
- lib/doom.rb
|
|
66
|
+
- lib/doom/game/animations.rb
|
|
67
|
+
- lib/doom/game/combat.rb
|
|
68
|
+
- lib/doom/game/item_pickup.rb
|
|
69
|
+
- lib/doom/game/player_state.rb
|
|
70
|
+
- lib/doom/game/sector_actions.rb
|
|
71
|
+
- lib/doom/game/sector_effects.rb
|
|
67
72
|
- lib/doom/map/data.rb
|
|
68
73
|
- lib/doom/platform/gosu_window.rb
|
|
69
74
|
- lib/doom/render/renderer.rb
|
|
75
|
+
- lib/doom/render/status_bar.rb
|
|
76
|
+
- lib/doom/render/weapon_renderer.rb
|
|
70
77
|
- lib/doom/version.rb
|
|
71
78
|
- lib/doom/wad/colormap.rb
|
|
72
79
|
- lib/doom/wad/flat.rb
|
|
80
|
+
- lib/doom/wad/hud_graphics.rb
|
|
73
81
|
- lib/doom/wad/palette.rb
|
|
74
82
|
- lib/doom/wad/patch.rb
|
|
75
83
|
- lib/doom/wad/reader.rb
|
|
@@ -80,7 +88,6 @@ homepage: https://github.com/khasinski/doom-rb
|
|
|
80
88
|
licenses:
|
|
81
89
|
- GPL-2.0
|
|
82
90
|
metadata: {}
|
|
83
|
-
post_install_message:
|
|
84
91
|
rdoc_options: []
|
|
85
92
|
require_paths:
|
|
86
93
|
- lib
|
|
@@ -95,8 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
95
102
|
- !ruby/object:Gem::Version
|
|
96
103
|
version: '0'
|
|
97
104
|
requirements: []
|
|
98
|
-
rubygems_version:
|
|
99
|
-
signing_key:
|
|
105
|
+
rubygems_version: 4.0.3
|
|
100
106
|
specification_version: 4
|
|
101
107
|
summary: Doom engine port in pure Ruby
|
|
102
108
|
test_files: []
|