| 07-11-2008, 08:08 PM | #1 | ||
Hi guys, here is my second spell Stupid Penguin. After all help I got from my other spell I decided I should give more to this community, mainly because a community that gives more attention to it's users, deserves more attention from them in retribution (yes, I am comparing this to THW !!! ) Anyway I hope you like the spell =) This spell is from my map, Castle vs Castle Flame Edition and I hope you like it. This spell belongs to my project Castle vs Castle Flame Edition and I hope you all enjoy it. Description: The caster creates a Penguin that is Stupid and cannot attack. So what do we do with him ?? We blow him up !! =P While the caster channels the penguin grows, and the more it grows the more damage it will cause when it explodes. Requirements: - Jass NewGen Pack (uses vJASS) - TimerUtils - Table History:
JASS://=========================================================================== //A spell that creates a penguin which will grow every second, and then, when //it becomes to big, it BOOMMM !! explodes xD // //Requires TimerUtils and Table // //@author Flame_Phoenix // //@credits //- Anitarf, chobibo, Pyrogasm and Captain Griffen //- My first teacher of vJASS: Blue_Jeans //- All other people I forgot or ignored // //@version 2.0 //=========================================================================== scope StupidPenguin initializer Init //don't change this global globals private unit tmpCaster = null endglobals //=========================================================================== //=============================SETUP START=================================== //=========================================================================== globals private constant integer AID = 'A000' //The rawcode of the Stupid Penguin ability private constant string EXPLOSION_EFFECT = "Objects\\Spawnmodels\\NightElf\\NEDeathMedium\\NEDeath.mdl" //explosion effect when penguin dies private constant string DEATH_EFFECT = "Objects\\Spawnmodels\\Orc\\OrcSmallDeathExplode\\OrcSmallDeathExplode.mdl" //death's effect of penguin private constant string BLOOD_EFFECT = "Objects\\Spawnmodels\\Critters\\Albatross\\CritterBloodAlbatross.mdl" //effect shown when units take damage private constant string BIRTH_EFFECT = "Objects\\Spawnmodels\\Other\\ToonBoom\\ToonBoom.mdl" //effect shown when pinguin is created private constant integer TARGET_RED = 0 //the red RGB color for the text tag that will appear above the targets when they are hit by the explosion private constant integer TARGET_GREEN = 0 //the green RGB color for the text tag that will appear above the targets when they are hit by the explosion private constant integer TARGET_BLUE = 255 //the blue RGB color for the text tag that will appear above the targets when they are hit by the explosion private constant integer CASTER_RED = 255 //the red RGB color for the text tag that will appear above the caster, every cycle of channel time private constant integer CASTER_GREEN = 0 //the green RGB color for the text tag that will appear above the caster, every cycle of channel time private constant integer CASTER_BLUE = 0 //the blue RGB color for the text tag that will appear above the caster, every cycle of channel time endglobals private constant function penguinID takes integer level returns integer //this if statement is just to show you, how you can create different units //depending on level. I want to always have a penguin, so I really didn't need //this statement, having just " return 'npng' " would be Ok if (level > 0) then return 'npng' endif return 0 endfunction private constant function growTime takes integer level returns real return 1. + (level * 0) //time intervail between each time the unit grows (is a cycle) endfunction private constant function colorTime takes integer level returns real return 0.5 + (level * 0) //this is the amount of time a color will remain, before changing endfunction private function colorRed takes integer level returns integer //this function tells us the red gradient RGB color the penguin will have when it's time //to change color. Here i want a random red gradient, but you can use level like this: //return color * level, where "color" is the INTEGER number you want //NOTE: the red gradient goes from 0 to 255 only ! return GetRandomInt(0, 255) endfunction private function colorGreen takes integer level returns integer //this function tells us the green RGB color the penguin will have when it's time //to change color. Here i want a random green gradient, but you can use level like this: //return color * level, where "color" is the INTEGER number you want //NOTE: the green gradient goes from 0 to 255 only ! return GetRandomInt(0, 255) endfunction private function colorBlue takes integer level returns integer //this function tells us the blue RGB color the penguin will have when it's time //to change color. Here i want a random blue gradient, but you can use level like this: //return color. * level, where "color" is the INTEGER number you want //NOTE: the blue gradient goes from 0 to 255 only ! return GetRandomInt(0, 255) endfunction private function colorAlpha takes integer level returns integer //this function tells us the Alpha the penguin will have when it's time //to change color. Alpha value is responsable for the transparency of the unit. //Here i want a constant alpha, so the penguin is always visible //at it's best, but you can use level like this: //return alpha * level, where "alpha" is the INTEGER number you want return 255 endfunction private constant function growth takes integer level returns real return 0.1 * level //How much the unit will grow. It grows 10% * level in this case endfunction private constant function radius takes integer level returns integer return 200 + (50 * (level - 1)) //the area of damage endfunction private constant function damage takes integer level returns real return 10. * level //Damage increase per cycle endfunction private function casterText takes integer damageAdd returns string //the text that will appear above the caster every cycle return I2S(damageAdd) + " damage!" endfunction private function unitText takes integer unitDamage returns string //the text that will appear above the unit when the penguin explodes return "-" + I2S(unitDamage) + " !" endfunction private function targets takes nothing returns boolean //these are the targets the explosion will affect ! return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(tmpCaster)) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL) == false) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false) and (GetWidgetLife(GetFilterUnit()) > 0.405) endfunction //=========================================================================== //=============================SETUP END===================================== //=========================================================================== globals private group StupidPenguinCasters //to store the casters private group StupidPenguins //to store the penguins private HandleTable activeTable //your private Table's global variable private group g //the group that will store the units to suffer the effect of the explosion private boolexpr b //the units that will be selected into group g endglobals private struct MyStruct unit caster integer level unit penguin real currentScale timer growPeriod timer colorTicker real grow real damage boolean hasCasterStoped //this tells us if the spell is ending or not static method create takes unit caster, real spellX, real spellY returns MyStruct local MyStruct data = MyStruct.allocate() //set variables about the caster set data.caster = caster set data.level = GetUnitAbilityLevel(data.caster, AID) //while false, the caster is channeling, //when true the caster stoped and we stop the spell too set data.hasCasterStoped = false //set variables about the Stupid Penguin set data.penguin = CreateUnit(GetOwningPlayer(data.caster), penguinID(data.level), spellX, spellY, 0.) set data.currentScale = 1 set data.growPeriod = NewTimer() set data.colorTicker = NewTimer() set data.grow = growth(data.level) set data.damage = damage(data.level) //put the struct in the Table, we just use the caster's and the //penguin's handle adress as the key which tells us where in the //Table the struct is stored set activeTable[data.caster] = data set activeTable[data.penguin] = data //we add the casting unit and the penguin to some sort of "pool" //with all other casters and penguins that are using this spell call GroupAddUnit(StupidPenguinCasters, data.caster) call GroupAddUnit(StupidPenguins, data.penguin) return data endmethod method onDestroy takes nothing returns nothing //since the spell is not active anymore, we clean the Table call activeTable.flush(.caster) call activeTable.flush(.penguin) //the units are not anymore in the active units group. call GroupRemoveUnit(StupidPenguinCasters, .caster) call GroupRemoveUnit(StupidPenguins, .penguin) //releasing the timer for CSSafety to use it one day later =D call ReleaseTimer(.growPeriod) call ReleaseTimer(.colorTicker) endmethod endstruct //=========================================================================== private function explosion takes integer structure returns nothing //variables for the explosion! local MyStruct data = structure local unit f local texttag text //blow the penguin to hell !! xD call DestroyEffect(AddSpecialEffect(EXPLOSION_EFFECT, GetUnitX(data.penguin), GetUnitY(data.penguin))) call DestroyEffect(AddSpecialEffect(DEATH_EFFECT, GetUnitX(data.penguin), GetUnitY(data.penguin))) call ShowUnit(data.penguin, false)//hide the penguin //if the penguin is not dead, we kill him MUHAHHAHAHHA if (GetWidgetLife(data.penguin) > 0.405) then call KillUnit(data.penguin) endif set tmpCaster = data.caster call GroupEnumUnitsInRange(g, GetUnitX(data.penguin), GetUnitY(data.penguin), radius(data.level), b) loop set f = FirstOfGroup(g) exitwhen (f == null) call GroupRemoveUnit(g, f) // the effect when the unit is damaged and the damage call DestroyEffect(AddSpecialEffect(BLOOD_EFFECT, GetUnitX(f), GetUnitY(f))) call UnitDamageTarget(data.penguin, f, data.damage, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNIVERSAL, null) //now we show some text set text = CreateTextTag() call SetTextTagText(text, unitText(R2I(data.damage)), .023 ) call SetTextTagPosUnit( text, f, 0 ) call SetTextTagColor( text, TARGET_RED, TARGET_GREEN, TARGET_BLUE, 255 ) call SetTextTagPermanent(text, false) call SetTextTagVelocity( text, 0, .0277 ) call SetTextTagLifespan(text, 2.0) endloop set text = null endfunction //=========================================================================== private function onStop 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, StupidPenguinCasters)) then //recover the data from the caster set data = activeTable[u] set data.hasCasterStoped = true //here we make things blow up ! An explosion easy to customize call explosion(data) //now, time to clean the mess once again call data.destroy() endif set u = null return false endfunction //=========================================================================== private function onDeath takes nothing returns boolean local MyStruct data local unit u = GetTriggerUnit() //we make sure that the unit that dies is the penguin if(IsUnitInGroup(u, StupidPenguins)) then //recover that data (the struct) from the penguin set data = activeTable[u] //we make a check: if the caster already stoped, the penguin has just //been killed in the "explosion" function and we don't need to make him //stop, in the case the variable "hasCasterStoped" is equal to true and //we just jump this if, thus doing nothing. //However, if the penguin died first, the "hasCasterStoped" is equal //to false, and so we order the caster to stop, thus ending the spell. if not(data.hasCasterStoped) then call IssueImmediateOrder(data.caster, "stop" ) endif endif set u = null return false endfunction //=========================================================================== private function ChangeColor takes nothing returns nothing local MyStruct data = MyStruct(GetTimerData(GetExpiredTimer())) call SetUnitVertexColor(data.penguin, colorRed(data.level), colorGreen(data.level), colorBlue(data.level), colorAlpha(data.level)) endfunction //=========================================================================== private function Size takes nothing returns nothing //code to make the penguin grow bigger and bigger ! //we also set the damage variables and all that stuff here local MyStruct data = MyStruct(GetTimerData(GetExpiredTimer())) local texttag text set data.currentScale = data.currentScale + data.grow set data.damage = data.damage + damage(data.level) call SetUnitScale(data.penguin, data.currentScale, data.currentScale, data.currentScale) set text = CreateTextTag() call SetTextTagText(text, casterText(R2I(data.damage)), .023 ) call SetTextTagPosUnit( text, data.caster, 0 ) call SetTextTagColor( text, CASTER_RED, CASTER_GREEN, CASTER_BLUE, 255 ) call SetTextTagPermanent(text, false) call SetTextTagVelocity( text, 0, .0277 ) call SetTextTagLifespan(text, 2.0) set text = null endfunction //=========================================================================== private function Conditions takes nothing returns boolean local MyStruct data local location spellLoc if (GetSpellAbilityId() == AID) then //setting variables for the struct set spellLoc = GetSpellTargetLoc() set data = MyStruct.create(GetTriggerUnit(), GetLocationX(spellLoc), GetLocationY(spellLoc)) //this is just an eye candy, when the Stupid Penguin borns =) //If you could find an animation with an egg, that could be cute xD call DestroyEffect(AddSpecialEffect(BIRTH_EFFECT, GetUnitX(data.penguin), GetUnitY(data.penguin))) //we attach the struct to the timer and we start it call SetTimerData(data.growPeriod, integer(data)) call TimerStart(data.growPeriod, growTime(data.level), true, function Size) call SetTimerData(data.colorTicker, integer(data)) call TimerStart(data.colorTicker, colorTime(data.level), true, function ChangeColor) //cleaning up the mess call RemoveLocation(spellLoc) endif set spellLoc = null // to prvent a leak return false endfunction //=========================================================================== private function Init takes nothing returns nothing local trigger StupidPenguinTrigger =CreateTrigger() call TriggerRegisterAnyUnitEventBJ(StupidPenguinTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition(StupidPenguinTrigger, Condition( function Conditions ) ) set StupidPenguinTrigger = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(StupidPenguinTrigger, EVENT_PLAYER_UNIT_DEATH) call TriggerAddCondition(StupidPenguinTrigger, Condition(function onDeath)) set StupidPenguinTrigger = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(StupidPenguinTrigger, EVENT_PLAYER_UNIT_SPELL_ENDCAST) call TriggerAddCondition(StupidPenguinTrigger, Condition(function onStop)) //setting our globals set g = CreateGroup() set b = Condition(function targets) set activeTable = HandleTable.create() //Create our spell's private Table for casters and penguins set StupidPenguinCasters = CreateGroup() set StupidPenguins = CreateGroup() //we preload all our effects, so they won't lag the first time we use them !=P call Preload(EXPLOSION_EFFECT) call Preload(DEATH_EFFECT) call Preload(BLOOD_EFFECT) call Preload(BIRTH_EFFECT) set StupidPenguinTrigger = null endfunction endscope Quote:
Oh, and by the way, you can also explode mini-abominations Squally425. Hope you all have fun =P |
| 07-11-2008, 10:26 PM | #2 |
You forgot to change this bit private constant integer AID = 'A000' //The rawcode of the Apocalypse ability to Stupid Penguin xD. Oh just in my point of view. It would be nice to disable the texttag or have an option to show the amount of damage channeled. The scaling can be smoother... buts that your choice. Its pretty funny spell though xD -Av3n EDIT: Relating to this line... call DestroyEffect(AddSpecialEffect(BIRTH_EFFECT, GetUnitX(data.penguin), GetUnitY(data.penguin))) in the Condition function it won't. 1. You are directly passing it into the function 2. You are not using a variable to point to it 3. Reading this might explain why: http://wc3campaigns.net/showthread.php?t=81872 |
| 07-11-2008, 10:44 PM | #3 | |||
Quote:
Quote:
Quote:
+rep You think this can be approved ? |
| 07-12-2008, 12:05 AM | #4 |
Wait, what are you going on about there Av3n? Maybe you forgot a word in your post because it makes no sense to me... |
| 07-12-2008, 01:24 AM | #5 |
Which bit? it most likely the Effects bit I reckon, that was from what i know so.... -Av3n |
| 07-12-2008, 12:52 PM | #6 |
Yes to understand the part about the effect you must read the code. However, because the code was already improved, it won't make any sense now =P Anyway, when will this be reviewed by a mod ? EDIT EDIT EDIT Heyy =) I decided to follow Av3rn advice, now the current damage being channeled will appear above the caster every cicle. The text tag is also easy to configure, so it can be as you like =) I also made few changes in the names of the function and globals. Hope you all like the improvements =D |
| 07-15-2008, 11:02 PM | #7 |
It has already passed a few days, when will this be moderated ?? =S |
| 07-20-2008, 10:50 PM | #8 |
The word is "cycle", not "cicle"; however, that's not too important. I'll look at this soon, I suppose. |
| 07-23-2008, 02:41 PM | #9 |
Lol.... sorry for typo,I will fix that soon also. Again, tomorrow new version =) Hope you like the spell, it was specially designed to be fun ! =D EDIT EDIT EDIT Ok guys I updated the penguinID function and now it is more efficient than ever. I am sorry but I forgot to change "cicle" to "cycle"... I will fix that tomorrow xD Anyway, here is the new version of the map. Please note that I didn't update the code in the 1st thread because I am in cheap cyber shop that doesn't open WE maps, and so I can't access to the code. Anyway, please enjoy the spell =) Comments please =D NOTE:Please note that the map in the 1st post is NOT updated as well. The map on THIS post is the most recent version of the spell, and please evaluate it. EDIT EDIT EDIT Hey guys, the code was now updated as well as the map in the first post. Please make comments and approve the spell, this is most likely it's last version =D EDIT EDIT EDIT Ok, guys, here is a new version of the spell, with the spelling mistakes corrected, as promised. Please post comments and enjoy ! =P |
| 07-31-2008, 07:31 PM | #10 |
You should replace CSSafety and CSData with timer utils since that's the new standard. Timer utils only works with timers, not groups, the reason for that is because in vJass we don't really use dynamic groups anymore and for static groups NewGroup is useless, you can just replace all your NewGroup calls with CreateGroup and then replace CSSafety with timer utils, this will make your spell more up to date. You could move a lot of function calls from the Conditions function to the MyStruct create method for organisational purposes. Since you flush the table data in the onDestroy method, it would be more fitting to set it in the create method. Similarly, since you remove the units from the groups in the onDestroy method, you should add them in the create method. Same for creating the timer. I understand why it's a pain to start the timer in the create method, so that can be left in the Conditions function, but the rest of the stuff there belongs in the create method more. Perhaps a cool calibration option would be to allow the vertex colouring of the penguin to change over time as size does, but that would on the other hand mean you'd need a ton of calibration constants... Other than that the spell seems ok. |
| 07-31-2008, 07:57 PM | #11 | |
Quote:
Arrghhh I will see what I can do with TimerUtils... So I will have to use "CreateGroup()" and "DestroyGroup()" once again right ? That has to wait, I just downlaoded the new patch and now I can not start my JNGP ! help! Anyway, When will my spell get approved ? EDIT EDIT EDIT Problem with JNGP solved. Now I will soon make some changes but I do not guarantee I will use TimerUtils .. I still need some answers because recycling groups looks very good and I am not sure of stop using it without any further advices. |
| 07-31-2008, 09:28 PM | #12 | ||
Quote:
Quote:
|
| 07-31-2008, 09:49 PM | #13 | ||
Quote:
Besides, Captain_Grifen said that using natives in map init is evil because it can cause the map to crash ... =S EDIT EDIT EDIT Quote:
EDIT EDIT EDIT Hey guys, the code was improved. I still don't use TimerUtils, I need to read more about that thing and I really don't feel like importing another system into my map, however, I did most changes in the code that Anitarf suggested (expect for the timer, that Size function is really a pain and placing it before the structure would mess up everything). Is it good now ? |
| 07-31-2008, 10:08 PM | #14 | ||||
Quote:
Quote:
Quote:
Quote:
|
| 08-01-2008, 08:50 AM | #15 | ||
Quote:
About the size with each it is created, yes you can change that, in the object editor ... however in the code I use 1.0 to start for relative purposes. Quote:
Anyway, can this be approved ? |
