| 06-22-2011, 04:04 PM | #1 |
I'm working on a map in which there are 6 players, 2 gold mines each. Each player has a pair of gold mines right next to their spawn point. I want to pick those two gold mines and, if the player's race is undead or night elf, change them to the appropriate type of gold mine (haunted or entangled). I also want to have some kind of list or array of variables that contains all those gold mines so that I can add gold to them, possibly even being selective about which ones have gold added to them, and replace any that get destroyed at specific times. (I've put a region under each gold mine to help with the replacing part) This is in the middle of a "pick every player in unit group" loop, using GUI because I don't know JASS at all. I really want to somehow tie each pair of goldmines to its respective player. I'm just not sure how to approach the problem. |
| 06-22-2011, 04:58 PM | #2 |
If you take a look at the Custom Race System, you can see in the example setup how night elf and undead gold mines are handled when the game starts (since that part is copied from Blizzard's original melee initialization code). The original melee initialization only does this to the nearest mine and the Custom Race System also allows only the nearest gold mine to be manipulated, but you can easily find the other gold mine on your own by picking all units of the gold mine type within a certain range of the nearest gold mine. If you were to use the Custom Race System, a modified initialization that looks for the second gold mine would look somewhat like this: JASS:library GoldMineSetup globals private constant integer MAX_MINES = 2 private constant real MINE_SEARCH_RADIUS = 1024.0 // This 2D vJass array holds the gold mines for each player so you can manipulate them whenever you want. public unit array goldMines[12][MAX_MINES] private unit firstMine private integer playerId private integer minesFound private group g = CreateGroup() endglobals private function Enum takes nothing returns boolean if minesFound<MAX_MINES and GetUnitTypeId(GetFilterUnit())==GetUnitTypeId(firstMine) and GetFilterUnit()!=firstMine then set goldMines[playerId][minesFound]=GetFilterUnit() set minesFound=minesFound+1 endif return false endfunction function GoldMineSetup takes player p, unit nearestMine returns nothing set firstMine=nearestMine set playerId=GetPlayerId(p) set minesFound=1 set goldMines[playerId][0]=firstMine call GroupEnumUnitsInRange(g, x,y,radius, Condition(function Enum)) endfunction endlibrary //==================================================================== // HUMAN SETUP //==================================================================== library HumanSetup initializer Init requires CustomRaceSystem, GoldMineSetup private function SetupGoldMine takes player play, group workers, unit goldmine, unit townhall, unit randhero returns nothing call GoldMineSetup(play, goldmine) call DestroyGroup(workers) endfunction private function Init takes nothing returns nothing local CustomRace c = CustomRace.create("Human",RACE_HUMAN,1.0) call c.setTownHall('htow') // Town Hall call c.addWorkerType('hpea',c.NEAR_MINE,5) // Peasant call c.addHeroType('Hpal') // Paladin call c.addHeroType('Hamg') // Archmage call c.addHeroType('Hmkg') // Mountain King call c.addHeroType('Hblm') // Blood Mage call c.setCallback(CustomRaceCall.SetupGoldMine) call c.setAIScript("human.ai") endfunction endlibrary //==================================================================== // ORC SETUP //==================================================================== library OrcSetup initializer Init requires CustomRaceSystem, GoldMineSetup private function SetupGoldMine takes player play, group workers, unit goldmine, unit townhall, unit randhero returns nothing call GoldMineSetup(play, goldmine) call DestroyGroup(workers) endfunction private function Init takes nothing returns nothing local CustomRace c = CustomRace.create("Orc",RACE_ORC,1.0) call c.setTownHall('ogre') // Great Hall call c.addWorkerType('opeo',c.NEAR_MINE,5) // Peon call c.addHeroType('Obla') // Blademaster call c.addHeroType('Ofar') // Far Seer call c.addHeroType('Otch') // Tauren Chieftain call c.addHeroType('Oshd') // Shadow Hunter call c.setCallback(CustomRaceCall.SetupGoldMine) call c.setAIScript("orc.ai") endfunction endlibrary //==================================================================== // UNDEAD SETUP //==================================================================== library UndeadSetup initializer Init requires CustomRaceSystem, GoldMineSetup private function WorkerHideToggle takes nothing returns nothing call ShowUnit(GetEnumUnit(),IsUnitHidden(GetEnumUnit())) endfunction private function HauntGoldMine takes player play, group workers, unit goldmine, unit townhall, unit randhero returns nothing local integer id=GetPlayerId(play) call GoldMineSetup(play, goldmine) call ForGroup(workers,function WorkerHideToggle) call BlightGoldMineForPlayerBJ(goldMines[id][0],play) call BlightGoldMineForPlayerBJ(goldMines[id][1],play) call ForGroup(workers,function WorkerHideToggle) call DestroyGroup(workers) endfunction private function Init takes nothing returns nothing local CustomRace c = CustomRace.create("Undead",RACE_UNDEAD,1.0) call c.setTownHall('unpl') // Necropolis call c.addWorkerType('uaco',c.NEAR_MINE,3) // Acolyte call c.addWorkerType('ugho',c.NEAR_HALL,1) // Ghoul call c.addHeroType('Udea') // Death Knight call c.addHeroType('Ulic') // Lich call c.addHeroType('Udre') // Dreadlord call c.addHeroType('Ucrl') // Crypt Lord call c.setCallback(CustomRaceCall.HauntGoldMine) call c.setAIScript("undead.ai") endfunction endlibrary //==================================================================== // NIGHT ELF SETUP //==================================================================== library NightElfSetup initializer Init requires CustomRaceSystem, GoldMineSetup private function EntangleGoldMine takes player play, group workers, unit goldmine, unit townhall, unit randhero returns nothing local integer id=GetPlayerId(play) call GoldMineSetup(play, goldmine) call SetUnitPosition(townhall,GetUnitX(goldMines[id][0]),GetUnitY(goldMines[id][0])) call IssueTargetOrder(townhall, "entangleinstant", goldMines[id][0]) call SetUnitPosition(townhall,GetUnitX(goldMines[id][1]),GetUnitY(goldMines[id][1])) call IssueTargetOrder(townhall, "entangleinstant", goldMines[id][1]) call DestroyGroup(workers) endfunction private function Init takes nothing returns nothing local CustomRace c = CustomRace.create("Night Elf",RACE_NIGHTELF,1.0) call c.setTownHall('etol') // Tree of Life call c.addWorkerType('ewsp',c.NEAR_MINE,5) // Wisp call c.addHeroType('Ekee') // Keeper of the Grove call c.addHeroType('Emoo') // Priestess of the Moon call c.addHeroType('Edem') // Demon Hunter call c.addHeroType('Ewar') // Warden call c.setCallback(CustomRaceCall.EntangleGoldMine) call c.setAIScript("elf.ai") endfunction endlibrary Although it is possible that the engine simply does not support blighting/entangling multiple mines at the same time, in which case you might need to use timers to delay the blighting/entangling of the second mine. |
| 06-22-2011, 06:50 PM | #3 |
As I mentioned, I'm using GUI because I don't know how to manipulate JASS at all. When the concept I'm working on was going to be a 1-player thing, I discovered that you can haunt multiple gold mines (with a single necropolis) but you can't entangle more than one because haunting is a unit-based action, while entangling is tied to the tree of life/etc that is ordered to do it. I got around it by replacing each mine for a night elf player with an entangled mine, then giving them to the player and resetting the unit variables. I'm actually more concerned with how to "tie" a pair of mines to a given player, possibly putting all the mines into one array and using some math function based on the present player's index, but I'm not sure what the best way is. I could simply make a variable for each mine and use a ton of if-then statements, but that would very messy and tedious every time I might want to use them for something. |
| 06-22-2011, 07:20 PM | #4 |
Well, at map initialization I would loop through all players and for each one, do a "pick all units in range and do actions" action around their start position. In there, I would check if the picked unit is a gold mine (or an entangled/haunted gold mine, in case those are different unit types, since by then the melee initialization code might have already converted them) and if it is, add it to an array for a player (you can simulate a 2D array by calculating the 1D array index as playerId*MAX_MINES_PER_PLAYER+mineCounter, mineCounter is an integer variable that you set to 0 before doing the group enum and then increase it by 1 whenever you add a mine tot he array). If the player is a night elf or an undead, you can also replace the mines as needed. I hope I described it clearly enough, unfortunately I can't give you a GUI trigger that you could easily copy&paste the way I could do with a vJass script. |
| 06-23-2011, 01:13 AM | #5 |
Thank you very much. Once I figured out what you were saying I saw it works extremely well, but for one thing. When I went and calculated that for myself there were extra parts of the array not being used (like, with 2 mines it would start with 2, with 3 mines it would start with 3, which would leave that many things unused). I added in a subtraction of the maximum number of mines so it now looks like this: Trigger: Unit Group - Pick every unit in (Units in (Region centered at ((Picked player) start location) with size (100.00, 100.00)) matching ((Unit-type of (Matching unit)) Equal to Gold Mine)) and do (Actions)
And all the other parts that need to find those mines use the same calculation. |
| 06-23-2011, 09:42 AM | #7 |
"Leaking pretty big" is quite an overstatement. This code runs only once for each player at the start of the map. Besides, this is GUI, things will leak anyway, however he could easily avoid the rect leak by picking units in range rather than in region. By the way, I'm surprised the posted code works because the size of the region is so small, I wouldn't expect gold mines to be close enough to the start location to fit in such a small region. |
| 06-23-2011, 03:08 PM | #8 |
To be honest, I haven't tested the map yet because there are a lot of basic things that aren't put together yet. I really just don't know how big a "1" is for wc3 triggers, but the mines were intentionally placed pretty close to the start positions. Out of mostly curiosity, what does bj_wantdestroygroup do? |
| 06-23-2011, 04:55 PM | #9 | ||
Quote:
Quote:
JASS:function ForGroupBJ takes group whichGroup, code callback returns nothing // If the user wants the group destroyed, remember that fact and clear // the flag, in case it is used again in the callback. local boolean wantDestroy = bj_wantDestroyGroup set bj_wantDestroyGroup = false call ForGroup(whichGroup, callback) // If the user wants the group destroyed, do so now. if (wantDestroy) then call DestroyGroup(whichGroup) endif endfunction |
| 06-25-2011, 04:44 PM | #10 |
Okay, still working on the map and I have a quick question. I have a trigger which checks when a mine dies, and another trigger activated at certain times which refreshes mines. The mine-refreshing trigger first kills any living mines with 0 gold in them, since haunted mines actually take a few seconds to die after running out of resources. I want to know: Will the mine-refreshing trigger's killing the mine cause the mine death trigger to fire and set the variable for whether that mine is alive or not before the mine-refreshing trigger moves forward? This is the first part of the gold refreshing trigger in question: Trigger: ![]() Custom script: set bj_wantDestroyGroup = true |
| 06-25-2011, 07:51 PM | #11 | ||
Quote:
Quote:
|
| 06-26-2011, 09:10 AM | #13 | |||
Quote:
Quote:
Quote:
|
| 06-26-2011, 10:10 PM | #14 |
Looks like I already had the fixed start locations set...and then I discovered a checkbox in the "Forces" tab called "Fixed Player Settings". Okay, yeah. The regions work fine, based on the unit-creation test. Since the trigger in question makes use of the various regions, I thought the error was related to a variable not being set, but I was wrong. I think I may have discovered the source of the fatal error. It wasn't in the initialization at all, but rather in the round-making triggers. It was exactly when that one was supposed to run that the game exploded, and the reason was that I made a reference to "picked player" in the middle of a loop based on integer A, without any statement of picking players. It still won't kill the unused player slots. In fact, it acts like this condition is neither true nor false: Trigger: EDIT: When it's just me as player 1 (red) user, and brown, the Player 12 computer not considered by this set of triggers at all, the game still deletes player 2's stuff for some reason. Maybe I'd be better off working backwards and creating mines in zones instead of having them generated at the start and destroying them... EDIT EDIT: It seems that the problem was most likely the attempt to select units surrounding the start location of a player not being used. I say that because when I set it up to generate the gold mines for existing players, and delete trees for non-playing players, it worked perfectly. |
