• 0

    posted a message on Exclusive targetting

    Thank you for the very long post :-)

    I have attached my map below, it does not work - all marines attack the same target and the buff is only applied sometimes. I have to go out a bit now but will take a look again when I get back.

    The main problem for me is the Data editor is sooooooo laggy. When I click something it takes literally 5+ seconds before anything happens.

    When you start the map up, click one of the beacons, select "Barracks", and then place the beacon on the road somewhere close to the barracks. That will create 3 marines, and they will respawn with 1000 HP.

    Zerglings are spawned with randomly 500-1000 hp. They can not be targetted at the moment you need to change that in the Library custom code section. Everything is in one big bulk of code at the moment because that is easier for me to work with. Once things are more stable I will separate the UI code and the code per tower, etc.

    Posted in: Galaxy Scripting
  • 0

    posted a message on Exclusive targetting

    Thank you!

    I understand 25% of your post. Can someone link me to a relevant tutorial or show me more in detail how this would work?

    Posted in: Galaxy Scripting
  • 0

    posted a message on Exclusive targetting

    Hi, So, this is certainly possible, but I would like to do it without constant calls to check units within regions and so forth.

    1. Imagine a road leading from one edge of the map to the other.
    2. Imagine a continous stream of Hydralisks, with 1000 life. All Hydralisks are on plain Move (so no attack) command from one end to the other.
    3. Imagine 10 marines standing Hold Position in the middle, with 1000 life.

    They are hostile towards eachother.

    When a Hydralisks walks in to range of an idle marine, a few things happen:

    1. This marine attacks the Hydralisk
    2. The Hydralisk attacks the marine
    3. This marine registers that it should hold this Hydralisk until either it or he dies. So the Hydralisk has been "arrested"/tagged.
    4. All other marines may fire at will, but remain idle so they can arrest their own Hydralisk when possible.

    After a while, 10 Marines will stand there fighting 10 Hydralisks to the death while any other Hydralisks will simply walk past.

    And I want to do this mostly without the Data editor, at least for the Hydralisk. The Marine can be modified if needed.

    So, my thought was to:

    • Give all units that spawn on the map a UnitSetCustomValue id=1...N
    • When a marine TriggerAddEventUnitAcquiredTarget:
    • Check if any other marines are attacking this target
    • If so, do not set any customvalue on the marine, but attack the Hydralisk
    • If not, set a custom value arrested=hydraId, AND set custom value on hydralisk, arrester=marineId When a Hydralisk dies:
    • Check if any Marine on the map has set arrested to this Hydras ID. And if so, clear the field (-1). When a Marine dies:
    • Put Hydralisk back on Move command.

    Now the problem is when a marine is attacking a Hydralisk that is not arrested by him and a new Hydra walks in to range, we do not know about it. We could, if we used a Region with unit enters, loop through all marines and hydras and cross-check to see who is targetting who. But imagine this going on 5-10 places on the map, 24/7.

    Is that too expensive? How else should I do this? Am I just fixated on performance, will it not have any impact at all doing these region checks?

    Thank you :-)

    Posted in: Galaxy Scripting
  • 0

    posted a message on Advanced script example

    Okay so I could really use some help making this stuff to a library. I have renamed the library ID to "Spwn" and tried adding it to the "CGame" GameplaySettings object TriggerLibraries thing as both "Spwn" + "" "Spwn" + "Base.SC2Data/LibSpwn" ( for some reason I did not try with LibSpwn.galaxy yet but now I've been fiddling with this crap for HOURS and I give up until tomorrow ) Then I publish it to BNet and add as dependency in a new map.

    But it never runs the LibSpwn.galaxy file. How can I make it? It should be so that when you add the library in another map, the library gets loaded right? What the hell is going on?

    And how come it's called "CGame" when every other map and mod that I see has it listed in the Gameplay Data tab as "Default SC2 Gameplay Settings"?

    And why is it sometimes blue, sometimes brown, sometimes gray?

    Posted in: Galaxy Scripting
  • 0

    posted a message on Advanced script example

    Thanks for your most excellent guidance. I've attached the latest version of my crap.

    If anyone would be so kind as to tell me where my code really sucks, that would be awesome!

    In the Data editor in the Evil Regions table, you can change "Action" to things from here: http://www.sc2mapster.com/paste/12941/ If you want to play. But just load the map up, start it, and move the tank to one of the 3 signs at the bottom. They all do the same thing.

    Note that if you stagger so much that the timer will go over the specified repeat, I have not tested that and don't care, really. There are also probably some other things you could do to break it.

    You can call

    libCp_ManuallyTriggerRegion(string regionName, int budget);
    

    To manually trigger.

    I think there is one bug. Some times, and I have not tested this enough to verify how or when, when you enter either the first or the last of the additional 3 trigger regions with your tank, it will not start the spawns.

    EDIT: Okay so I already found a few bugs. For example you can only have Repeat set to 30 in the attached version. Anyway that's what you get when coding for one test case, and it's not really important.

    I am more interested in the level of shitty in my code. Someone tell me how bad it runs please, and that it needs to be optimized in 5 different ways. And then enumerate those ways :-P Thank you!

    All suggestions welcome!

    Posted in: Galaxy Scripting
  • 0

    posted a message on Advanced script example

    Okay so tell me, how crazy am I here? So as you might have guessed, I will do the galaxy coding while a real mapper will do the layout and world stuff.

    I think my next step is creating a test map which means I have to fiddle with the world editor and learn some things there, too.

    // ZZZ Build a table of User Data in the SC2 Editor with the name and
    // fields defined below.
    
    // Can name the table anything as long as the id is "EvilRegions"
    static const string _cpCoreRegionListKey = "EvilRegions"
    // Region name as defined in world editor. Put all buildings that should
    // autospawn inside this region.
    // Type: String
    // Amount: 1
    static const string _cpCoreRegionFieldName = "Region Name"
    // How many resources this evil base region has access to per wave.
    // We multiply this based on difficulty (for example * 4 is very hard,
    // * 0.6 is easy and * 1 is normal).
    // Type: Integer
    // Amount: 1
    static const string _cpCoreRegionFieldMinerals = "Resources";
    // Can also trigger this base to start spawning from the regions
    // defined here. And yes, I know you can combine regions.
    // Note also that we don't look for spawning buildings in these, that's just in
    // the main region.
    // Type: String
    // Amount: 10
    static const string _cpCoreRegionFieldTriggerRegions = "Trigger Regions";
    // What should happen when a player enters this base?
    // Type: String
    // Amount: 1
    static const string _cpCoreRegionFieldAction = "Action";
    // Can be "Spawn X", where X is seconds between waves
    // We need to figure out the other action types
    
    // Make a new User Data table with these names and fields.
    static const string _cpCoreSettingsListKey = "CPSettings";
    // If these unit types enter a region, do not start events.
    // Type: String
    // Amount: 1
    static const string _cpCoreSettingsIgnore = "ignoreUnitTypes";
    // Spawn units from these kinds of buildings
    // Type: String
    // Amount: 1
    static const string _cpCoreSettingsSpawners = "spawnFromTypes";
    
    static string getSetting(string settingKey) {
        return UserDataGetString(_cpCoreSettingsListKey, settingKey, "Key", 1);
    }
    
    static struct SETTINGS {
        string ignoreUnitTypes;
        string spawners;
    }
    // XXX Defaults, init them somewhere
    // SETTINGS.ignoreUnitTypes = "Medivac Battlecruiser Raven Banshee VoidRay VikingFighter ProtossRelic"
    // SETTINGS.spawners = "BanelingNest EvolutionChamber GreaterSpire Hatchery Hive HydraliskDen InfestationPit Lair LurkerDen RoachWarren SpawningPool Spire UltraliskCavern"
    
    static const int _maxEvilRegions = 100;
    struct RegionData {
        string name;
        region regionRef;
        int resources;
        region[10] triggers;
        string action;
    }
    // Map of region + trigger region to master region name
    struct RegionRef {
        region ref;
        string name;
    }
    static int _cpRegionRefAmount = 0;
    static RegionRef[1000] _cpRegionRefs;
    static RegionData[_maxEvilRegions] evilRegions;
    
    // always use index=1 if the field is not an array
    static string getStr(string instance, string field, int index) {
        return UserDataGetString(_cpCoreRegionListKey, instance, field, index)
    }
    static string getInt(string instance, string field, int index) {
        return UserDataGetInt(_cpCoreRegionListKey, instance, field, index)
    }
    
    static bool _cpCoreHandleUnitEntersTrigger(bool check, bool do) {
        region triggeredByRegion = EventUnitRegion();
        unit triggeredByUnit = EventUnit();
        int i = 0;
        // xxx check if triggeredByUnit should be ignored first because it would be faster I assume
        // xxx we check if the unit belongs to a player and that it's not in SETTINGS.ignoreUnitTypes
    
        // find spawners for this region
        unitgroup spawners;
        for (; i < _cpRegionRefAmount; i += 1) {
            if (_cpRegionRefs[i].ref == triggeredByRegion) {
                spawners = DataTableGetUnitGroup(true, _cpRegionRefs[i].name);
            }
        }
        if (!spawners) {
            return true;
        }
    
        // XXX START SPAWNING UNITS HOLY SHIT IT SHOULD WORK?!
    
        TriggerDestroy(TriggerGetCurrent());
        return true;
    }
    
    static void buildRegionData() {
        string instance;
        int i;
        int j;
        string triggerRegionName;
        string regionName;
        region regionTmp;
        int regionCount = UserDataInstanceCount(_cpCoreRegionListKey);
        trigger regionTrigger;
        for (; i <= regionCount; i += 1) {
            instance = IntToString(i);
            regionName = getStr(instance, _cpCoreRegionFieldName, 1);
            regionTmp = RegionFromName(regionName);
            if (!regionTmp) {
                // XXX not sure what RegionFromName would return here, check it
                // XXX debugmessage that region doesn't exist and break
            }
    
            regionTrigger = TriggerCreate("_cpCoreHandleUnitEntersTrigger");
            TriggerAddEventUnitRegion(regionTrigger, null, regionTmp, true);
    
            evilRegions[i].name = regionName;
            evilRegions[i].resources = getInt(instance, _cpCoreRegionFieldMinerals, 1);
            evilRegions[i].action = getStr(instance, _cpCoreRegionFieldAction, 1);
            evilRegions[i].regionRef = regionTmp;
    
            _cpRegionRefs[_cpRegionRefAmount].ref = regionTmp;
            _cpRegionRefs[_cpRegionRefAmount].name = regionName;
            _cpRegionRefAmount += 1;
    
            for (; j < 10; j += 1) {
                triggerRegionName = getStr(instance, _cpCoreRegionFieldTriggerRegions, j);
                if ( triggerRegionName != "") {
                    regionTmp = RegionFromName(triggerRegionName);
                    evilRegions[i].triggers[j] = regionTmp;
                    TriggerAddEventUnitRegion(regionTrigger, null, regionTmp, true);
                    _cpRegionRefs[_cpRegionRefAmount].ref = regionTmp;
                    // ZZZ Master region name, not trigger region.
                    // ZZZ The unitgroup of spawners is stored in datatable referenced by master region.
                    _cpRegionRefs[_cpRegionRefAmount].name = regionName;
                    _cpRegionRefAmount += 1;
                }
            }
        }
    }
    
    static void findSpawners(string regionName, region r) {
        unitgroup units = UnitGroup(null, -1, r, null, 0);
        unitgroup spawners = UnitGroupEmpty();
        unit current;
        UnitGroupLoopBegin(units);
        while(!UnitGroupLoopDone()) {
            current = UnitGroupLoopCurrent();
            // Do we spawn units from this type?
            if (StringFind(SETTINGS.spawnFromTypes, UnitGetType(current))) {
                UnitGroupAdd(spawners, current);
            }
            UnitGroupLoopStep();
        }
        UnitGroupLoopEnd();
        DataTableSetUnitGroup(true, regionName, spawners);
    }
    
    static void initializeRegions() {
        int i;
    
        buildRegionData();
    
        for (; i < _maxEvilRegions; i += 1) {
            // XXX String values default to "" right? Or null? Check this.
            if (evilRegions[i].name == "") {
                break;
            }
            findSpawners(evilRegions[i].name, evilRegions[i].regionRef);
        }
    }
    
    Posted in: Galaxy Scripting
  • 0

    posted a message on Advanced script example

    Thank you, between your answers here, your map, and Cortex, I have all the code I need to inspect. Well done, good work.

    Posted in: Galaxy Scripting
  • 0

    posted a message on Advanced script example

    Thank you. That is an awesome answer, very thorough. If I make this map work then my code will be available for everyone to use. If I can't make it work through pure script then I will discontinue it, so we will see.

    The fact that I can't redeclare a static function in another file completely ruins the keyword then. Grrrr. And I suppose namespacing is impossible as well, then.

    Before reading your answer about preplacing points I had already started doing something similar but using regions instead. But I need some metadata on them, and some help :-)

    If I have a

    region x = RegionFromId(10);
    

    How can I get the regions name? I know about RegionFromName but I can't enumerate them. With RegionFromId I can just do a while loop until it returns nothing to enumerate all regions. Or at least I assume so, provided the editor keeps the id numbers going upwards an replaces unused ones. Perhaps I will end up traversing from 0-1000 and just skipping empty ones.

    Or, alternatively, can I enumerate all regions in the map?

    Is it possible to set custom values on a Region through the editor, and if so can I get them through script? I already checked and the max length of a Regions name when created through the editor is 80, so I can use that to store some metadata if I can just get to it through script.

    Posted in: Galaxy Scripting
  • 0

    posted a message on Advanced script example

    Hi, I am looking for an example of some very advanced Galaxy script. For example a complete map like Tower Defense Tycoon, if it was scripted manually, which it probably wasn't. I just need something to learn from, some script to read so that I can understand how to do basic things in Galaxy, if they are even possible.

    More specifically I want to know the best/cleanest way to

    • - repeatedly do many dynamic things if condition but stop it at some different condition (I understand TriggerAddEventTimeElapsed and such, but is it good to have 50 of those running or should I make a big one that handles all of them, even if the things happen at different intervals? If so, should I just have a |timer| running that I check for elapsed time with a big if/switch block? Should I create an array of structrefs, that contain a time and funcref, that I loop through and trigger at the right time?)
    • - can I have anonymous functions / create functions on the fly
    • - is it possible to use static functions for CreateTrigger or must it be a global one
    • - can I create unit Behaviors through Galaxy and bind them
    • - create a hash-type map like map["key"] = value

    I will probably have more questions as I go, which is why I'd rather have access to an already-existing advanced map from which I could just deduce these things myself. But it's hard to find one.

    After reading the forums here for a while I recognize many names of whom I'd like to read their code, but I can't find their maps through the editor. That probably means they have obfuscated the code right? Or locked their maps, that is.

    Also, how can I get the ID of a unit that I select with my mouse in the World Editor? The code I am working with references UnitFromId(123), but how can I find that unit in the terrain view?

    Posted in: Galaxy Scripting
  • To post a comment, please or register a new account.