Snippet Rally Sound Replacement

Weep

Godspeed to the sound of the pounding
Reaction score
400
As someone who likes playing with GUI despite having some coding knowledge, as someone who cannot use NewGen/vJASS due to a lack of a release of JNGP for Mac (and therefore cannot use any of the available indexing/attaching systems), and as someone who finds MUI arrays to be unwieldy, annoying, inelegant, and flawed (although their 8191 instance limit would be rare to ever hit), my heart did a little backflip when I noticed that Rally could be used to "attach" a location or unit to a dummy...<3

...until I found out that setting the rally-point would play the rally-point noise regardless of whether the unit is selected, has the Locust ability, etc. etc. etc. It's not great to cast a spell only to hear "PLUNKT PLUNKT PLUNKT PLUNKT". :thdown:

This snippet-system fixes that by overwriting the default rally-point noise with silence, and playing the re-imported rally-point noise, exactly as happens without the system, except it excludes Locust units and units that do not have the stock Rally ability.

--------------------------------------------------------------------------------------

This whole abuse of Rally will probably be made obsolete by hashtables once patch 1.24 is out (assuming Blizzard fixes the World Editor for Mac to function properly with 1.24, because presently 1.24 utterly cripples it), and I don't really expect anyone else to adopt this paradigm...but since I'm planning to post some spells that I've made using this snippet-system, I figured it ought to be here for review. (Previously discussed here.)

--------------------------------------------------------------------------------------

Description and instructions:
JASS:
//*********************************************************************************************
//* Rally Sound Replacement -- v1 -- by Weep                                                  *
//*                                                                                           *
//*    Requires: the sound files &quot;silence.wav&quot; and &quot;RallyPointPlace.mp3&quot;, included in its     *
//*    download archive.  If you are importing this system from a map, export the sound       *
//*    &quot;silence.wav&quot; from Imported &gt; war3mapimported, and the music &quot;RallyPointPlace.mp3&quot;     *
//*    from Music &gt; Imported &gt; war3mapimported.                                               *
//*                                                                                           *
//* -- What? --                                                                               *
//*    This snippet-system will play the rally-point-set sound only if the commanded unit is  *
//*    not a dummy, based on two basic conditions: the unit does not have the Locust ability, *
//*    and has the standard Rally ability.                                                    *
//*                                                                                           *
//* -- Why? --                                                                                *
//*    Setting a unit&#039;s rally-point is a versatile and native way to associate a unit with    *
//*    another unit or location.  Using it to associate a target or caster with a dummy unit  *
//*    that&#039;s purposed as a projectile is easily implemented, even in GUI, and requires no    *
//*    other systems or unweildy MUI arrays (and is not limited to 8191 values).              *
//*                                                                                           *
//*    The problem is that any unit that is having its rally-point set will play that         *
//*    &quot;plunkt&quot; sound for the owner of that unit, regardless of whether the unit is meant to  *
//*    be an actual unit in play, or just a dummy or effect.  This fixes that problem.        *
//*                                                                                           *
//*    This technique (using rally-points for targeting) will probably be made obsolete by    *
//*    hashtables when patch 1.24 goes live.                                                  *
//*                                                                                           *
//* -- How To Implement --                                                                    *
//*    1. Open the Sound Editor and find RallyPointPlace1.wav under Sound &gt; Interface.        *
//*    2. Right-click that sound and select &quot;Replace Internal Sound&quot;.  Select the file        *
//*       &quot;silence.wav&quot; included in the download archive.                                     *
//*    3. Import the file &quot;RallyPointPlace.mp3&quot; included in the download archive.             *
//*    4. Right-click the imported sound (it will be in Music &gt; Imported &gt; war3mapimported)   *
//*       and select &quot;Use As Sound&quot;.                                                          *
//*    5. Be sure &quot;Automatically create unknown variables while pasting trigger data&quot; is      *
//*       enabled in the World Editor general preferences.                                    *
//*    6. Copy this trigger category (&quot;Rally Sound Replacement&quot;) and paste it into your map.  *
//*                                                                                           *
//*    Units that have the Locust ability (typically found on dummy units) will not trigger   *
//*    the rally-point sound.  Another way to avoid the sound is to copy the Rally ability    *
//*    and give that to any unit that you do not want to trigger a rally-point sound in       *
//*    place of the normal Rally ability.                                                     *
//*                                                                                           *
//* -- Notes --                                                                               *
//*    This snippet-system should not interfere with existing abilities, units, or triggers   *
//*    in your map, except in the case that you are specifically playing the rally-point      *
//*    sound in an ability or trigger.                                                        *
//*                                                                                           *
//* -- Some observations about rally-points and their usage --                                *
//*    The action of setting a rally-point will interrupt a unit&#039;s current orders.            *
//*                                                                                           *
//*    Rally-points can only be set onto units owned by the same player as the unit having    *
//*    its rally-point set.  However, a unit&#039;s rally-point will remain even if the unit       *
//*    changes owner.  To set a rally-point onto any player&#039;s unit, change the ownership of   *
//*    the unit having its rally-point set to the owner of the intended rally target,         *
//*    then change it back.                                                                   *
//*                                                                                           *
//*    If a unit that another unit has set as a rally-point changes owner, the rally-point    *
//*    will be lost.  If you do not want this to happen, you&#039;ll need to detect all units      *
//*    that have the changing unit as their rally-point, and use the method above to reset    *
//*    their rally-point to the unit after it has changed ownership.                          *
//*                                                                                           *
//*    If a unit loses its current rally-point, its rally-point will be set to itself.        *
//*                                                                                           *
//*    A unit&#039;s rally-point can still be retrieved at its death event.                        *
//*                                                                                           *
//*********************************************************************************************

Code:
JASS:
// Global variables: group udg_Weep_RallyCheckGroup
//                   force udg_Weep_RallySoundForce
//                   sound gg_snd_RallyPointPlace

function PlayRallySoundForceCallback takes nothing returns nothing
	call SetSoundVolume(gg_snd_RallyPointPlace, 90)
	if (GetLocalPlayer() == GetEnumPlayer()) then
		call StartSound(gg_snd_RallyPointPlace)
		// &quot;Plunkt&quot;
	endif
	call ForceRemovePlayer(udg_Weep_RallySoundForce, GetEnumPlayer())
endfunction

function PlayRallySoundForce takes nothing returns nothing
	call ForForce(udg_Weep_RallySoundForce, function PlayRallySoundForceCallback)
	call DestroyTimer(GetExpiredTimer())
endfunction

function PlayRallySoundGroupCallback takes nothing returns nothing
	if (GetUnitCurrentOrder(GetEnumUnit()) != 851980) then // 851980 = String2OrderIdBJ(&quot;smart&quot;)
	// If, an instant later, the unit&#039;s order is not still &#039;smart&#039;, it had its rally point set by the order, and we should play the sound anew:
		if (GetLocalPlayer() == GetOwningPlayer(GetEnumUnit())) then
			call StopSound(gg_snd_RallyPointPlace, false, false)
		endif
		call ForceAddPlayer(udg_Weep_RallySoundForce, GetOwningPlayer(GetEnumUnit()))
		call TimerStart(CreateTimer(), 0.00, false, function PlayRallySoundForce)
		// Because, for some reason, if the sound is already playing, calling StopSound immediately followed by StartSound
		// will only stop the sound, not also play it again.  An instant timer is enough delay to make it work.
	endif
	call GroupRemoveUnit(udg_Weep_RallyCheckGroup, GetEnumUnit())
endfunction

function PlayRallySoundGroup takes nothing returns nothing
	call ForGroup(udg_Weep_RallyCheckGroup, function PlayRallySoundGroupCallback)
	call DestroyTimer(GetExpiredTimer())
endfunction

function RallySoundConditionAction takes nothing returns boolean
	if (GetUnitAbilityLevel(GetTriggerUnit(), &#039;ARal&#039;) &gt; 0 and (not (GetUnitAbilityLevel(GetTriggerUnit(), &#039;Aloc&#039;) &gt; 0))) then
		if (GetIssuedOrderId() == 851971) then // 851971 = String2OrderIdBJ(&quot;setrally&quot;)
			if (GetLocalPlayer() == GetOwningPlayer(GetTriggerUnit())) then
				call StopSound(gg_snd_RallyPointPlace, false, false)
			endif
			call ForceAddPlayer(udg_Weep_RallySoundForce, GetOwningPlayer(GetTriggerUnit()))
			call TimerStart(CreateTimer(), 0.00, false, function PlayRallySoundForce)
		elseif (GetIssuedOrderId() == 851980) then // 851980 = String2OrderIdBJ(&quot;smart&quot;)
			// If, an instant later, the unit&#039;s order is still &#039;smart&#039;, it did not have its rally point set by the order, so we test:
			call GroupAddUnit(udg_Weep_RallyCheckGroup, GetTriggerUnit())
			call TimerStart(CreateTimer(), 0.00, false, function PlayRallySoundGroup)
		endif
	endif
	return false
endfunction

function InitTrig_RallySoundReplacement takes nothing returns nothing
	local trigger t = CreateTrigger()
	call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
	call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
	call TriggerAddCondition(t, Condition(function RallySoundConditionAction))
endfunction

--------------------------------------------------------------------------------------

The attached archive contains the necessary sound files and a demo map with the trigger ready to copy, as well as 3 MUI/MPI/SUI demo spells making use of this method. It also has a building in the middle just to show that Rally still makes noise like usual.

Demo spells:
Frost Orb
Launches a floating orb of frost that will track the target unit. Enemies near the orb will have their attack and movement speed decreased 50%. The orb will dissipate after 30 seconds, or if the target dies.

Trigger:
  • Frost Orb Cast
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Frost Orb
    • Actions
      • Set TempPoint = (Position of (Triggering unit))
      • Unit - Create 1 Frost Orb for (Owner of (Target unit of ability being cast)) at TempPoint facing Default building facing degrees
      • Unit - Add Rally to (Last created unit)
      • Unit - Set Rally-Point for (Last created unit) to (Target unit of ability being cast)
      • Unit - Change ownership of (Last created unit) to (Owner of (Triggering unit)) and Change color
      • Unit - Add Crow Form to (Last created unit)
      • Unit - Remove Crow Form from (Last created unit)
      • Unit - Add a 30.00 second Generic expiration timer to (Last created unit)
      • Unit Group - Add (Last created unit) to Example_FrostOrbGroup
      • Custom script: call RemoveLocation(udg_TempPoint)

Trigger:
  • Frost Orb Slide
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in Example_FrostOrbGroup and do (Actions)
        • Loop - Actions
          • Set TempUnit = (Rally-Point of (Picked unit) as a unit)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (TempUnit is alive) Equal to True
              • ((Picked unit) is alive) Equal to True
              • (Life of TempUnit) Greater than or equal to 0.40
              • TempUnit Not equal to (Picked unit)
            • Then - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • ((Playable map area) contains TempUnit) Equal to True
                • Then - Actions
                  • Set TempPoint = (Position of (Picked unit))
                  • Set TempPoint2 = (Position of TempUnit)
                  • Set TempReal = (Angle from TempPoint to TempPoint2)
                  • Set TempReal2 = (Min((Distance between TempPoint and TempPoint2), 6.00))
                  • Custom script: call RemoveLocation(udg_TempPoint2)
                  • Set TempPoint2 = (TempPoint offset by TempReal2 towards TempReal degrees)
                  • Custom script: call RemoveLocation(udg_TempPoint)
                  • Custom script: call SetUnitX(GetEnumUnit(), GetLocationX(udg_TempPoint2))
                  • Custom script: call SetUnitY(GetEnumUnit(), GetLocationY(udg_TempPoint2))
                  • Custom script: call RemoveLocation(udg_TempPoint2)
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • ((Triggering unit) is A flying unit) Equal to True
                    • Then - Actions
                      • Animation - Change (Picked unit) flying height to (Current flying height of TempUnit) at 5.00
                    • Else - Actions
                      • Animation - Change (Picked unit) flying height to ((Current flying height of TempUnit) + 60.00) at 5.00
                • Else - Actions
            • Else - Actions
              • Unit Group - Remove (Picked unit) from Example_FrostOrbGroup
              • Unit - Kill (Picked unit)

Fire Orb
Launches a floating orb of fire that will circle the caster and automatically attack nearby enemies. The orb will dissipate after 30 seconds, or if the caster dies.

If the caster is attacked, the attacking unit will take damage proportional to the number of fire orbs tracking the caster.

Trigger:
  • Fire Orb Cast
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Fire Orb
    • Actions
      • Set TempPoint2 = (Position of (Triggering unit))
      • Set TempPoint = (TempPoint offset by 200.00 towards (Facing of (Triggering unit)) degrees)
      • Unit - Create 1 Fire Orb for (Owner of (Triggering unit)) at TempPoint facing Default building facing degrees
      • Animation - Change (Last created unit) prop window angle to ((Real((((Integer((Facing of (Triggering unit)))) / 2) x 2))) + 1.00)
      • Unit - Add Rally to (Last created unit)
      • Unit - Set Rally-Point for (Last created unit) to (Triggering unit)
      • Unit - Add a 30.00 second Generic expiration timer to (Last created unit)
      • Unit Group - Add (Last created unit) to Example_FireOrbGroup
      • Custom script: call RemoveLocation(udg_TempPoint)
      • Custom script: call RemoveLocation(udg_TempPoint2)

Trigger:
  • Fire Orb Slide
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in Example_FireOrbGroup and do (Actions)
        • Loop - Actions
          • Set TempUnit = (Rally-Point of (Picked unit) as a unit)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (TempUnit is alive) Equal to True
              • ((Picked unit) is alive) Equal to True
              • (Life of TempUnit) Greater than or equal to 0.40
              • TempUnit Not equal to (Picked unit)
            • Then - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • ((Playable map area) contains TempUnit) Equal to True
                • Then - Actions
                  • Set TempPoint = (Position of TempUnit)
                  • Set TempPoint2 = (TempPoint offset by 200.00 towards (Current prop window angle of (Picked unit)) degrees)
                  • Custom script: call RemoveLocation(udg_TempPoint)
                  • Custom script: call SetUnitX(GetEnumUnit(), GetLocationX(udg_TempPoint2))
                  • Custom script: call SetUnitY(GetEnumUnit(), GetLocationY(udg_TempPoint2))
                  • Custom script: call RemoveLocation(udg_TempPoint2)
                  • Unit - Make (Picked unit) face TempUnit over 0.00 seconds
                  • Animation - Change (Picked unit) prop window angle to (((Current prop window angle of (Picked unit)) + 4.00) mod 360.00)
                • Else - Actions
            • Else - Actions
              • Unit Group - Remove (Picked unit) from Example_FireOrbGroup
              • Unit - Kill (Picked unit)

Trigger:
  • Fire Orb Retaliation
    • Events
      • Unit - A unit Is attacked
    • Conditions
    • Actions
      • Set TempGroup = (Units owned by (Owner of (Triggering unit)) matching ((((Matching unit) is in Example_FireOrbGroup) Equal to True) and ((Rally-Point of (Matching unit) as a unit) Equal to (Triggering unit))))
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Number of units in TempGroup) Greater than 0
        • Then - Actions
          • Unit - Cause (Triggering unit) to damage (Attacking unit), dealing ((Real((Number of units in TempGroup))) x 5.00) damage of attack type Spells and damage type Normal
          • Special Effect - Create a special effect attached to the origin of (Attacking unit) using Abilities\Weapons\RedDragonBreath\RedDragonMissile.mdl
          • Special Effect - Destroy (Last created special effect)
        • Else - Actions
      • Custom script: call DestroyGroup(udg_TempGroup)

Death Orb
Launches a shotgun spray of death orbs that will damage the first enemy they hit.

Trigger:
  • Death Orb Cast
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Death Orb
    • Actions
      • Set TempPoint = (Position of (Triggering unit))
      • Set TempPoint2 = (Target point of ability being cast)
      • For each (Integer A) from 1 to 7, do (Actions)
        • Loop - Actions
          • Unit - Create 1 Death Orb for (Owner of (Triggering unit)) at TempPoint facing ((Angle from TempPoint to TempPoint2) + (((Real((Integer A))) - 4.00) x 5.00)) degrees
          • Custom script: call SetUnitX(GetLastCreatedUnit(), GetLocationX(udg_TempPoint))
          • Custom script: call SetUnitY(GetLastCreatedUnit(), GetLocationY(udg_TempPoint))
          • Unit - Add Rally to (Last created unit)
          • Unit - Set Rally-Point for (Last created unit) to (Triggering unit)
          • Unit - Add a 1.15 second Generic expiration timer to (Last created unit)
          • Unit Group - Add (Last created unit) to Example_DeathOrbGroup
      • Custom script: call RemoveLocation(udg_TempPoint)
      • Custom script: call RemoveLocation(udg_TempPoint2)

Trigger:
  • Death Orb Slide
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in Example_DeathOrbGroup and do (Actions)
        • Loop - Actions
          • Set TempUnit = (Rally-Point of (Picked unit) as a unit)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (TempUnit is alive) Equal to False
            • Then - Actions
              • Unit - Set Rally-Point for (Picked unit) to (Picked unit)
            • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • ((Picked unit) is alive) Equal to True
            • Then - Actions
              • Set TempPoint = (Position of (Picked unit))
              • Set TempPoint2 = (TempPoint offset by 21.00 towards (Facing of (Picked unit)) degrees)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • ((Playable map area) contains TempPoint2) Equal to True
                • Then - Actions
                  • Custom script: call SetUnitX(GetEnumUnit(), GetLocationX(udg_TempPoint2))
                  • Custom script: call SetUnitY(GetEnumUnit(), GetLocationY(udg_TempPoint2))
                  • Set TempGroup = (Units within 75.00 of TempPoint2 matching ((((Matching unit) belongs to an enemy of (Owner of (Picked unit))) Equal to True) and (((Matching unit) is alive) Equal to True)))
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Number of units in TempGroup) Greater than 0
                    • Then - Actions
                      • Unit - Cause TempUnit to damage (Random unit from TempGroup), dealing 30.00 damage of attack type Spells and damage type Normal
                      • -------- -------------------------------------------------------------------- --------
                      • -------- If there was no rally-point and you just caused the dummy to damage the target, --------
                      • -------- the damaged unit would not aggro onto the caster! --------
                      • -------- -------------------------------------------------------------------- --------
                      • Unit Group - Remove (Picked unit) from Example_FrostOrbGroup
                      • Unit - Kill (Picked unit)
                    • Else - Actions
                  • Custom script: call DestroyGroup(udg_TempGroup)
                • Else - Actions
                  • Unit Group - Remove (Picked unit) from Example_FrostOrbGroup
                  • Unit - Remove (Picked unit) from the game
              • Custom script: call RemoveLocation(udg_TempPoint)
              • Custom script: call RemoveLocation(udg_TempPoint2)
            • Else - Actions
              • Unit Group - Remove (Picked unit) from Example_FrostOrbGroup

--------------------------------------------------------------------------------------

Comments pointing out problems, improvements, and allowability as a system required by submitted spells are welcome.
 

Attachments

  • Rally Sound Replacement v1.zip
    76.6 KB · Views: 204

quraji

zap
Reaction score
144
Hmmm, that's a pretty neat trick. Now if only I new what a rally point was in game :p
 

Weep

Godspeed to the sound of the pounding
Reaction score
400
Well, normally, Rally is an ability on buildings that can produce units. It sets a point or target unit to which all units produced by that building will move. Since you can retrieve that point or unit with triggers, though, it was ripe for abuse in this manner, provided this fix for that annoying noise. :p
 

Weep

Godspeed to the sound of the pounding
Reaction score
400
Ah, J4L. I've seen your systems and, as far as I'm able to understand how they're used, have been quite impressed; others' systems also (although I admit sometimes I wonder whether your aim is productivity or simple "my efficiency is bigger than yours" competitions ;)). I'd love to use them instead of dozens of arrays or clever application of every random value and setting available in GUI, but as I mentioned in the original post, any system or library that requires NewGen or a vJASS preprocessor is utterly useless for me due to the lack of any such program made for my computing platform of choice. For the most part, as soon as I see "scope" or "library" or "globals" or "private", I might as well stop reading.

As an aside, if it would be possible to release these systems in a stock JASS form, I might be interested, and certainly very appreciative of the effort to support all WC3 developers. :thup:
 

quraji

zap
Reaction score
144
Isn't there a cross platform vJass compiler? I think Vexorian uses Linux so no newgen for him, I believe....
 

Weep

Godspeed to the sound of the pounding
Reaction score
400
I'm not aware of one existing for Mac. The last word I saw was Vex saying that a Mac version might be coming "soon"...I think this was in 2006. He also posted a tutorial about running JassHelper in a virtual machine (or was it DarWINE?) and then manually inserting the resultant map script into your .w3x - not practical.

It also looks like this won't be obsoleted by hashtables, because the editor for Mac is still incompatible with the release version of the 1.24 patch, meaning the new functions/natives will not successfully compile.
 

GetTriggerUnit-

DogEntrepreneur
Reaction score
129
How about importing a blank sound and putting it custom path to the path of the rally point sound?

I'll also try to find the path.

I found the path:
Sound\Interface\Warning\RallyPointPlace1.wav
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top