| 01-01-2007, 12:09 PM | #1 |
Creep Respawn System v2.6! Updated to work with Warcraft III 1.24 and above! JASS:// CREEP RESPAWN SYSTEM v2.6 // Made by Themerion // [url]http://www.wc3campaigns.net/showthread.php?t=90302[/url] // // The creep respawn system automates the creation of respawning creep groups. // (when there are no creeps left in the group, the group will respawn after X seconds) // // Needs AutoIndex (by grim001) // [url]http://www.wc3c.net/showthread.php?t=105643[/url] // ----------------------------------------------------------------------------------------- // // - Very simple to use. // - Respawning creeps will remember their original position, facing and acquisition range. // - Supports randomly spawning a group from a list of pre-defined setups. // - Has the possibility to suspend respawn if certain units are too close to the spawn point. // - The respawn will detect unit death, changed ownership, RemoveUnit and ReplaceUnit. // // ----------------------------------------------------------------------------------------- //##### BASIC USAGE ##### //# //# ----------------------------------------------------------------------------------------- //# function CRS_CreateGroup takes rect r returns crsGroupSimple //# ----------------------------------------------------------------------------------------- //# * Setups all units in the region/rect to respawn as a group. //# * If the units in the group have campaign acquisition range, //# they will remember it on respawn. //###### //##### SPAWN DIFFERENT UNITS ##### //# //# ----------------------------------------------------------------------------------------- //# function CRS_CreateSetup takes rect r returns crsSetup //# ----------------------------------------------------------------------------------------- //# * Creates a setup of the units in the rect/region. //# * Recently created Setups are stored in a list. //# * Calling CRS_ClearSetups() will empty the list. //# //# ----------------------------------------------------------------------------------------- //# function CRS_CreateListGroup takes rect r, boolean random, boolean campaginRange returns crsListGroup //# function CRS_CreateListGroupXY takes real x, real y, boolean random, boolean campaginRange returns crsListGroup //# ----------------------------------------------------------------------------------------- //# * Creates a list group, which automatically is assigned the last created setup list. //# * The group spawns instantly. //# * random determines whether to spawn a random setup from the list, or spawn them in order. //# * If campaignRange is true the units will spawn with campaign acquisition range. //# //# //###### //##### IMPORTANT UNITS ##### //# //# ----------------------------------------------------------------------------------------- //# function CRS_AddImportantUnit takes unit u returns nothing //# function CRS_RemoveImportantUnit takes unit u returns nothing //# ----------------------------------------------------------------------------------------- //# * Creep groups' respawn will be suspended if an important unit is too close. //##### //##### CUSTOM RESPAWN TIME ##### //# //# ----------------------------------------------------------------------------------------- //# integer crsGroup.respawnTime //# ----------------------------------------------------------------------------------------- //# * Sets a group's respawn time (defaults to CRS_DEFAULT_RESPAWN_TIME). //##### //##### MISC ##### //# //# ----------------------------------------------------------------------------------------- //# method crsGroup.spawn() //# ----------------------------------------------------------------------------------------- //# //# * Instantly spawns the group. Calling it when the group is not dead //# will cause the group to be larger until killed off. //# //# ----------------------------------------------------------------------------------------- //# group crsGroup.units //# ----------------------------------------------------------------------------------------- //# //# * Returns all the units still in the group. //# * DO NOT alter this group. //# //# ----------------------------------------------------------------------------------------- //# integer crsGroup.count //# ----------------------------------------------------------------------------------------- //# //# * Is basically CountUnitsInGroup(crsGroup.unit), but faster. //# * DO NOT alter this number. //###### library CreepRespawn initializer Init needs AutoIndex globals //================================================================= // SETUP //================================================================= // Default respawn time for creep groups (seconds). private constant integer CRS_DEFAULT_RESPAWN_TIME=30 // If you use important units. // How far away must all important units be for the group to respawn? // ( If you press 'G' in the terrain editor; 512 is the width/height of a yellow square. ) private constant real CRS_IMPORTANT_DISTANCE=600 // Campaign acquire range for creeps. constant integer CRS_CAMPAIGN_ACQUIRE_RANGE=200 // Well, if you for some reason would not like to respawn Neutral Hostile, // change this into the player you want to respawn. constant integer CRS_RESPAWNING_PLAYER=PLAYER_NEUTRAL_AGGRESSIVE // PS. The setup-funtions will only detect the player chosen here. // Neutral Passive = PLAYER_NEUTRAL_PASSIVE // Neutral Hostile = PLAYER_NEUTRAL_AGRESSIVE // Neutral Extra = bj_PLAYER_NEUTARL_EXTRA // Neutral Victim = bj_PLAYER_NEUTARL_VICTIM //================================================================= // END OF SETUP //================================================================= private trigger trg private boolexpr setupFilter private crsGroup first=0 private timer respawn_timer private group important_group endglobals // ====================== For the unit attaching ======================= globals crsGroup array CRS_groupOfUnit endglobals //! textmacro CRS_AttachGroupToUnit takes GROUP, UNIT set CRS_groupOfUnit[GetUnitId($UNIT$)]=$GROUP$ //! endtextmacro //! textmacro CRS_GetGroupOfUnit takes GROUP, UNIT set $GROUP$=CRS_groupOfUnit[GetUnitId($UNIT$)] //! endtextmacro //! textmacro CRS_CleanData takes UNIT set CRS_groupOfUnit[GetUnitId($UNIT$)]=0 //! endtextmacro // =================================================================== //! textmacro crs_DestroyGroup call ForGroup(.units,function EnumClean) call DestroyGroup(.units) call CRS_RemoveFromSpawnList(this) //! endtextmacro //! textmacro CRS_InitGroup takes A set $A$.respawnTime=CRS_DEFAULT_RESPAWN_TIME set $A$.time=-1 set $A$.units=CreateGroup() //! endtextmacro globals private real rect_x private real rect_y private boolean temp_b endglobals private function CheckForImportantUnitsEnum takes nothing returns nothing local real x=GetUnitX(GetEnumUnit())-rect_x local real y=GetUnitY(GetEnumUnit())-rect_y if GetWidgetLife(GetEnumUnit())>.405 and x*x+y*y<CRS_IMPORTANT_DISTANCE*CRS_IMPORTANT_DISTANCE then set temp_b=false return endif endfunction private function CheckForImportantUnits takes real x, real y returns boolean set rect_x=x set rect_y=y set temp_b=true call ForGroup(important_group,function CheckForImportantUnitsEnum) return temp_b endfunction private function RespawnTix takes nothing returns nothing local crsGroup cd=first local crsGroup prev=0 loop exitwhen cd==0 if cd.time<=0 then // Respawn... if CheckForImportantUnits(cd.x,cd.y) then if prev==0 then set first=cd.next else set prev.next=cd.next endif call cd.spawn() endif else // Count down... set cd.time=cd.time-1 set prev=cd endif set cd=cd.next endloop endfunction private function EnumClean takes nothing returns nothing //! runtextmacro CRS_CleanData("GetEnumUnit()") endfunction function CRS_RemoveFromSpawnList takes crsGroup g returns nothing local crsGroup prev=0 local crsGroup cg=first loop exitwhen cg==0 if cg==g then // Remove g if prev==0 then set first=g.next else set prev.next=g.next endif exitwhen true endif set prev=cg set cg=cg.next endloop endfunction // ==================================================================================== struct crsUnitData real x real y real face integer uid crsUnitData next=0 static method create takes integer unitid, real x, real y, real face returns crsUnitData local crsUnitData c=crsUnitData.allocate() set c.uid=unitid set c.x=x set c.y=y set c.face=face return c endmethod endstruct // ===================================================================================== // struct crsSetup globals private crsGroup tempGroup private crsUnitData setupUnitData private crsUnitData setupTempData private real tempX private real tempY private group emptyGroup endglobals private function SetupFilter takes nothing returns boolean local unit u = GetFilterUnit() if GetOwningPlayer(u)==Player(CRS_RESPAWNING_PLAYER) and GetWidgetLife(u)>.405 then // Create a new data instance, and put it first in the list. set setupUnitData=crsUnitData.create(GetUnitTypeId(u),GetUnitX(u)-tempX,GetUnitY(u)-tempY,GetUnitFacing(u)) set setupUnitData.next=setupTempData set setupTempData=setupUnitData // If we're initializing a single group, make it respawnable. if tempGroup!=0 then //! runtextmacro CRS_AttachGroupToUnit("tempGroup","u") call GroupAddUnit(tempGroup.units,u) set tempGroup.count=tempGroup.count+1 set u=null return true endif endif set u=null return false endfunction struct crsSetup // How many groups are using this setup? integer refcount=0 // If no groups use the setup, should it be destroyed? boolean destroyOnZero=true crsSetup next=0 crsUnitData unitData=0 static method create takes rect r, crsGroup cg returns crsSetup local crsSetup cs=crsSetup.allocate() // Loops through all the units in the rect, // adding them to the setup. set tempX=GetRectCenterX(r) set tempY=GetRectCenterY(r) set tempGroup = cg set setupTempData = 0 // If we're creating a setup for a single group. // Do the group a favor and fill the unit group up! if cg!=0 then call GroupEnumUnitsInRect(cg.units,r,setupFilter) else call GroupEnumUnitsInRect(emptyGroup,r,setupFilter) endif set cs.unitData=setupUnitData return cs endmethod method release takes nothing returns nothing if .destroyOnZero and .refcount<=1 then call .destroy() else set .refcount=.refcount-1 endif endmethod method onDestroy takes nothing returns nothing local crsUnitData cud=.unitData local crsUnitData temp loop exitwhen cud==0 set temp=cud.next call cud.destroy() set cud=temp endloop endmethod endstruct // ===================================================================================== interface crsGroup real x real y integer time integer respawnTime integer count=0 group units boolean longAcquireRange=true crsSetup setup=0 crsGroup next=0 method spawn takes nothing returns nothing endinterface private function crsGroup_Spawn takes crsGroup cg, crsSetup cs returns nothing local crsUnitData ud=cs.unitData local unit u // If the group is in the respawn list, // that is, the .spawn()-call was manually triggered by the user // remove it from the list. if cg.time>0 then call CRS_RemoveFromSpawnList(cg) endif loop exitwhen ud==0 set u=CreateUnit(Player(CRS_RESPAWNING_PLAYER),ud.uid,ud.x+cg.x,ud.y+cg.y,ud.face) //! runtextmacro CRS_AttachGroupToUnit("cg","u") call GroupAddUnit(cg.units,u) set cg.count=cg.count+1 if cg.longAcquireRange==false then call SetUnitAcquireRange(u,CRS_CAMPAIGN_ACQUIRE_RANGE) endif set ud=ud.next endloop set u=null endfunction // ===================================================================================== struct crsListGroup extends crsGroup crsSetup listPointer integer length=0 static method create takes real x, real y, crsSetup setup, integer listPointer returns crsListGroup local crsListGroup cg=crsListGroup.allocate() local crsSetup cs=setup set cg.x=x set cg.y=y set cg.setup=setup set cg.listPointer=listPointer loop exitwhen cs==0 set cs.refcount=cs.refcount+1 set cg.length=cg.length+1 set cs=cs.next endloop //! runtextmacro CRS_InitGroup("cg") return cg endmethod method spawn takes nothing returns nothing local integer i=1 local crsSetup pickedSetup=.setup if .listPointer==0 then // random-spawn set i=GetRandomInt(1,.length) loop exitwhen i==1 set pickedSetup=pickedSetup.next set i=i-1 endloop else // linear spawn set .listPointer=.listPointer.next if .listPointer==0 then set .listPointer=.setup endif set pickedSetup=.listPointer endif call crsGroup_Spawn(this,pickedSetup) endmethod method onDestroy takes nothing returns nothing local crsSetup cs=.setup local crsSetup temp //! runtextmacro crs_DestroyGroup() loop exitwhen cs==0 set temp=cs.next call cs.release() set cs=temp endloop endmethod endstruct // ===================================================================================== struct crsGroupSimple extends crsGroup static method create takes real x, real y, crsSetup setup returns crsGroupSimple local crsGroupSimple cd=crsGroupSimple.allocate() set cd.x=x set cd.y=y set cd.setup=setup set setup.refcount=setup.refcount+1 //! runtextmacro CRS_InitGroup("cd") return cd endmethod static method createStub takes nothing returns crsGroupSimple local crsGroupSimple cd=crsGroupSimple.allocate() //! runtextmacro CRS_InitGroup("cd") return cd endmethod method spawn takes nothing returns nothing call crsGroup_Spawn(this,this.setup) endmethod method onDestroy takes nothing returns nothing //! runtextmacro crs_DestroyGroup() call .setup.release() endmethod endstruct // ===================================================================================== // On leave may also called by AutoIndex, detecting RemoveUnits. public function OnLeave takes unit u returns nothing local crsGroup d //! runtextmacro CRS_GetGroupOfUnit("d","u") if d!=0 then //! runtextmacro CRS_CleanData("u") call GroupRemoveUnit(d.units,u) set d.count=d.count-1 if d.count<=0 then set d.time=d.respawnTime // Add to respawn list set d.next=first set first=d endif endif endfunction private function Action takes nothing returns boolean // This isn't really needed for AutoIndex. // I decided to leave it, in case someone wants to port CRS to a less awesome attachment system. if GetChangingUnit()==null or GetChangingUnitPrevOwner()==Player(CRS_RESPAWNING_PLAYER) then call OnLeave(GetTriggerUnit()) endif return false endfunction private function Init takes nothing returns nothing local integer i=0 set important_group=CreateGroup() set trg=CreateTrigger() set setupFilter=Condition(function SetupFilter) set emptyGroup=CreateGroup() // The trigger which checks if units leaves a creep group. // CHANGE_OWNER is fired for the new owner, so all players must be considered in the event. call TriggerAddCondition(trg,Condition(function Action)) call TriggerRegisterPlayerUnitEvent(trg, Player(CRS_RESPAWNING_PLAYER), EVENT_PLAYER_UNIT_DEATH, null) call TriggerRegisterAnyUnitEventBJ(trg, EVENT_PLAYER_UNIT_CHANGE_OWNER) // Start the respawn-timer. // This timer keep track of all dead groups' respawn time. set respawn_timer=CreateTimer() call TimerStart(respawn_timer,1,true,function RespawnTix) // For detecting Remove / ReplaceUnit // Needs AutoIndex call OnUnitDeindexed(OnLeave) endfunction // ============================================================================================ function CRS_AddImportantUnit takes unit u returns nothing call GroupAddUnit(important_group,u) endfunction function CRS_RemoveImportantUnit takes unit u returns nothing call GroupRemoveUnit(important_group,u) endfunction // ============================================================================================ globals crsSetup CRS_lastCreatedSetup=0 endglobals // --------------------------------------------------------------------------------- function CRS_CreateGroup takes rect r returns crsGroupSimple local crsGroupSimple gs=crsGroupSimple.createStub() local crsSetup cs = crsSetup.create(r,gs) // Check acquisition-range local unit u = FirstOfGroup(gs.units) if u!=null and GetUnitAcquireRange(u)<=CRS_CAMPAIGN_ACQUIRE_RANGE then set gs.longAcquireRange=false endif set gs.x=GetRectCenterX(r) set gs.y=GetRectCenterY(r) set gs.setup=cs set u=null return gs endfunction // --------------------------------------------------------------------------------- function CRS_CreateSetup takes rect r returns crsSetup local crsSetup cset=crsSetup.create(r,0) // Link with previously created setups. set cset.next=CRS_lastCreatedSetup set CRS_lastCreatedSetup=cset return cset endfunction // --------------------------------------------------------------------------------- function CRS_ClearSetups takes nothing returns nothing set CRS_lastCreatedSetup=0 endfunction // --------------------------------------------------------------------------------- function CRS_CreateListGroupXY takes real x, real y, boolean random, boolean campaignRange returns crsListGroup local integer i=1 local crsListGroup cr if random then set i=0 endif set cr=crsListGroup.create(x,y,CRS_lastCreatedSetup,i) set cr.longAcquireRange=not(campaignRange) call cr.spawn() return cr endfunction // --------------------------------------------------------------------------------- function CRS_CreateListGroup takes rect r, boolean random, boolean campaignRange returns crsListGroup return CRS_CreateListGroupXY(GetRectCenterX(r),GetRectCenterY(r),random,campaignRange) endfunction endlibrary Purpose The Creep Respawn system is intended to greatly simplify the process of automatically respawning creep groups for you. A creep group is a group of creeps (1 or more) which will respawn after every unit in the group dies. Requirements:
Features:
|
| 01-06-2007, 09:48 AM | #2 |
This system was made 1000 times on GUI and 10000 times was optimised on JASS. I seriously doubt its usefulness. |
| 01-06-2007, 11:02 AM | #3 |
I'm not sure if I get your point. When you say "this system", do you refer to exactly this system or this kind of systems? If you mean that there already are a lot of creep respawn systems, then my answer is simple: There are none at wc3campaigns -> Resources -> Systems. If you mean that my system isn't useful, then that would be a subjective opinion. I have myself implemented this in a map of mine, and the creation of many respawning creeps have never been easier. Have you actually looked at the code? |
| 01-06-2007, 11:16 AM | #4 | |
Hell, it's not that hard really... Quote:
|
| 01-18-2007, 01:54 PM | #6 |
Seems pretty useful (not just your standard fare anyway). You will definitely need to add some usage and installation instructions though. |
| 01-23-2007, 10:40 PM | #7 | |
Quote:
Okay, I've made a try for documentation and instructions in 1.2. Response (negative or positive) would be appreciated =) |
| 01-24-2007, 03:43 AM | #8 |
one question unless I missed it somewhere on the first post does this keep creeps from spawning into unmovable places like cliffs and in trees? |
| 01-24-2007, 02:02 PM | #9 |
It spawns units in an equivalent way of a normal trigger. If you attempt to spawn them onto, for instance, a tree; then they will appear close to the tree instead of on it. |
| 01-28-2007, 01:17 PM | #10 |
As I've realised that not everybody is a scripting guru, I've decided to create and maintain two versions simultaneously. One for people using JASSHelper, and one for mortals (called CreepRespawnSystem1.3i). Hopefully this will make the system more attractive for people who generally doesn't script. EDIT Yeah, having 2 versions of a map is dumb. I've merged them into 1.4. |
| 02-01-2007, 02:41 PM | #11 |
Ok, usage instructions seem good. Don't see any code problems. Approved. |
| 02-02-2007, 06:42 AM | #12 | |
Quote:
|
| 02-02-2007, 10:59 AM | #13 |
I think there has been some kind of misunderstanding... This system respawns unit in a certain location. Which you decide. It doesn't respawn them randomly across the map. (Or did you mean something else?) |
| 01-05-2008, 05:07 PM | #14 |
I like it and think I'm gonna use it for a new rpg project. Here a some small suggestions you may think about to add for a bit more flexibility: - 2 or maybe 3 different unit types per group (so that you can create mixed groups). TempType1, TempType2 etc. Should be pretty easy to add and if you want only one unit type you just don't set TempType2 or TempType 3. - If it's not already implented: the possibility that each unit of the group spawns at a random point within the specified region (to avoid all units being concentrated at one point) to make it look and feel more realistic. Just suggestions, anyway good sys. |
| 01-06-2008, 08:14 PM | #15 |
Thank you for the suggestions! Sure, I'll implement the things you asked for. |
