| 03-16-2009, 07:49 PM | #1 |
Well, this is pretty much my first real stab at a JASS spell - such as it is. The idea sort of came about through the Custom Race topic, when people were discussing unique ways to harvest resources, build/repair things, etc. Even though I'm supposed to submit a Pandaren race, it got me thinking - a goblin race wouldn't bother repairing a damaged building. They'd just blow it up and make a new one! However, because of my inexperience in JASS, the "spell" runs into a few problems and is fairly dependent on dummy-casters. Also, the positioning of the functions (in global space) makes it easier to use, but there's probably something else I should be doing with that space (looking at other JASS spells, it looks like I should be able to stick that block of code somewhere else and still be able to get it to work...). So. Suggestions? And I haven't got a clue about vJASS yet. The spell actually comes in two forms: the first tries to rebuild the structure from scratch (making it much more authentic, I suppose) while the second simply pauses the building and gives it extremely low health, then heals it over time and unpauses when it's fully healed. Known issues: (first method) - Dummy Builder must be Undead to prevent leaks. - Building will be destroyed and not replaced if builder is unable to build the structure (including techtree requirements, e.g. Altar of Storms must exist for Fortress to be built). - Build speed cannot be increased (without making the builder Human and potentially leaking) (second method) - Depending on the healing method used, various restrictions apply. - Looks a little clumsier than the first method So, um, here's the code: JASS:// User-Defined Constants globals constant integer DUMMY_UNIT = 'u000' // Used for all implementations // Note: the dummy unit needs to be able to build everything that might be considered a valid target for Reconstruct. // It'd probably work best to intercept "bad" Reconstruct orders in the trigger that calls this function. constant string REPAIR_ORDER = "heal" // Used for BuildingRebuild endglobals // Functions // -------------------whatever, anyway this is a line I stuck here to divide stuff // The function below rebuilds a unit with the default repair order (REPAIR_ORDER). function BuildingRebuild takes unit building returns nothing local unit repairman local location site = GetUnitLoc(building) if not IsUnitType(building, UNIT_TYPE_STRUCTURE) then return endif call SetUnitAnimation(building, "birth") call SetUnitState(building, UNIT_STATE_LIFE, 1) call PauseUnit(building, true) set repairman = CreateUnitAtLoc(GetOwningPlayer(building), DUMMY_UNIT, site, bj_UNIT_FACING) call IssueTargetOrder(repairman, REPAIR_ORDER, building) loop call PolledWait(0.01) exitwhen (GetUnitState(building, UNIT_STATE_LIFE) <= 0) or (GetUnitState(building, UNIT_STATE_LIFE) >= GetUnitState(building, UNIT_STATE_MAX_LIFE)) endloop call SetUnitAnimation(building, "stand") call PauseUnit(building, false) call ShowUnit(repairman, false) call KillUnit(repairman) call RemoveLocation(site) return endfunction // You really only need this version of the function if you want it to be compatible with multiple // versions of the same spell. function BuildingRebuildOrder takes unit building, string repair returns nothing local unit repairman local location site = GetUnitLoc(building) if not IsUnitType(building, UNIT_TYPE_STRUCTURE) then return endif call SetUnitAnimation(building, "birth") call SetUnitState(building, UNIT_STATE_LIFE, 1) call PauseUnit(building, true) set repairman = CreateUnitAtLoc(GetOwningPlayer(building), DUMMY_UNIT, site, bj_UNIT_FACING) call IssueTargetOrder(repairman, repair, building) loop call PolledWait(0.01) exitwhen (GetUnitState(building, UNIT_STATE_LIFE) <= 0) or (GetUnitState(building, UNIT_STATE_LIFE) >= GetUnitState(building, UNIT_STATE_MAX_LIFE)) endloop call ShowUnit(repairman, false) call KillUnit(repairman) call RemoveLocation(site) call SetUnitAnimation(building, "stand") call PauseUnit(building, false) return endfunction // The functions below reconstruct the entire thing "from scratch". You will need all of these functions. function StupidCondFunc takes nothing returns boolean return IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == true and GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0 endfunction function BuildingReconstruct takes unit building returns nothing local unit repairman local player owner = GetOwningPlayer(building) local integer buildingId = GetUnitTypeId(building) local location site = GetUnitLoc(building) // local timer waitForBuild = CreateTimer() local integer wood local integer gold local integer couldBuild if not IsUnitType(building, UNIT_TYPE_STRUCTURE) then return endif call KillUnit(building) set repairman = CreateUnitAtLoc(owner, DUMMY_UNIT, site, bj_UNIT_FACING) set wood = GetPlayerState(owner, PLAYER_STATE_RESOURCE_LUMBER) set gold = GetPlayerState(owner, PLAYER_STATE_RESOURCE_GOLD) set couldBuild = GetPlayerTechMaxAllowed(owner, buildingId) call SetPlayerState(owner, PLAYER_STATE_RESOURCE_LUMBER, 1000000) call SetPlayerState(owner, PLAYER_STATE_RESOURCE_GOLD, 1000000) call SetPlayerTechMaxAllowed(owner, buildingId, -1) // The above just "backs up" the player's settings for an instant and sets them to the maximum. call IssueBuildOrderById(repairman, buildingId, GetLocationX(site), GetLocationY(site)) call SetPlayerTechMaxAllowed(owner, buildingId, couldBuild) call SetPlayerState(owner, PLAYER_STATE_RESOURCE_LUMBER, wood) call SetPlayerState(owner, PLAYER_STATE_RESOURCE_GOLD, gold) // The above just "restores" the player's previous settings. TechMaxAllowed isn't really necessary on // most maps, but it's handy to have in there anyway in case *someone* wants to limit the number of buildable // buildings. // call TimerStart(waitForBuild, 2, false, null) Until I figure out how to use this timer, I'm still going to call PolledWait(2) // I was deeply annoyed when I found out there was no function GetMostRecentBuildingCreatedByBuildOrderTrigger! set building = FirstOfGroup(GetUnitsInRangeOfLocMatching(1, site, Filter(function StupidCondFunc))) if IsUnitType(repairman, UNIT_TYPE_UNDEAD) == false then loop call PolledWait(0.01) exitwhen (GetUnitState(building, UNIT_STATE_LIFE) <= 0) or (GetUnitState(building, UNIT_STATE_LIFE) >= GetUnitState(building, UNIT_STATE_MAX_LIFE)) endloop endif // call DestroyTimer(waitForBuild) call ShowUnit(repairman, false) call KillUnit(repairman) call RemoveLocation(site) set building = null set owner = null return endfunction |
| 03-18-2009, 07:57 PM | #2 |
Hm, perhaps I should have put [help] in the thread title. Or...something. Anyway, I'd still like to know what I can do to fix some of the problems (if there is a solution), and if it'd look nicer in structs I'll see what I can do about a vJASS version (but if you never complain, I'll never know). |
| 03-21-2009, 07:02 PM | #3 |
I'd really appreciate some sort of feedback. Anyone have a link to a set of "coding standards"? Are there any? |
| 03-21-2009, 08:29 PM | #4 |
Sorry, I don't know how to help you (and I haven't been out of the house in order to download :P). |
| 03-22-2009, 03:44 AM | #5 |
JASS:local unit building = target JASS:local player owner = GetOwningPlayer(target) JASS:if not IsUnitType(target, UNIT_TYPE_STRUCTURE) then return endif JASS:function CreateUnitAtLocSaveLast takes player id, integer unitid, location loc, real face returns unit if (unitid == 'ugol') then set bj_lastCreatedUnit = CreateBlightedGoldmine(id, GetLocationX(loc), GetLocationY(loc), face) else set bj_lastCreatedUnit = CreateUnitAtLoc(id, unitid, loc, face) endif return bj_lastCreatedUnit endfunction JASS:CreateUnitAtLocSaveLast(owner, DUMMY_UNIT, site, bj_UNIT_FACING) JASS:CreateUnitAtLoc(GetOwningPlayer(target), DUMMY_UNIT, site, bj_UNIT_FACING) JASS:function IssueBuildOrderByIdLocBJ takes unit whichPeon, integer unitId, location loc returns boolean if (unitId == 'ugol') then return IssueHauntOrderAtLocBJ(whichPeon, loc) else return IssueBuildOrderById(whichPeon, unitId, GetLocationX(loc), GetLocationY(loc)) endif endfunction JASS:call IssueBuildOrderByIdLocBJ(repairman, buildingId, site) JASS:call IssueBuildOrderById(repairman, buildingId, GetLocationX(site), GetLocationY(site)) JASS:call PolledWait(2) JASS:if not IsUnitType(repairman, UNIT_TYPE_UNDEAD) then loop exitwhen(GetUnitLifePercent(building) > 99.99) call PolledWait(0.01) exitwhen(IsUnitDeadBJ(building)) endloop endif JASS:if not IsUnitType(repairman, UNIT_TYPE_UNDEAD) then loop exitwhen GetUnitStatePercent(target, UNIT_STATE_LIFE, UNIT_STATE_MAX_LIFE) call PolledWait(0.01) exitwhen GetUnitState(target, UNIT_STATE_LIFE) <= 0 endloop endif JASS:call ShowUnit(repairman, false) call KillUnit(repairman) JASS:call RemoveLocation(site) Also, why would the builder not being Undead cause leaks? |
| 03-22-2009, 07:36 AM | #6 | ||||||||||
Thank you so much for looking at it and providing such detailed feedback. You definitely deserve +rep, and I wish I could do more... Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
|
| 03-22-2009, 12:59 PM | #7 | |
Quote:
'the hell? 2 exitwhens? Never seen that before... And I thought polled waits had that strange ~.2 sec minimum anyway. |
| 03-22-2009, 05:52 PM | #8 |
use IsUnitType(repairman, UNIT_TYPE_UNDEAD)==false... hmm IsUnitType got some issues ...you shoudl always use "==true" or "==false" with it .. |
