• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Seeking Object Editor Wisdom: Complex Question

Status
Not open for further replies.
I'm making a Voidwalker-ish race for a race mod project, and their Shrine of the Æther serves both as a Town Hall and as 6 peasants. It drains gold with a custom lightning effect energy beam and lumber with a bright green laser. All of that works fine.

While I was developing the Building for the race, I made a spellbook with several Charge Gold and Lumber abilities, which when activated ran a fancy series of JASS scripts I wrote to activate hidden Build Tiny abilities on the building so that each one will build a respective building. In this way, the race summons their buildings with their town center with a long range (currently it can summon buildings from up to 4200 range, but only upon Void-corrupted ground, which functions as blight)

In my test map where I had all of this laid out it was working like a sweet charm, but then I hit a stump. Charge Gold and Lumber does not actually require the tech put on its "requirements" lists, so even though I have the summoning of buildings long-range functioning great with building costs functioning perfectly, I realized that nothing required anything (which I at first did not notice in my test map where all the buildings required are already placed.)
Is there any other Instant (No Target) spell that displays gold and lumber costs, has a functional Requires list (it does not need to actually make the player pay the costs, I just want it on the UI panel) and can function inside of a spellbook? I have already tried using a series of Destroyer-form type morphing abilities for the gold/lumber/requirement UI display, which worked great except that they always display on the unit's normal command card as well as in the spellbook.
So, I'm looking for a spell suggestion. I do not want to make a series of added and removed hidden spellbooks containing passive abilities that say "This building requires this" and "That building requires that," because it would be a very tedious process, but it is the last possibility I can think of to solve my problem. Is there anyone out there with a better idea for me to try?

:vw_death:<----- The Void will be dead if you don't help me.
 
Level 13
Joined
May 11, 2008
Messages
1,198
blue troll berserk requires berserker upgrade?
other instant spells include windwalk, frenzy, almost all kinds of summon abilities...such as summon phoenix, summon bear, there is also roar, howl of terror...

not knowing much about costs of spells like for gold and lumber, haven't delved into that much...

err....have you seen the libram thread? libram mimicks a spell book. it MIGHT be what you need...
http://www.hiveworkshop.com/forums/spells-569/libram-v2-0-0-0-a-193521/
 
Level 4
Joined
Aug 8, 2011
Messages
84
If nothing else works you can fake the requirements with triggers; cause the build process to stop if the requirements are not met. If you don't get the "This building requires whatever" message, you can create that too with triggers.
 
Hmm... I took a quick look at Libram, it seems like the right kind of idea for what I need but because it's written in vJASS and for my mod so far I've only used JASS.
But, I was thinking it might work to make a quick sort of similar system in JASS to handle the abilities, it would allow me to use morphing abilities to display costs and requirements correctly and they wouldn't appear outside the custom spellbook because it would be handled with triggers. I don't have much time this morning, but I'm going to look in to that next time I get the chance.

Morphing abilities can swap out a unit's spells, I wonder if it could be as simple as using a morphing ability instead of a spellbook.
 
Hmm... To my understanding, vJASS was something that was inserted into a map by a special editor. Because of that, I really don't know how I'd input vJASS code into Blizzard.j for my mod the way that I've been doing with plain old JASS. Do you know if there's a way to have vJASS in mods?
 
Level 13
Joined
May 11, 2008
Messages
1,198
Hmm... To my understanding, vJASS was something that was inserted into a map by a special editor. Because of that, I really don't know how I'd input vJASS code into Blizzard.j for my mod the way that I've been doing with plain old JASS. Do you know if there's a way to have vJASS in mods?

vjass is what you write into your trigger editor. a compiler(the vjass compiler is called jasshelper) converts it into regular jass when you save the map...just as gui is normally automatically converted into regular jass.

there's also a cjass compiler called adichelper. it requires jasshelper, pretty much.
 
I remember once looking at the war3map.j file created by jasshelper, and all the functions were named things like "AA" and "AB" so that no one other than the computer could understand them. With that being the case, I think it would be quite difficult to move the crazy-named functions into the Blizzard.j game script file without bringing all map init scripts and other things that I wouldn't want copied into every melee map played. Is there some way for jasshelper to compile to something a human could understand so that they could selectively move the parts of the generated jass that they wanted?
 
Level 13
Joined
May 11, 2008
Messages
1,198
I remember once looking at the war3map.j file created by jasshelper, and all the functions were named things like "AA" and "AB" so that no one other than the computer could understand them. With that being the case, I think it would be quite difficult to move the crazy-named functions into the Blizzard.j game script file without bringing all map init scripts and other things that I wouldn't want copied into every melee map played. Is there some way for jasshelper to compile to something a human could understand so that they could selectively move the parts of the generated jass that they wanted?

why don't you export map script? it should be easy to read, complete with comments...perhaps you're looking at the war3map.j file of a protected map.
 
I finally got some time and tried doing that, but the exported script had stuff in it like "library" declarations, and I'm certain that if I put those into my mod's Blizzard.j file it would crash the game because the Blizzard.j is only parsed as JASS, not vJASS.
Any idea what part of the system actually reads the vJASS and turns it into something Warcraft can use? What would it take to put that part of the system into my mod?
 
If you want to be able to parse vJASS, first download this:
http://sc2modding.info/warcraft3/wc3-editing-tools/jass-new-generation-pack-(jngp)/

It is a custom editor that allows you to parse both vJASS and regular JASS, as well as having some other features. (such as having 16 tiles in a map) All of its features are 100% playable in normal Warcraft III, so there is no need to worry about converting the vJASS to JASS or anything like that. As long as you have the file open in the NewGen Editor, there shouldn't be any problems.

If you don't feel like downloading Jass NewGen Pack, then I recommend that you do this:
If nothing else works you can fake the requirements with triggers; cause the build process to stop if the requirements are not met. If you don't get the "This building requires whatever" message, you can create that too with triggers.

As that would be the next best route. Just detect the build issue order (EVENT_UNIT_ISSUED_POINT_ORDER) and then check the necessary requirements. To detect the requirements, you can either make a database (just add all the info of the requirements of each building into a hashtable or globals or something like that) or you can add the building ability to a dummy unit of that player, and then have them try to build the building instead. (if they can't, then that means that they don't meet the requirements)

Then you can follow it with a realistic error message:
http://wc3jass.com/viewtopic.php?t=239
 
I've already a got a system that enforces gold/lumber/food/etc costs on the buildings which does basically exactly everything you suggested except for the fact that it checks the creation of the building and removes it, instead of canceling the order (honestly it's probably smarter to check the order like you suggested, I may change that).
The reason I didn't just want to add requirement enforcement to that is that it would function differently on the player's UI. But, over the past few days, I made a system that adds and removes spellbooks with disabled icons for the abilities, and it seems to work. The only issue is that the disabled icons would float around the spellbook because unlike Charge Gold & Lumber their button position does not function inside a spellbook (they instead order themselves from beginning to end in the book, based on when each was added). But, I think I've overcome the issue with an iconless Charge Gold & Lumber placeholder on the list where there's no building. (Currently this race does not obtain food from farms, but rather by simply starting with max food cap. One might argue it's a little overpowered, but the races in the mod are on a higher power level than original warcraft races.)

If you're interested, or want to suggest anything, here's a copy of my code for the spellbook adding and removing (note that it uses Vexorian's CasterSystem version 12-13ish):
(And I apologize, I didn't comment much so it's a bit atrocious to read. I left some info at the bottom in the init function, read that to understand the system's main functional objective.)


Code:
function RetTrig_ReqSys_TechComplete_Conditions takes nothing returns boolean
    
    return IsUnitType(GetTriggerUnit(),UNIT_TYPE_STRUCTURE)//HaveStoredInteger(CSCache(),I2S(CS_H2I(GetConstructedStructure())),"ReqSys_NumAbils")
endfunction

function ReqSys_AbilFilter takes nothing returns boolean
    return (GetUnitAbilityLevel(GetFilterUnit(),bj_forceCountPlayers)>=1)
endfunction


function ReqSys_SwapSpells takes nothing returns nothing
    local integer rabilid=bj_forceCountPlayers
    local integer abilid=bj_groupCountUnits
    local unit e=GetEnumUnit()
    call UnitRemoveAbility(e,rabilid)
//    call BJDebugMsg(GetAbilityName(rabilid)+" is being removed from "+GetUnitName(e)+".")    
    call UnitAddAbility(e,abilid)
//    call BJDebugMsg(GetAbilityName(abilid)+" is being added to "+GetUnitName(e)+".")    
    set e=null
endfunction

function LivingDonePlayerUnitsOfTypeIdFilter takes nothing returns boolean
    local unit filterUnit = GetFilterUnit()
    return (IsUnitAliveBJ(filterUnit) and GetUnitTypeId(filterUnit) == bj_livingPlayerUnitsTypeId) and GetUnitAbilityLevel(filterUnit,'A0H9')>=1
endfunction

function CountLivingDonePlayerUnitsOfTypeId takes integer unitId, player whichPlayer returns integer
    local group g
    local integer matchedCount
    local boolexpr b=Filter(function LivingDonePlayerUnitsOfTypeIdFilter)

    set g = CreateGroup()
    set bj_livingPlayerUnitsTypeId = unitId
    call GroupEnumUnitsOfPlayer(g, whichPlayer, b)
    set matchedCount = CountUnitsInGroup(g)
    call DestroyGroup(g)
    call DestroyBoolExpr(b)
    set b=null
    set g=null

    return matchedCount
endfunction

function ReqSys_PlayerRefreshAll takes player p returns nothing
    local integer n=GetStoredInteger(CSCache(),"ReqSys","NumAbils")
    local integer i=0
    local integer ix=0
    local integer nx
    local integer abilid
    local integer rabilid
    local group g
    local boolexpr b
    local boolean  hasreqs
    loop
        exitwhen i==n
        set rabilid=GetStoredInteger(CSCache(),"ReqSys","ReqAbil"+I2S(i))
        set abilid=GetStoredInteger(CSCache(),"ReqSys","Abil"+I2S(i))
        set ix=0
        set nx=GetStoredInteger(CSCache(),I2S(abilid),"StructN")
        set hasreqs=true
        loop
            exitwhen ix==nx
            if not(CountLivingDonePlayerUnitsOfTypeId(GetStoredInteger(CSCache(),I2S(abilid),"Struct"+I2S(ix)),p)>=1) then
            set hasreqs=false
            endif 
            set ix=ix+1
        endloop
        
        if hasreqs==true then
        set bj_groupCountUnits=abilid
        set bj_forceCountPlayers=rabilid
        else
        set bj_groupCountUnits=rabilid
        set bj_forceCountPlayers=abilid     
        endif
        
        set g=CreateGroup()
        set b=Filter(function ReqSys_AbilFilter)
        call GroupEnumUnitsOfPlayer(g,p,b)
        
        call ForGroup(g,function ReqSys_SwapSpells)
        call DestroyGroup(g)
        call DestroyBoolExpr(b)
        
        set i=i+1
    endloop
    set g=null
    set b=null
endfunction

function ReqSys_RefreshAllEnum takes nothing returns nothing
    local player p=GetEnumPlayer()
    call ReqSys_PlayerRefreshAll(p)
endfunction

function ReqSys_RefreshAll takes nothing returns nothing
    call ForForce(bj_FORCE_ALL_PLAYERS,function ReqSys_RefreshAllEnum)

endfunction

function RetTrig_ReqSys_TechComplete_Actions takes nothing returns nothing
//    local unit u=GetConstructedStructure()
//    local string uid=I2S(CS_H2I(u))
//    local integer n=GetStoredInteger(CSCache(),uid,"ReqSys_NumAbils")
//    local integer i=0
//    local integer abilid
//    local integer rabilid
//    local group g
//    local boolexpr b
//    
//    loop
//        exitwhen i=n
//        set rabilid=GetStoredInteger(CSCache(),uid,"ReqAbil"+I2S(i))
//        set abilid=GetStoredInteger(CSCache(),uid,"Abil"+I2S(i))
//        if HaveStoredInteger(CSCache(),abilid,"Reqs"
//        set bj_groupCountUnits=rabilid
//        set g=CreateGroup()
//        set b=Filter(function ReqSys_AbilFilter)
//        call GroupEnumUnitsOfPlayer(g,GetOwningPlayer(u),b)
//        set bj_groupCountUnits=abilid
//        set bj_forceCountPlayers=rabilid
//        call ForGroup(b,function ReqSys_SwapSpells)
//        call DestroyGroup(g)
//        call DestroyBoolExpr(b)
//        set i=i+1
//    endloop
//    set g=null
//    set b=null
//    set u=null
call ReqSys_PlayerRefreshAll(GetOwningPlayer(GetTriggerUnit()))
if GetTriggerUnit()==GetConstructedStructure() then
call UnitAddAbility(GetTriggerUnit(),'A0H9')//This is an ability with no art and no effect that signifies a unit is completed building, because there's no native for that
call UnitMakeAbilityPermanent(GetTriggerUnit(),true,'A0H9')
endif
endfunction

//==== Init Trigger ReqSys_TechComplete ====
function InitRetTrig_ReqSys_TechComplete takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH)
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_UPGRADE_FINISH)
    call TriggerRegisterEnterRectSimple(t, GetWorldBounds())
    call TriggerAddCondition(t, Condition(function RetTrig_ReqSys_TechComplete_Conditions))
    call TriggerAddAction(t, function RetTrig_ReqSys_TechComplete_Actions)
    set t=null    
endfunction

function RetTrig_ReqSys_TechLoss_Conditions takes nothing returns boolean
    
    return HaveStoredInteger(CSCache(),I2S(CS_H2I(GetDyingUnit())),"ReqSys_NumAbils")
endfunction

function RetTrig_ReqSys_TechLoss_Actions takes nothing returns nothing
call ReqSys_PlayerRefreshAll(GetOwningPlayer(GetDyingUnit()))
endfunction

//==== Init Trigger ReqSys_TechLoss ====
function InitRetTrig_ReqSys_TechLoss takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
//    call TriggerAddCondition(t, Condition(function RetTrig_ReqSys_TechLoss_Conditions))
    call TriggerAddAction(t, function RetTrig_ReqSys_TechLoss_Actions)
    set t=null
endfunction


function ReqSys_DisableSpbk takes nothing returns nothing
local player p=GetEnumPlayer()
call SetPlayerAbilityAvailable(p,bj_groupCountUnits,false)
call SetPlayerAbilityAvailable(p,bj_forceCountPlayers,false)
set p=null
endfunction

function ReqSys_AddSpellStructReq takes integer abilityId, integer disableAbilityId, integer structId, boolean spbk returns nothing
local integer n=GetStoredInteger(CSCache(),"ReqSys","NumAbils")
local integer nx=GetStoredInteger(CSCache(),I2S(abilityId),"StructN")
if HaveStoredInteger(CSCache(),I2S(abilityId),"ReqN") then
set n=GetStoredInteger(CSCache(),I2S(abilityId),"ReqN")
endif
if spbk then
    set bj_groupCountUnits=abilityId
    set bj_forceCountPlayers=disableAbilityId
    call ForForce(bj_FORCE_ALL_PLAYERS,function ReqSys_DisableSpbk)
endif
call StoreInteger(CSCache(),"ReqSys","ReqAbil"+I2S(n),disableAbilityId)
call StoreInteger(CSCache(),"ReqSys","Abil"+I2S(n),abilityId)
call StoreInteger(CSCache(),I2S(abilityId),"Struct"+I2S(nx),structId) 
call StoreInteger(CSCache(),I2S(abilityId),"ReqN",n)
call StoreInteger(CSCache(),"ReqSys","NumAbils",n+1)
call StoreInteger(CSCache(),I2S(abilityId),"StructN",nx+1)
endfunction


function InitRetReqSys takes nothing returns nothing
call InitRetTrig_ReqSys_TechLoss()
call InitRetTrig_ReqSys_TechComplete()
call ReqSys_AddSpellStructReq('A0PP','A0PX','h02I',true)
call ReqSys_AddSpellStructReq('A0PQ','A0PY','h02F',true)
call ReqSys_AddSpellStructReq('A0Q0','A0Q5','h02I',true)
call ReqSys_AddSpellStructReq('A0PR','A0PZ','h02F',true)
call ReqSys_AddSpellStructReq('A0PR','A0PZ','h02I',false)
//So the way this part works is that the first ability code is a spellbook with
//the Charge Gold & Lumber abilities for which requirements don't work,
//and the second code is for a spellbook with versions of those abilities
//made off of "Channel" that require the proper tech correctly. The
//third code is the code for the structure which the abilities inside that spellbook
//require. Essentially, as long as the structure code does not exist, ability #1 is
//replaced with ability #2.
//The boolean defines whether or not the system hides the spellbook
// (SetPlayerAbilityAvailable) so that it will simply stack with a pre-existant one.
//The only reason this should really be false would be if I re-used this system for
//abilities outside of spellbooks. Flagging it false is also useful as in the bottom of
//the five examples, which requires 2 different structures and I didn't want the
//computer to waste processing power disabling the spellbook twice.
endfunction


The other issue with this is the fact that the player can click the placeholder iconless charge gold and lumber to do nothing, and it has an empty tooltip. Unfortunately, I think there isn't an easy way to fix either of these; when I tried to use a passive in place of it the spellbook moved the icons around and the button positions didn't work. I've attached a pic of what I mean, let me know if you have any good suggestions for how to fix that.

Also, back to the question of vJASS, I still don't see how it would work for this mod. I've had the NewGen pack for quite a while, but I've neglected to use it much so I could understand if I'm wrong about this; however, while I understand that a map with vJASS put into it is fully playable in WC3 and that the NewGen editor can effectively parse vJASS and JASS both, my issue is making the WarCraft III game itself parse vJASS. Because the NewGen editor makes vJASS code work in normal warcraft by converting it into normal JASS with many, complex functions running, I feel it would be very difficult to inject vJASS code into a mod of the game. The NewGen editor produces "war3map.j" files from vJASS, which includes map specific code. For my mod, I've pasted several non-map specific spell enhancing functions and such into "Scripts\Blizzard.j," the normal melee map warcraft script file, and placed Blizzard.j in my mod's MPQ archive. The only way I could see to get vJASS into that file (or any other similar internal melee game script file) would be either to hack warcraft 3's dll's to parse vJASS (and I haven't the slightest ability to do that) or to parse vJASS with the NewGen editor into a war3map.j file, then copy all of the bizarre hectic functions that it would create into "Blizzard.j". Even then, the JASS-parsed version of war3map.j would include map-specific code, and it would be very difficult to separate out the particular part of the code that I wanted within the mod.
That's a full explanation of my understanding of vJASS and why I have not used it in my mod. That said, if somebody has a version of the NewGen pack that saves the parsed vJASS into Blizzard.j and not war3map.j, I'd be quite interested in using it.
 

Attachments

  • BadTooltips.png
    BadTooltips.png
    2.8 MB · Views: 135
Last edited:
Status
Not open for further replies.
Top