vrtc / honeydew (public) (License: CC0) (since 2023-12-20) (hash sha1)
Warcraft 3: The Frozen Throne 1.27 custom scenario.
List of commits:
Subject Hash Author Date (UTC)
feat!: add spell Dampening Field 61ddc9409c00c79ee947578291c21eaa701f41e2 Vladyslav Bondarenko 2023-12-22 01:38:15
stash amend this 050948decf45ea58dd25b0eddf62d1593ed4460f Vladyslav Bondarenko 2023-12-21 07:39:33
fix!: patch map script correctly 3a8cb9ba68d82685dce420659416d36b00e06ac8 Vladyslav Bondarenko 2023-12-21 01:15:05
fix: typo in Makefile 7fd84f0bd1d63c2218c4f72f96ea2297f204a223 Vladyslav Bondarenko 2023-12-21 01:00:47
build: complicate Makefile bff3fe00560b3afe70a869e2859d665367b4f62d Vladyslav Bondarenko 2023-12-21 00:52:56
fix!: declare Jass module user correctly c7f6b810ca76a7eee47213061a0740039ec95cec Vladyslav Bondarenko 2023-12-21 00:50:29
doc: add macro preprocessor caveat 651bad90dfe868626b5aa19331f674b9981f1dee Vladyslav Bondarenko 2023-12-20 01:55:27
doc: add macro preprocessor caveat 886e7960b79f1f13acd2359c44715dc157c6d7cf Vladyslav Bondarenko 2023-12-20 01:55:27
fix: fix typo in Makefile 652c3bd4a70f9f215a8f6824bc689596d173b85a Vladyslav Bondarenko 2023-12-20 01:33:56
doc: add basic build instructions 0fbeb1f61f266b7430d9365e3c282e64f751487d Vladyslav Bondarenko 2023-12-20 01:32:07
feat: add script dependency declarations 4dc32d10ed485bc6fd6856bffa269d4dcd2be4e0 Vladyslav Bondarenko 2023-12-20 01:30:33
feat!: improve Jass preprocessor ef275cd4087e2023c7107583685a5d1e40395786 Vladyslav Bondarenko 2023-12-20 01:21:07
feat: add arcane blast spell 1c2e8853a32b2c35ffdb1ea9d2342ff9bd9b8669 Vladyslav Bondarenko 2023-12-19 13:07:09
fix: unique hero per player c7910812bf1957513aab9067e817ca57634d4834 Vladyslav Bondarenko 2023-12-19 13:05:50
feat: heroes do not require resources to hire 717364a931afcde3496058a3f6100d95c92f7fe7 Vladyslav Bondarenko 2023-12-18 15:47:54
fix: add user force singleton 62f7007392e88829951855f9bd5eab3e7a5552aa Vladyslav Bondarenko 2023-12-17 13:02:08
doc: update design notes to self d8caf093082f02efc919b01cc7bfddd9193d0531 Vladyslav Bondarenko 2023-12-17 12:35:50
feat: add victory script 8d0299b42a3e61ffee708395017967dc288ed1b8 Vladyslav Bondarenko 2023-12-17 12:28:18
feat: summon any hero instantly b3657cf44de4558f3e6a2eac5d7916a036aa3dad Vladyslav Bondarenko 2023-12-16 04:19:10
fix: remove debug trace 7022f33a403d9d37f3f84acda98501ca76e1f981 Vladyslav Bondarenko 2023-12-16 04:18:53
Commit 61ddc9409c00c79ee947578291c21eaa701f41e2 - feat!: add spell Dampening Field
Author: Vladyslav Bondarenko
Author date (UTC): 2023-12-22 01:38
Committer name: Vladyslav Bondarenko
Committer date (UTC): 2023-12-22 01:38
Parent(s): 050948decf45ea58dd25b0eddf62d1593ed4460f
Signer:
Signing key: EFF9624877D25D02
Signing status: E
Tree: a5dcb133beedc39685e1a68d7b0c510fbe1e7114
File Lines added Lines deleted
honeydew.w3x 0 0
src/adum.j 280 122
File honeydew.w3x changed (mode: 100644) (index 9fb32d5..500999a)
File src/adum.j changed (mode: 100644) (index 0fae13d..e146a39)
1 1 // jass_module(`SRC_ADUM_J') // jass_module(`SRC_ADUM_J')
2 2 // jass_include(`SRC_SPELL_J', `src/spell.j') // jass_include(`SRC_SPELL_J', `src/spell.j')
3 3
4 // Spell Dampening Field.
5
6 // Create a circle of spell immunity at a target location. Every unit within
7 // the circle is granted the Spell Immunity passive ability. This spell may
8 // help enemies.
9
10 // When spell is cast, it creates an identity with all relevant properties.
11
12 // When adum_main_timer periodic timer expires, it iterates over every spell
13 // cast identity. First it clears adum_main_group. Then it re-populates the
14 // group.
15
16 // The group adum_main_group collects all units that are affected by any
17 // existing dampening field spell cast.
18
19 // Beside adum_main_timer callback, the above mentioned procedures of
20 // collecting and removing units from the group is done each time a dampening
21 // field spell effect is created or destroyed.
22
23 // When dampening field spell effect is created, a timer that is unique to the
24 // spell effect is attached to it. This timer will run the destructor when it
25 // expires and representes the spell effect's duration or lifespan.
26
27 // The computations are resource intensive. The hope is that the robustness is
28 // worth it. Units may die and be moved around in unexpected manner. The blunt
29 // iterator over time is expected to account for the most amount of corner
30 // cases.
31
4 32 globals globals
5 33
6 34 // src/adum.j fields // src/adum.j fields
7 35
8 36 constant integer ADUM_ABILITY_ID = 'A001' constant integer ADUM_ABILITY_ID = 'A001'
9 //constant integer ADUM_SPELL_IMMUNITY_ABILITY_ID = 'AImx'
10 constant integer ADUM_SPELL_IMMUNITY_ABILITY_ID = 'A002'
37 constant integer ADUM_SPELL_IMMUNITY_ABILITY_ID = 'ACm2'
11 38
12 39 constant real ADUM_RADIUS_BASE = 200.0 constant real ADUM_RADIUS_BASE = 200.0
13 40 constant real ADUM_RADIUS_COEF = 0.0 constant real ADUM_RADIUS_COEF = 0.0
 
... ... globals
19 46 constant real ADUM_DURATION_SEC_MAX = 3600.0 constant real ADUM_DURATION_SEC_MAX = 3600.0
20 47 constant real ADUM_DURATION_SEC_MIN = 1.0 constant real ADUM_DURATION_SEC_MIN = 1.0
21 48
22 effect array adum_area_effect
49 constant string ADUM_SPLAT_FILE = "ReplaceableTextures\\Splats\\TeleportTarget.blp"
50 constant integer ADUM_SPLAT_ENUM = 4
51
52 constant real ADUM_MAIN_TIMER_TIMEOUT_SEC = 0.5
53
23 54 integer array adum_ability_id integer array adum_ability_id
24 location array adum_center
25 real array adum_radius
26 timer array adum_destructor_timer
27 55 unit array adum_caster unit array adum_caster
56 location array adum_circle_center
57 real array adum_circle_radius
58 real array adum_duration_sec
59 timer array adum_timer
60 image array adum_decal
61 effect array adum_area_effect
28 62
29 filterfunc adum_group_filterfunc = null
30 group adum_group = null
31 integer adum_list_size = 0
63 integer adum_head = 0
64 group adum_main_group = null
65 timer adum_main_timer = null
32 66 endglobals endglobals
33 67
34 68 // src/adum.j functions // src/adum.j functions
35 69
36 function adum_timer_destroy_callback takes nothing returns nothing
37 local timer t = null
38 local integer i = 0
70 function adum_destroy takes integer i returns nothing
71 local integer j = 0
72 local integer p = 0
73 local integer q = 0
39 74
40 set t = GetExpiredTimer()
41 set i = 0
42 loop
43 exitwhen i >= JASS_MAX_ARRAY_SIZE or i >= adum_list_size
44 if t == adum_destructor_timer[i] then
45 call DestroyEffect(adum_area_effect[i])
46 call DestroyTimer(adum_destructor_timer[i])
47 call RemoveLocation(adum_center[i])
48
49 set adum_ability_id[i] = adum_ability_id[adum_list_size]
50 set adum_area_effect[i] = adum_area_effect[adum_list_size]
51 set adum_caster[i] = adum_caster[adum_list_size]
52 set adum_center[i] = adum_center[adum_list_size]
53 set adum_destructor_timer[i] = adum_destructor_timer[adum_list_size]
54 set adum_radius[i] = adum_radius[adum_list_size]
55
56 set adum_list_size = adum_list_size - 1
57
58 return
59 endif
60 set i = i + 1
61 endloop
62 endfunction
75 if i < 0 or i >= JASS_MAX_ARRAY_SIZE then
76 return
77 endif
63 78
64 function adum_apply takes integer ability_id, unit caster, location destination, real radius, real duration_sec returns integer
65 local integer circle = 0
66 local integer i = 0
67 local timer t = null
79 set j = adum_head
68 80
69 if null == destination then
70 return JASS_MAX_ARRAY_SIZE
81 if j < 0 or j >= JASS_MAX_ARRAY_SIZE then
82 return
71 83 endif endif
72 84
73 if adum_list_size >= JASS_MAX_ARRAY_SIZE then
74 return JASS_MAX_ARRAY_SIZE
75 endif
85 call DestroyEffect(adum_area_effect[i])
86 call DestroyTimer(adum_timer[i])
87 call RemoveLocation(adum_circle_center[i])
88 call DestroyImage(adum_decal[i])
76 89
77 set radius = RMinBJ(RMaxBJ(ADUM_RADIUS_MIN, radius), ADUM_RADIUS_MAX)
78 set duration_sec = RMinBJ(RMaxBJ(ADUM_DURATION_SEC_MIN, duration_sec), ADUM_DURATION_SEC_MAX)
79 set t = CreateTimer()
80 call TimerStart(t, duration_sec, false, function adum_timer_destroy_callback)
90 set p = i
91 loop
92 exitwhen p >= j or p >= JASS_MAX_ARRAY_SIZE
93
94 set q = p + 1
95 if q < JASS_MAX_ARRAY_SIZE then
96 set adum_ability_id[p] = adum_ability_id[q]
97 set adum_caster[p] = adum_caster[q]
98 set adum_circle_center[p] = adum_circle_center[q]
99 set adum_circle_radius[p] = adum_circle_radius[q]
100 set adum_duration_sec[p] = adum_duration_sec[q]
101 set adum_timer[p] = adum_timer[q]
102 set adum_decal[p] = adum_decal[q]
103 set adum_area_effect[p] = adum_area_effect[q]
104 endif
81 105
82 set i = adum_list_size
83 set adum_ability_id[i] = ability_id
84 set adum_area_effect[i] = AddSpellEffectByIdLoc(ability_id, EFFECT_TYPE_AREA_EFFECT, destination)
85 set adum_caster[i] = caster
86 set adum_center[i] = Location(GetLocationX(destination), GetLocationY(destination))
87 set adum_destructor_timer[i] = t
88 set adum_radius[i] = radius
106 set p = p + 1
107 endloop
108 endfunction
89 109
90 set adum_list_size = adum_list_size + 1
110 function adum_apply_group_filter takes nothing returns boolean
111 local boolean flag = true
112 local unit u = null
91 113
92 call BJDebugMsg("adum_apply: " + I2S(i))
93 return i
94 endfunction
114 set u = GetFilterUnit()
115 if null == u then
116 return false
117 endif
95 118
96 function adum_trig_filter takes nothing returns boolean
97 return ADUM_ABILITY_ID == GetSpellAbilityId()
119 set flag = GetUnitState(u, UNIT_STATE_LIFE) > 0.0 and flag
120 set flag = not IsUnitType(u, UNIT_TYPE_DEAD) and flag
121 set flag = not IsUnitType(u, UNIT_TYPE_STRUCTURE) and flag
122
123 return flag
98 124 endfunction endfunction
99 125
100 function adum_trig_action takes nothing returns nothing
101 local integer ability_level = 0
102 local integer ability_id = 0
103 local location destination = null
104 local real radius = 0.0
105 local real duration_sec = 0.0
106 local unit caster = null
126 function adum_apply_group_callback takes nothing returns nothing
127 local unit u = null
107 128
108 set ability_id = GetSpellAbilityId()
109 if 0 == ability_id then
129 set u = GetEnumUnit()
130 if null == u then
110 131 return return
111 132 endif endif
112 133
113 set destination = GetSpellTargetLoc()
134 if not IsUnitInGroup(u, adum_main_group) then
135 call UnitAddAbility(u, ADUM_SPELL_IMMUNITY_ABILITY_ID)
136 call GroupAddUnit(adum_main_group, u)
137 endif
138 endfunction
139
140 function adum_apply takes location destination, real radius returns nothing
141 local group g = null
142 local filterfunc filter = null
143
114 144 if null == destination then if null == destination then
115 145 return return
116 146 endif endif
117 147
118 set caster = GetSpellAbilityUnit()
148 set radius = RMinBJ(RMaxBJ(ADUM_RADIUS_MIN, radius), ADUM_RADIUS_MAX)
119 149
120 set ability_level = GetUnitAbilityLevel(caster, ability_id)
150 if null == adum_main_group then
151 set adum_main_group = CreateGroup()
152 endif
121 153
122 set radius = ADUM_RADIUS_BASE + ADUM_RADIUS_COEF * ability_level
123 set radius = RMinBJ(RMaxBJ(ADUM_RADIUS_MIN, radius), ADUM_RADIUS_MAX)
154 set g = CreateGroup()
155 set filter = Filter(function adum_apply_group_filter)
124 156
125 set duration_sec = ADUM_DURATION_SEC_BASE + ADUM_DURATION_SEC_COEF * ability_level
126 set duration_sec = RMinBJ(RMaxBJ(ADUM_DURATION_SEC_MIN, radius), ADUM_DURATION_SEC_MAX)
157 call GroupEnumUnitsInRangeOfLoc(g, destination, radius, filter)
127 158
128 call adum_apply(ability_id, caster, destination, radius, duration_sec)
159 call ForGroup(g, function adum_apply_group_callback)
129 160
130 call RemoveLocation(destination)
161 call DestroyGroup(g)
162 call DestroyFilter(filter)
131 163 endfunction endfunction
132 164
133 function adum_group_filter takes nothing returns boolean
134 local unit u = GetFilterUnit()
135 local boolean flag = true
165 function adum_unit_check takes unit u returns boolean
166 local integer i = 0
167 local location o = null
168 local real r = 0.0
169
136 170 if null == u then if null == u then
137 171 return false return false
138 172 endif endif
139 set flag = GetUnitState(u, UNIT_STATE_LIFE) > 0.0 and flag
140 set flag = not IsUnitType(u, UNIT_TYPE_DEAD) and flag
141 set flag = not IsUnitType(u, UNIT_TYPE_STRUCTURE) and flag
142 call BJDebugMsg("adum_group_filter: add " + GetUnitName(u))
143 return flag
173
174 set i = 0
175 loop
176 exitwhen i >= adum_head or i >= JASS_MAX_ARRAY_SIZE
177 set o = adum_circle_center[i]
178 set r = adum_circle_radius[i]
179 if IsUnitInRangeLoc(u, o, r) then
180 return true
181 endif
182 set i = i + 1
183 endloop
184 return false
144 185 endfunction endfunction
145 186
146 function adum_group_apply_callback takes nothing returns nothing
147 local unit u = GetEnumUnit()
148 call UnitAddAbility(u, ADUM_SPELL_IMMUNITY_ABILITY_ID)
149 call BJDebugMsg("src/adum.j: add " + GetUnitName(u))
187 function adum_unapply_group_callback takes nothing returns nothing
188 local unit u = null
189
190 set u = GetEnumUnit()
191 if null == u then
192 return
193 endif
194
195 if not adum_unit_check(u) then
196 call UnitRemoveAbility(u, ADUM_SPELL_IMMUNITY_ABILITY_ID)
197 endif
150 198 endfunction endfunction
151 199
152 function adum_group_clear_callback takes nothing returns nothing
153 local unit u = GetEnumUnit()
154 call UnitRemoveAbility(u, ADUM_SPELL_IMMUNITY_ABILITY_ID)
200 function adum_unapply takes group g returns nothing
201 if null == g then
202 return
203 endif
204 call ForGroup(g, function adum_unapply_group_callback)
205 call GroupClear(g)
155 206 endfunction endfunction
156 207
157 function adum_looper_action takes nothing returns nothing
158 local group g = adum_group
208 function adum_timer_callback takes nothing returns nothing
209 local timer t = null
159 210 local integer i = 0 local integer i = 0
160 local filterfunc filter = adum_group_filterfunc
161
162 call ForGroup(g, function adum_group_clear_callback)
163 call GroupClear(g)
211 local integer j = 0
164 212
165 213 set i = 0 set i = 0
214 set j = adum_head
215 set t = GetExpiredTimer()
166 216 loop loop
167 exitwhen i >= JASS_MAX_ARRAY_SIZE or i >= adum_list_size
168 call GroupEnumUnitsInRangeOfLoc(g, adum_center[i], adum_radius[i], filter)
217 exitwhen i >= j
218 if t == adum_timer[i] then
219 call adum_destroy(i)
220
221 set adum_head = adum_head - 1
222 endif
169 223 set i = i + 1 set i = i + 1
170 224 endloop endloop
171 call ForGroup(g, function adum_group_apply_callback)
225
226 if adum_main_group != null then
227 call adum_unapply(adum_main_group)
228 endif
229
230 if adum_head <= 0 then
231 call PauseTimer(adum_main_timer)
232 endif
233
234 call DestroyTimer(t)
172 235 endfunction endfunction
173 236
174 function adum_init takes nothing returns nothing
237
238 function adum_main_timer_callback takes nothing returns nothing
239 local unit c = null
175 240 local integer i = 0 local integer i = 0
176 local conditionfunc caster_filter = null
177 local trigger caster = null
178 local trigger looper = null
241 local integer j = 0
179 242
180 set adum_list_size = 0
181 set adum_group = CreateGroup()
182 set adum_group_filterfunc = Filter(function adum_group_filter)
243 call adum_unapply(adum_main_group)
183 244
184 245 set i = 0 set i = 0
246 set j = adum_head
185 247 loop loop
186 exitwhen i >= JASS_MAX_ARRAY_SIZE
187 set adum_ability_id[i] = 0
188 set adum_area_effect[i] = null
189 set adum_caster[i] = null
190 set adum_center[i] = null
191 set adum_destructor_timer[i] = null
192 set adum_radius[i] = 0.0
248 exitwhen i >= j
249
250 call adum_apply(adum_circle_center[i], adum_circle_radius[i])
251
252 // Given the spell was cast by a unit,
253 // given the unit is dead,
254 // destroy the spell effect.
255 set c = adum_caster[i]
256 if c != null then
257 if GetUnitState(c, UNIT_STATE_LIFE) < 1.0 or IsUnitType(c, UNIT_TYPE_DEAD) then
258 call adum_destroy(i)
259
260 set adum_head = adum_head - 1
261 endif
262 endif
263
193 264 set i = i + 1 set i = i + 1
194 265 endloop endloop
266 endfunction
267
268 function adum_cast takes integer ability_id, unit caster, location destination, real radius, real duration_sec returns nothing
269 local image splat = null
270 local integer i = 0
271 local real s = 0.0
272 local real x = 0.0
273 local real y = 0.0
274 local real z = 0.0
275
276 if null == destination then
277 return
278 endif
279
280 set radius = RMinBJ(RMaxBJ(ADUM_RADIUS_MIN, radius), ADUM_RADIUS_MAX)
281
282 set duration_sec = RMinBJ(RMaxBJ(ADUM_DURATION_SEC_MIN, duration_sec), ADUM_DURATION_SEC_MAX)
283
284 if adum_head < 0 or adum_head >= JASS_MAX_ARRAY_SIZE then
285 return
286 endif
287
288 set i = adum_head
289
290 set adum_ability_id[i] = ability_id
291 set adum_caster[i] = caster
292 set x = GetLocationX(destination)
293 set y = GetLocationY(destination)
294 set adum_circle_center[i] = Location(x, y)
295 set adum_circle_radius[i] = radius
296 set adum_duration_sec[i] = duration_sec
297 set adum_timer[i] = CreateTimer()
298 call TimerStart(adum_timer[i], duration_sec, false, function adum_timer_callback)
299
300 set s = radius * 2.0
301 set z = 24.0
302 set splat = CreateImage(ADUM_SPLAT_FILE, s, s, s, x - radius, y - radius, z, 0, 0, 0, ADUM_SPLAT_ENUM)
303 // It is mandatory to call SetImageRenderAlways after CreateImage
304 call SetImageRenderAlways(splat, true)
305 call ShowImage(splat, true)
306 set adum_decal[i] = splat
307
308 set adum_area_effect[i] = AddSpellEffectByIdLoc(adum_ability_id[i], EFFECT_TYPE_AREA_EFFECT, adum_circle_center[i])
309
310 set adum_head = adum_head + 1
311 if adum_head < 0 or adum_head >= JASS_MAX_ARRAY_SIZE then
312 set adum_head = 0
313 endif
314
315 call adum_apply(adum_circle_center[i], adum_circle_radius[i])
316
317 call TimerStart(adum_main_timer, ADUM_MAIN_TIMER_TIMEOUT_SEC, true, function adum_main_timer_callback)
318 endfunction
319
320 function adum_trig_filter takes nothing returns boolean
321 return ADUM_ABILITY_ID == GetSpellAbilityId()
322 endfunction
323
324 function adum_trig_action takes nothing returns nothing
325 local integer ability_id = 0
326 local integer ability_level = 0
327 local unit caster = null
328 local location destination = null
329 local real radius = 0.0
330 local real duration_sec = 0.0
331
332 set ability_id = GetSpellAbilityId()
333 set ability_level = GetUnitAbilityLevel(caster, ability_id)
334 set caster = GetSpellAbilityUnit()
335 set destination = GetSpellTargetLoc()
336
337 set radius = ADUM_RADIUS_BASE + ADUM_RADIUS_COEF * ability_level
338 set radius = RMinBJ(RMaxBJ(ADUM_RADIUS_MIN, radius), ADUM_RADIUS_MAX)
339
340 set duration_sec = ADUM_DURATION_SEC_BASE + ADUM_DURATION_SEC_COEF * ability_level
341 set duration_sec = RMinBJ(RMaxBJ(ADUM_DURATION_SEC_MIN, duration_sec), ADUM_DURATION_SEC_MAX)
342
343 call adum_cast(ability_id, caster, destination, radius, duration_sec)
344
345 call RemoveLocation(destination)
346 endfunction
347
348 function adum_init takes nothing returns nothing
349 local trigger trig = null
350 local conditionfunc filter = null
195 351
196 set caster_filter = Condition(function adum_trig_filter)
197 set caster = spell_trig_init(caster_filter, function adum_trig_action)
352 set adum_head = 0
353 set adum_main_group = CreateGroup()
354 set adum_main_timer = CreateTimer()
355 call TimerStart(adum_main_timer, ADUM_MAIN_TIMER_TIMEOUT_SEC, true, function adum_main_timer_callback)
356 call PauseTimer(adum_main_timer)
198 357
199 set looper = CreateTrigger()
200 call TriggerRegisterTimerEvent(CreateTrigger(), 0.5, true)
201 call TriggerAddAction(looper, function adum_looper_action)
358 set filter = Condition(function adum_trig_filter)
359 set trig = spell_trig_init(filter, function adum_trig_action)
202 360 endfunction endfunction
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/vrtc/honeydew

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/vrtc/honeydew

Clone this repository using git:
git clone git://git.rocketgit.com/user/vrtc/honeydew

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main