doom 0.4.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.
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doom
4
+ module Game
5
+ # Sector light specials and scrolling walls, matching Chocolate Doom's
6
+ # P_SpawnSpecials (p_spec.c) and p_lights.c.
7
+ class SectorEffects
8
+ GLOWSPEED = 8 # Light units per tic for glow
9
+ STROBEBRIGHT = 5 # Bright duration for strobes (tics)
10
+ FASTDARK = 15 # Dark duration for fast strobe (tics)
11
+ SLOWDARK = 35 # Dark duration for slow strobe (tics)
12
+
13
+ def initialize(map)
14
+ @map = map
15
+ @effects = []
16
+ @scroll_sides = []
17
+ spawn_specials
18
+ end
19
+
20
+ # Called every game tic (35/sec)
21
+ def update
22
+ @effects.each(&:update)
23
+ @scroll_sides.each { |side| side.x_offset += 1 }
24
+ end
25
+
26
+ private
27
+
28
+ def spawn_specials
29
+ @map.sectors.each do |sector|
30
+ case sector.special
31
+ when 1 # Flickering lights
32
+ @effects << LightFlash.new(sector, find_min_light(sector))
33
+ when 2 # Fast strobe
34
+ @effects << StrobeFlash.new(sector, find_min_light(sector), FASTDARK, false)
35
+ when 3 # Slow strobe
36
+ @effects << StrobeFlash.new(sector, find_min_light(sector), SLOWDARK, false)
37
+ when 4 # Fast strobe + 20% damage
38
+ @effects << StrobeFlash.new(sector, find_min_light(sector), FASTDARK, false)
39
+ when 8 # Glowing light
40
+ @effects << Glow.new(sector, find_min_light(sector))
41
+ when 12 # Sync strobe slow
42
+ @effects << StrobeFlash.new(sector, find_min_light(sector), SLOWDARK, true)
43
+ when 13 # Sync strobe fast
44
+ @effects << StrobeFlash.new(sector, find_min_light(sector), FASTDARK, true)
45
+ when 17 # Fire flicker
46
+ @effects << FireFlicker.new(sector, find_min_light(sector))
47
+ end
48
+ end
49
+
50
+ # Linedef type 48: scrolling wall (front side scrolls +1 unit/tic)
51
+ @map.linedefs.each do |linedef|
52
+ next unless linedef.special == 48
53
+ side = @map.sidedefs[linedef.sidedef_right]
54
+ @scroll_sides << side if side
55
+ end
56
+ end
57
+
58
+ # P_FindMinSurroundingLight: find lowest light level among adjacent sectors
59
+ def find_min_light(sector)
60
+ min = sector.light_level
61
+ sector_idx = @map.sectors.index(sector)
62
+ return min unless sector_idx
63
+
64
+ @map.linedefs.each do |ld|
65
+ right = @map.sidedefs[ld.sidedef_right]
66
+ next unless right
67
+ left_idx = ld.sidedef_left
68
+ next if left_idx >= 0xFFFF
69
+ left = @map.sidedefs[left_idx]
70
+ next unless left
71
+
72
+ if right.sector == sector_idx && left.sector != sector_idx
73
+ other_light = @map.sectors[left.sector].light_level
74
+ min = other_light if other_light < min
75
+ elsif left.sector == sector_idx && right.sector != sector_idx
76
+ other_light = @map.sectors[right.sector].light_level
77
+ min = other_light if other_light < min
78
+ end
79
+ end
80
+ min
81
+ end
82
+
83
+ # T_LightFlash (type 1): mostly bright with brief random dark flickers
84
+ class LightFlash
85
+ def initialize(sector, minlight)
86
+ @sector = sector
87
+ @maxlight = sector.light_level
88
+ @minlight = minlight
89
+ @count = (rand(65)) + 1
90
+ end
91
+
92
+ def update
93
+ @count -= 1
94
+ return if @count > 0
95
+
96
+ if @sector.light_level == @maxlight
97
+ @sector.light_level = @minlight
98
+ @count = (rand(8)) + 1 # dark for 1-8 tics
99
+ else
100
+ @sector.light_level = @maxlight
101
+ @count = (rand(2) == 0 ? 1 : 65) # bright for 1 or 65 tics (P_Random()&64)
102
+ end
103
+ end
104
+ end
105
+
106
+ # T_StrobeFlash (types 2, 3, 4, 12, 13): regular strobe blink
107
+ class StrobeFlash
108
+ def initialize(sector, minlight, darktime, in_sync)
109
+ @sector = sector
110
+ @maxlight = sector.light_level
111
+ @minlight = minlight
112
+ @minlight = 0 if @minlight == @maxlight
113
+ @darktime = darktime
114
+ @brighttime = STROBEBRIGHT
115
+ @count = in_sync ? 1 : (rand(8)) + 1
116
+ end
117
+
118
+ def update
119
+ @count -= 1
120
+ return if @count > 0
121
+
122
+ if @sector.light_level == @minlight
123
+ @sector.light_level = @maxlight
124
+ @count = @brighttime
125
+ else
126
+ @sector.light_level = @minlight
127
+ @count = @darktime
128
+ end
129
+ end
130
+ end
131
+
132
+ # T_Glow (type 8): smooth triangle-wave oscillation
133
+ class Glow
134
+ def initialize(sector, minlight)
135
+ @sector = sector
136
+ @maxlight = sector.light_level
137
+ @minlight = minlight
138
+ @direction = -1 # start dimming
139
+ end
140
+
141
+ def update
142
+ if @direction == -1
143
+ @sector.light_level -= GLOWSPEED
144
+ if @sector.light_level <= @minlight
145
+ @sector.light_level += GLOWSPEED
146
+ @direction = 1
147
+ end
148
+ else
149
+ @sector.light_level += GLOWSPEED
150
+ if @sector.light_level >= @maxlight
151
+ @sector.light_level -= GLOWSPEED
152
+ @direction = -1
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ # T_FireFlicker (type 17): random fire-like flickering
159
+ class FireFlicker
160
+ def initialize(sector, minlight)
161
+ @sector = sector
162
+ @maxlight = sector.light_level
163
+ @minlight = minlight + 16 # fire doesn't go as dark
164
+ @count = 4
165
+ end
166
+
167
+ def update
168
+ @count -= 1
169
+ return if @count > 0
170
+
171
+ amount = (rand(4)) * 16 # 0, 16, 32, or 48
172
+ level = @maxlight - amount
173
+ @sector.light_level = level < @minlight ? @minlight : level
174
+ @count = 4
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end