Wc3C.net

Wc3C.net (http://www.wc3c.net/forums.php)
-   vJass Spells (http://www.wc3c.net/forumdisplay.php?f=647)
-   -   Apocalypse (http://www.wc3c.net/showthread.php?t=101331)

Flame_Phoenix 07-07-2008 09:20 AM

Apocalypse
 
2 Attachment(s)
Hi people. After remaking the spell 4 times, here it is, the final version of my spell Apocalypse. The definitive proof that persistence and good will, will always win above the adversities and problems of the world, that those who never quit, no matter how hard things get, will win, no matter what.

This spell if also for the contest Spell Contest #11. I really think it fits to the theme "cinematic" because it was based on one, and it has a very strong connection to the game =)

This is my first vJASS spell and JESP spell (boy, am I tired of writing this sentence xD). It is fully customizable and I hope you all like it.
I also followed Moyack's suggestion, and now the caster has a nice buff (well, it is just slow, but you can pick something better xD) when he casts the spell.
The important parts of the code are also commented, with comments from me, Vexorian and others. This way it is easier for people to change the code if they need.

This spell belongs to my project
Castle vs Castle Flame Edition and I hope you all enjoy it.


Description:
Spell inspired in the classic Apocalypse spell, and inspired in the first introducing Warcraft movie. Just as in the beginning of times, when the Legion first Step into this world, meteors will fall from the sky and Infernals may be spawned.

Attachment 35430

Requirements:
- Jass NewGen Pack (uses vJASS)
- Table
- TimerUtils

Credits:
- Cohadar, Vexorian, Anitarf, Moyack, Themerion, Captain Griffen, tamisrah, Pyrogasm, chobibo, spiwn, and last, but not least, my first teacher of vJASS: Blue_Jeans
- All other people I ignored or forgot

History:
Hidden information:

Version 1.0
- Initial release

Version 1.1
- Removed PolarProjectionBJ and IssueOrderLocBJ, thus optimizing greatly the efficiency of the spell
- Fixed some locations that were leaking. Now everything is done with coordinates, thus being even faster
- Greatly improved the comments on the code, replace old and wrong comments by new ones.
- Decreased the infernal spawn chance to 4%, 7% and 10% according to the levels, changed the formula as well
- Improved the tooltips to match the changes made

Version 1.2
- Now the meteors only hurt enemy units
- Fixed a small bug, in the PolarProjection calculus with coordinates, replace GetUnitX, with GetUnitY, as it should be

Version 1.3
- Fixed the dummy unit, the iddle symbol no longer appears and improved the comments on the code

Version 1.4
- Added a line of code to prevent leaks, the B timer was not being destroyed correctly
- Improved the map, added some trees, so people can see the spell also affects them

Version 1.5
- Refixed the data.expirer timer. It was running on background without people knowing. This could bring serious lag problems, but now is fixed

Version 1.6
- Made the spell a lot more simple to import and configure !! Now you just need to copy paste the code, and change the rawcodes at the top !
- Improved the comments so you know what you have to do !

Version 1.7
- Added "call data.destroy()" in the end to prevent any possible leaks

Version 1.8
- Added more functions of implementation. The spell is now even easier to change !

Version 2.2
- Versions 1.9, 2.0, and 2.1 were not realeased, they were testing versions for version 2.2
- Great improvements in everything. Made the spell more JESP, removed and optimized useless functions as well as the algorithm for falling meteors.
- Now the code compiles with the guide lines of vJASS
- Added a recycling system, so the spell is faster easier

Version 2.6
- Versions 2.3 , 2.4 and 2.5 were beta tests.
- The spell was 100% changed to better !

Version 2.7
- Upgraded the spell, now it uses TimerUtils, the most recent timer system to date.

Version 2.7.1:
- Now compatible with patch 1.24.
- Updated the credits.


The spell was improved. Now the range of the spell depends on your level !! (only if you want xD)

Collapse JASS:
//===========================================================================
//A spell that makes meteors fall randomly in the map, damaging enemy units
//and maybe summoning powerfull infernals
//
//Requires:
// - TimerUtils
// - Table
//
//@author:
// - Flame_Phoenix 
//
//@credits:
// - Cohadar, Vexorian, Anitarf, Moyack, Themerion, Captain Griffen, tamisrah, 
//Pyrogasm, chobibo, spiwn, for their help in teh code.
// - Daelin for the inspiration and the idea
// - And last, but not least, Blue_Jeans, my first teacher of vJASS
//
//
//@version 2.7.1
//===========================================================================
scope Apocalypse initializer Init
//===========================================================================
//=============================SETUP START===================================
//===========================================================================
    
    globals
        private constant integer AID = 'A004'  //The rawcode of the Apocalypse ability 
        private constant integer INFERNAL = 'A002' //The rawcode of the Infernal ability
        private constant string INFERNALORDER = "dreadlordinferno" //the string order for Infernal
        private constant integer SPAWN = 'A003' //The rawcode for FlameStrike when we want to spawn an Infernal
        private constant string SPAWNORDER = "flamestrike" //the order for the FlameStrike ability when we spawn an Infernal
        private constant integer NO_SPAWN = 'A001' //The rawcode of the FlameStrike ability when we don't want to spanw an Infernal
        private constant string NO_SPAWNORDER = "flamestrike" //the order for the FlameStrike ability when we don't spawn an Infernal
        private constant integer DUMMY_RAW = 'h000' //rawcode of the dummy caster
        private constant real DUMMY_LIFE = 3.0 //The timed life of the dummy unit caster
    endglobals

    private constant function meteorCicle takes integer level returns real
        return 4.0 / level //the time interval that separates each serie (a cicle)
    endfunction
    
    private constant function infernalChance takes integer level returns integer
        //the chances you have to spawn an infernal each time a meteor falls
        // from 0 to 100
        return 3 * level + 1 
    endfunction 
    
    private constant function meteorSeries takes integer level returns integer
        //the number of series. Each serie is separated by a cicle and each
        //serie makes meteorsPerSerie meteors fall
        return 5 + (5 * level) 
    endfunction
    
    private constant function meteorsPerSerie takes integer level returns integer
        //the number of meteors that fall per serie
        local integer value = 0
        
        if (level < 3) then
            set value = 1
        else
            set value = 2
        endif
        
        //In this case, in levels 1 and 2, it will make fall 1 meteor per serie
        //in level 3 makes 2 meteors per serie fall
        return value 
    endfunction
    
    private constant function minimumRange takes integer level returns real
        //Minimal range. Meteors won't fall before this number. 
        return (level * 0) + 200. 
    endfunction
   
    private constant function maximumRange takes integer level returns real
        //Maximum range of spell. Meteors won't fall after this number
        return (level * 0) + 600. 
    endfunction
//===========================================================================
//=============================SETUP END=====================================
//===========================================================================
    globals 
        private group ApocalypseCasters = CreateGroup()
        private HandleTable activeTable //your private Table's global variable
    endglobals
   
   private struct MyStruct
        unit caster
        integer level
        timer repeator
        integer serieCounter 
        integer serieLimit 
    
       static method create takes unit caster returns MyStruct
            local MyStruct data = MyStruct.allocate()
            
            //set variables
            set data.caster = caster
            set data.level = GetUnitAbilityLevel(data.caster, AID)
            set data.repeator = NewTimer()
            set data.serieCounter = 0
            set data.serieLimit = meteorSeries(data.level)
        
            return data
        endmethod
        
        method onDestroy takes nothing returns nothing
            //this will clean all mess
            //since the spell is not active anymore, we clean the Table      
            call activeTable.flush(.caster) 
            
            //the unit is not anymore in the active units group.
            call GroupRemoveUnit(ApocalypseCasters, .caster) 
            
            call ReleaseTimer(.repeator)
        endmethod

    endstruct
//==========================================================================
    private function onDeath takes nothing returns boolean
        local MyStruct data
        local unit u = GetTriggerUnit()
        
        //this will save you unnecessary gamecache calls during units' deaths. 
        //It also prevents conflicts with units getting the same handle id as a ghost, 
        //however, since you flush when the spell ends that's most likely not an issue.

        if(IsUnitInGroup(u, ApocalypseCasters)) then
            set data = activeTable[u] //recover that data (the struct) from the caster
            call data.destroy()
        endif
        
        set u = null
        return false
    endfunction
//==========================================================================
    //Function made by Vexorian, it selects a random region in a disk. 
    //All regions have the same chance of beeing choosen
    private function GetRandomPointInDisk takes real centerx, real centery, real minradius, real maxradius returns location
        local real d = SquareRoot(GetRandomReal(minradius * minradius, maxradius * maxradius))
        local real a = GetRandomReal(0, 2 * bj_PI)
        return Location(centerx + d * Cos(a), centery + d * Sin(a))
    endfunction
//==========================================================================
    private function Effect takes nothing returns nothing
        local MyStruct data = MyStruct(GetTimerData(GetExpiredTimer()))
        local real casterX
        local real casterY
        local integer infernal
        local real randomX 
        local real randomY
        local unit dummy1
        local unit dummy2
        local location point
        local integer loopCounter
        local real dummyFacing = 0
        
        if (data.serieCounter >= data.serieLimit) then
            call data.destroy()
        else
            
            //Here we make meteors fall andall that stuff
            set loopCounter = 0
            loop 
                exitwhen(loopCounter >= meteorsPerSerie(data.level))
            
                set casterX = GetUnitX(data.caster)
                set casterY = GetUnitY(data.caster)
                set point = GetRandomPointInDisk(casterX, casterY, minimumRange(data.level), maximumRange(data.level))
                set randomX = GetLocationX(point)
                set randomY = GetLocationY(point)
                set infernal = GetRandomInt(0, 100)
                
                if (infernal <= infernalChance(data.level)) then
                
                    set dummy1 = CreateUnit(GetOwningPlayer(data.caster), DUMMY_RAW, casterX, casterY, dummyFacing)
                    call UnitAddAbility(dummy1, INFERNAL)
                    call SetUnitAbilityLevel(dummy1, INFERNAL, data.level)
                    call IssuePointOrder(dummy1, INFERNALORDER, randomX, randomY)
                    call UnitApplyTimedLife(dummy1, 'BTLF', DUMMY_LIFE)
                
                    set dummy2 = CreateUnit(GetOwningPlayer(data.caster), DUMMY_RAW, casterX, casterY, dummyFacing)
                    call UnitAddAbility(dummy2, SPAWN)
                    call SetUnitAbilityLevel(dummy2, SPAWN, data.level)
                    call IssuePointOrder(dummy2, SPAWNORDER, randomX, randomY)
                    call UnitApplyTimedLife(dummy2, 'BTLF', DUMMY_LIFE)
                else 
                    set dummy1 = CreateUnit(GetOwningPlayer(data.caster), DUMMY_RAW, casterX, casterY, dummyFacing)
                    call UnitAddAbility(dummy1, NO_SPAWN)
                    call SetUnitAbilityLevel(dummy1, NO_SPAWN, data.level)
                    call IssuePointOrder(dummy1, NO_SPAWNORDER, randomX, randomY)
                    call UnitApplyTimedLife(dummy1, 'BTLF', DUMMY_LIFE)
                endif   
            
                call RemoveLocation(point)
                set point = null
                set dummy1 = null
                set dummy2 = null
                
                set loopCounter = loopCounter + 1
            endloop
            
            set data.serieCounter = data.serieCounter + 1
        endif
    endfunction
//==========================================================================
    private function Conditions takes nothing returns boolean
        local MyStruct data 
        
        if (GetSpellAbilityId() == AID) then
            set data = MyStruct.create(GetTriggerUnit())
            
            //put the struct in the Table, we just use the caster's handle adress as 
            //the key which tells us where in the Table the struct is stored
            set activeTable[data.caster] = data 

            
            //we attach the struct to the timer
            call SetTimerData(data.repeator, integer(data))
            call TimerStart(data.repeator, meteorCicle(data.level), true, function Effect)
            
            //  we add the casting unit to some sort of "pool"
            call GroupAddUnit(ApocalypseCasters, data.caster)
        endif
        
        return false
    endfunction
//===========================================================================
    private function Init takes nothing returns nothing 
        local trigger ApocalypseTrigger =CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(ApocalypseTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition(ApocalypseTrigger, Condition( function Conditions ) )

        set ApocalypseTrigger = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(ApocalypseTrigger, EVENT_PLAYER_UNIT_DEATH)
        call TriggerAddCondition(ApocalypseTrigger,  Condition(function onDeath))
    
        //Create your spell's private table.      
        set activeTable = HandleTable.create()
        
        set ApocalypseTrigger = null
    endfunction
endscope

chobibo 07-07-2008 11:08 AM

Quite nostalgic, I remembered the warcraft 3 RoC opening movie because of the infernal meteors. Good Job dude!

@off topic:You should try entering the Spell Contest with this spell, it looks great.

moyack 07-07-2008 11:58 AM

I'll review it again but please one thing: DO NOT DELETE THE THREAD if there's a bug or something to improve!!!!

Flame_Phoenix 07-07-2008 12:39 PM

Quote:

Quite nostalgic, I remembered the warcraft 3 RoC opening movie because of the infernal meteors. Good Job dude!

@off topic:You should try entering the Spell Contest with this spell, it looks great.
Thx !!
Mmmm I dunno I'll see what I can do =)

Quote:

I'll review it again but please one thing: DO NOT DELETE THE THREAD if there's a bug or something to improve!!!!
LOOOOOL
Ok, well, when people find bugs I just run back to the thread and ask help to fix them, I believe i shouldn't be wasting space with bugged spells here xD
But ok, i will not delete the thread lol.
Also, I've been thinking and I will allow people to customize the range of the spell with two new constant functions.
I will update this thread when I have time =)

Thx for post guys =)
Btw, Have any suggestions for the buff ? Right now it's just slow model xD

Tide-Arc Ephemera 07-07-2008 12:58 PM

Instead of deleting the thread how about editing the first post and changing the attached map...?

Also I believe the spell "Reign of Chaos" or something does effectively what this does... hails down infernals like there's no tomorrow.

chobibo 07-07-2008 01:26 PM

In the triggers and script section, it's stickied, Spell Making Session # 11

Flame_Phoenix 07-07-2008 01:34 PM

Quote:

Instead of deleting the thread how about editing the first post and changing the attached map...?

Also I believe the spell "Reign of Chaos" or something does effectively what this does... hails down infernals like there's no tomorrow.
I don't like to see my bugged threads here, awaiting for approval. It is just silly and is something I personally don't like, so I remove them.
Also, NO NO SPELL IN GAME does what this spell do. If you find a spell like equal to this spell in game, or in any other place, please say so, but as far as I know, this is 100% original from my brain.

Quote:

In the triggers and script section, it's stickied, Spell Making Session # 11
I've seen the other submissions ... I think I may have a chance if none of the great minds like Vexorian, Cohadar, or any mod joins the contest.
I know my chances of winning are small, but I'll try =)
I'm in ! xD

EDIT EDIT EDIT
Hey guys, now the spell was improved in order to be even more JESPISH !!! xD
You if you want, the AOE of the spell can depends on the level ! =)

PS: Can any mod please change the title of this thread to [SPELL11] Apocalypse, so I can enter the contest please ?

EDIT EDIT EDIT
Thx for changing the title =)

ShadowWolf 07-07-2008 06:06 PM

Pretty nice but, fix the hotkey please.

P is for Patrol. :P

moyack 07-07-2008 08:00 PM

M S H A P O, are the keys that you'd never use.

Flame_Phoenix 07-07-2008 08:40 PM

Done, fixed the hotkey =)
Now I believe everything is up to 100% ok =D

moyack 07-07-2008 09:51 PM

This night I'll do a code review, so sty tunned

Flame_Phoenix 07-07-2008 11:51 PM

Ok ... spell updated, now I removed the 10 headed dragon fiery beast that made my code completely not understandable - yes I removed the 1 line containing the DUMMY_FACING variable xD

Funny how 1 line can be amplified in such a critic.
Now I removed that line and improved the comment about the dummy unit's expiration time.
Anything else I need to do ?

EDIT EDIT EDIT

It is very late in my country. I have to go to sleep now. Hope tomorrow when I wake up I have good news about the spell =)
cya all

moyack 07-08-2008 01:35 AM

Checked and in general it looks fine in eyecandy and code.

One thing optional, but it can help you with future spells is to remove the 'Amov' ability to the dummy, with this, it doesn't matter the unit facing, the cast of any ability will be instant. In this spell this is not necessary, but I think this tip can be useful for you.

The spell is approved, but due that this spell is participating in the spell contest, I won't move it until the contest will require.

Flame_Phoenix 07-08-2008 10:23 AM

Quote:

One thing optional, but it can help you with future spells is to remove the 'Amov' ability to the dummy, with this, it doesn't matter the unit facing, the cast of any ability will be instant. In this spell this is not necessary, but I think this tip can be useful for you.
Ok but, how do I remove that ability ? I can't find it in the Object Unit Editor ?? In which field is it ?

Quote:

The spell is approved, but due that this spell is participating in the spell contest, I won't move it until the contest will require.
Does it mean that if I lose the contest, the spell won't be moved =S

chobibo 07-08-2008 10:45 AM

Congratz dude! your spell is approved.


All times are GMT. The time now is 01:45 AM.

Powered by vBulletin (Copyright ©2000 - 2019, Jelsoft Enterprises Ltd).
Hosted by www.OICcam.com
IT Support and Services provided by Executive IT Services