Monday, May 26, 2014

Building the Triggers for Macroing King of the Hill

For this map, and I suspect many others I work on initially, the triggers will drive most of the playing experience (as opposed to clever map layouts or changes in the data). To help organize my efforts on the triggers, I'll start by listing the basic things I wish to accomplish:
  • Setup a leaderboard to keep track of a players tributes and fame
  • Create melee units for the players participating
  • Have player and computer share vision
  • Transfer ownership of units to the respective computer when tributes are given, and update the leaderboard
  • Update the leaderboard when tributes die by removing their value from the tributes
  • Update fame based on current tribute score at regular intervals
  • Have player and computer pair share upgrades
  • Have player and computer pair share supplies
Perhaps here I should include a generic disclaimer: The methods used below to accomplish the tasks mentioned above are simply the ones I tried. They are in no way the best or most efficient, I cannot even guaranty that they work (although I hope they do). Any suggestions on how to improve them, or constructive feedback as to why one way may be better than another is appreciated, just please don't complain that it sucks...because you've been warned!

Leaderboard, Melee, and Relations

I'll start with the leaderboard. I suspect there are fancy ways to use dialogues to add parts to the UI and make a very smart looking leaderboard, but I will start by using the built in functions. First, Initialization:

  • Leaderboard - Create a leaderboard with 3 columns and 7 rows, with the name "Tribute Army Value", and using (100%, 100%, 100%) color.

I think I'd like to change it later to be the actual number of people playing to limit its size, but for now let's just get it up and working. Now I'll name my leaderboard for future use:
  • Variable - Set Leaderboard = (Last created leaderboard)
Where Leaderboard is a variable: 
  • Leaderboard = No Leaderboard <Leaderboard>
Now that Leaderboard has been assigned the value of the last created leaderboard, I can name the columns:
  • Leaderboard - Set (Last created leaderboard) item text at column 1 and row Header to "Player"
  • Leaderboard - Set (Last created leaderboard) item text at column 2 and row Header to "Tributes"
  • Leaderboard - Set (Last created leaderboard) item text at column 3 and row Header to "Favor"
Now to set up the rows of the leaderboard. To do this, I'll simply iterate through the number of possible players, and catch the ones with status Playing. Once I've determined that they are playing, I'll name and color the row accordingly. Once the leaderboard is set up, I'll give the player melee units so they can begin training tributes. Finally, I set the relationship between the player and the computer 8 players larger. This is where the limit of 7 players comes in, as player 16 is not usable. Here is the code:

        General - For each integer i from 1 to 7 with increment 1, do (Actions)
            Actions
                General - If (Conditions) then do (Actions) else do (Actions)
                    If
                        (Status of player i) == Playing
                    Then
                        Leaderboard - Set Leaderboard item text at column 1 and row i to (Name of player i)
                        Leaderboard - Set (Last created leaderboard) item text color at column 1 and row i to (Color((Current player i color)))
                        Leaderboard - Set (Last created leaderboard) item text at column 2 and row i to "0"
                        Leaderboard - Set (Last created leaderboard) item text at column 3 and row i to "0"
                        Melee - Create (Race of player i) melee starting units for player i at (Start location of player i)
                        Player - Make player i and player {i+8} treat each other as Ally With Shared Vision And Pushable
                    Else

Giving Tributes

The idea behind tributes is relatively simple. Since I am looking to make a macro-only game mode, any and all micro should be done by the computer. Micro is done through the interaction of one player with another, so all player-player interactions are to be controlled by the computer AI. Essentially the players simply train heroes to fight in their name, without any orders from the player. As for the victory conditions, the invisible spectators enjoy watching combat, and will look to the players with the largest army competing. The metric for army size will be the sum of minerals and gas costs of all units participating. Therefore, there are two main things which must happen when giving tributes:
  1. The resource cost of the tributed unit must be added to the players score
  2. Control of the unit must be set to the computer player and the unit must attempt to hold the center region
The first is simple. It will be done with the use of an array:
  • Tribute Army Value = 0 <Integer[9]>
Every time a unit enters the computer control region, the 'Give Tribute' trigger will trigger. The trigger is built as follows:

Give Tribute
    Events
        Unit - Any Unit Enters (Region named "ComputerControl")
    Local Variables
        owner = (Owner of (Triggering unit)) <Integer>

With the actions accomplishing the above two tasks. The first task is accomplished with:
  • Variable - Modify Tribute Army Value[owner]: + (Sum - Minerals, Vespene cost of (Unit type of (Triggering unit)))
  • Leaderboard - Set Leaderboard item text at column 2 and row owner to (Text(Tribute Army Value[(Triggering player)]))
  • Leaderboard - Sort Leaderboard by column 2, in Descending order, with priority 1
While the second is accomplished with:
  • Unit - Change ownership of (Triggering unit) to player {owner+8} and Retain Color
  • Unit - Share Vision of (Triggering unit) with Player owner
  • AI - Add (Triggering unit) to the next attack wave for player {owner+8}
  • AI - Set the target for player {owner+8} attack (or defense) waves to be the region Hill with replace behavior Replace Never.
  • AI - Send the attack wave from player {owner+8} to attack in 0 seconds and Don't Wait
I do not know if the Share Vision action is necessary, as the player and computer are allied with shared vision, but I put it in there for good measure. I also am unsure of the best way to get the tribute to go and attack the hill as soon as it is tributed, but this should be a good first attempt.

Tribute Dies

The death of a tribute is pretty straight forward. First, set the trigger for  when a unit dies, with the condition that the owner of that unit is a computer player. Then, remove the points that unit gives from the players tributes score, and we are done! It looks something like this:

Tribute Dies
    Events
        Unit - Any Unit dies
    Local Variables
        owner = {(Owner of (Triggering unit))-8} <Integer>
    Conditions
        (Owner of (Triggering unit)) >= 9
    Actions
        Variable - Modify Tribute Army Value[owner]: - (Sum - Minerals, Vespene cost of (Unit type of (Triggering unit)))
        Leaderboard - Set Leaderboard item text at column 2 and row owner to (Text(Tribute Army Value[owner]))

Fame

Now that the very basic mechanics are in place, and the tribute score is properly generated, we can look at the metric for victory: Fame. The idea here is to have some number which gives an overview of how often a player has been the 'King of the Hill'. I suppose traditionally it would be the person who is in control of the top most point of the hill, but here we will take a more continuous approach and look at who has the greatest army in the hill region. That is where the tribute score comes in. My idea is rather simple: determine what fraction of the total score is controlled by a given player, and move their Fame score in that direction. I imagine the movement would be large if the two scores differ greatly, and smaller if the two scores are similar. Therefore, Fame will be a floating number from 0 to 1, and will be displayed on the leaderboard as a percent. Before I discuss the trigger, here are a few necessary variables:
  • Aggregate Rate = 0.001 <Real>
  • Aggregate Value = 0.0 <Real[9]>
The Aggregate Rate is multiplied into the difference between the current ratio and the Aggregate Value (Fame). The trigger that manages Fame is as follows (with some comments thrown in there):

iterate
    Events
        Timer - Every 1.0 seconds of Game Time
    Local Variables
        total = 0 <Integer>
        Percent = 0.0 <Real>
    Conditions

That is the setup. Now for the actions, we need to do a few things. First: determine the total army value on the hill:

    Actions
        General - Pick each integer from 1 to 7, and do (Actions)
            Actions
                General - If (Conditions) then do (Actions) else do (Actions)
                    If
                        Tribute Army Value[(Picked integer)] > 0
                    Then
                        Variable - Modify total: + Tribute Army Value[(Picked integer)]
                    Else

Now that we have the total determined, we can determine the Percent of the total each player has, and modify their Aggregate Value (Fame) accordingly (note the condition used to eliminate any divide by zero errors):

        General - Pick each integer from 1 to 7, and do (Actions)
            Actions
                General - If (Conditions) then do (Actions) else do (Actions)
                    If
                        (Status of player (Picked integer)) == Playing
                    Then
                        General - If (Conditions) then do (Actions) else do (Actions)
                            If
                                (Tribute Army Value[(Picked integer)] + Aggregate Value[(Picked integer)]) != 0
                            Then
                                Variable - Set Percent = {(Real(Tribute Army Value[(Picked integer)]))/(Real(total))}
                                Variable - Modify Aggregate Value[(Picked integer)]: + {(Percent-Aggregate Value[(Picked integer)])/(Percent+Aggregate Value[(Picked integer)])*Aggregate Rate}
                            Else
                        Leaderboard - Set Leaderboard item text at column 2 and row (Picked integer) to (Text(Tribute Army Value[(Picked integer)]))
                        Leaderboard - Set Leaderboard item text at column 3 and row (Picked integer) to (Text(Aggregate Value[(Picked integer)]) with Percent decimal places (Do Not use delimiters, precision limits: 0 to 0))
                    Else

One more thing we can stick in this trigger is a notification of a player dropping from the game. Note that none of their units are set to be destroyed, they must be defeated on the hill. However, the above trigger which changes the Fate value does not calculate for dropped players. In that way, a record of their Fame when they dropped is preserved.

                        General - If (Conditions) then do (Actions) else do (Actions)
                            If
                                (Status of player (Picked integer)) == Left The Game
                            Then
                                Leaderboard - Set Leaderboard item text at column 1 and row (Picked integer) to "Dropped..."
                            Else

I have one more trigger for calculating Fame, and that is a slow increase of the Aggregate Rate. This is to help prevent games from going on indefinitely.  This looks like:

Aggregate Rate Increase
    Events
        Timer - Every 150.0 seconds of Game Time
    Local Variables
    Conditions
    Actions
        Variable - Modify Aggregate Rate: + 0.001

The balancing of the Fate will probably take some time, to make sure games are long enough that players can have come-from-behind victories, but not so long as to lose appeal. The trigger which generates the victory condition itself will still need to be made, but for testing purposes I have neglected to write it (when I play solo, the game will be over before it begins). 

Learning to Share

The final part is setting up the sharing between the player and the computer. There are two things which need to be shared:
  1. Upgrades
  2. Supplies
The upgrades are simple, and accomplished with the following trigger:

Upgrade
    Events
        Unit - Any Unit research progress is Completed
    Local Variables
    Conditions
    Actions
        Tech Tree - Set (Triggering progress upgrade) upgrade level to ((Triggering progress upgrade) count for player (Triggering player), counting Complete) for player {(Triggering player)+8}

As for supplies, I spent a good amount of time looking for an equally simple approach. I was unsuccessful, and forced to come up with a more complicated approach. I will share this approach in the next post!

Wednesday, May 14, 2014

My First Map (in quite a while)

It has been a long time since I've worked in the map editor, and there was plenty of dust to blow off to get this going. For this project, I am looking for an 8 player map which meets in the center only. I do not want the players to be able to interact with each other, as I intend to have the computer take control of units before they are able to meet in glorious combat (to allow the player to focus solely on their macro). I was thinking each player would have 4 bases available to them, and would have to follow a path to the center hill.

Here is my first attempt at the map, using a tileset which may make it look a bit like a medieval arena:
The map has my main interests, but there are many things I did not like about the map. First off, I tried to use the pathing blocker to prevent flying units, as well as line of sight blocker, to get the different bases isolated from each other (this would be the red coloring). This did not work in any of my tests. I'm guessing it either only works for ground units or has other subtleties I have not worked out. Second, the bases aren't actually equal, and they do not have an equal distance to the hill. It may not really be too big of a deal, but I figured I could do better! I do like the hills that players should not have access to, as I was thinking of adding spectators and the like there, but that is purely cosmetic.

With what I've learned from my first map, I decided it would be easier to start from scratch and try a slightly different approach. Here I changed to a space station tileset, and turned on the 8-fold symmetry:
Instead of relying on regions I did not understand to limit vision, I simply made the bases far enough apart that one could not get a unit with enough vision to see the neighbors. Scratch that one off the list! It took quite a bit of doing, but here is the general approach I took to make this map:

  • Using the symmetry (or more precisely, the playable map area), find the center point, and mark it with a center point.
  • Draw a circular region, with the center at the center point, to mark the size of the battle grounds (here I wanted it big enough for large battles to take place, not sure about adding features such as choke points or line of sight blockers to add more dynamic, that will come later).
  • Using the symmetry, cut out the separations between the paths, starting at the inner corner (by the center region).
  • Play with the base size to determine how far out from the center to go until you can both have a large enough base and the bases cannot interact.
  • Define the outer bases fairly roughly, and clear away the empty space from the map
  • Turn to 4-fold symmetry to clean up the rough edges which arise from the difference between the on-axis and off-axis bases
  • Make the computer control region such that it just touches the edge of every base.
This gave the general shape of the map, the next task was to add the mineral patches and a few other helpful objects:

In this image you can see an outline of NoFly zones surrounding the base. This is the manner in which we can prevent the pathing from allowing flying units to leave the base. It is quite crude (a region would be much more helpful in this case, but is not available, to my knowledge), but gets the job done. It is important to make sure they overlap sufficiently and are as even as possible. The AI can get confused if there is a slight gap and it tries to fit through, but may not. Not too big of a deal here as we just don't want them to escape, but depending on what you are trying to do, it could be. Other details would be the 8 mineral and 2 gas for each of the 4 bases, arranged somewhat like many melee maps, and a smoke-screen to show the line where the computer takes control. I may also add some destructible rocks to make two of the bases more difficult to take, but that will come with testing.

Sunday, May 11, 2014

Map Proposal: Macroing King of the Hill

Introduction

I like to consider this map to be a 'macro-wars' style map, in contrast to the popular micro-wars maps currently available. In this map, players will have access to a cluster of bases for building their economy and training units. They will also have the option to give their units as tributes to fight for domination of the arena, earning favor as they fight. Players cannot attack each other, or control the units that fight in their honor. The game is won by a player reaching a specific level of favor.

Gameplay

Map

The design of the map will be such that each player has the same amount of space and access to minerals and gas. I am envisioning a ring of bases surrounding a central circle. These bases will be isolated from each other such that nobody can leave their own island. This will include no-fly zones surrounding the island to prevent people from attacking their neighbors directly. There will be a path between each players bases and the main battle ground. In keeping with the 'King of the Hill' mentality, I plan to have the tributes climb a hill to enter combat. This will give defenders an advantage.

Players

I am hoping for 8 human players and 8 computer players. The idea is that the computer players will handle the micro intense battle on the hill allowing the players to concentrate on building a larger economy and producing more troops to fight for their fame. I fear that I will only be able to have 7 players, as one computer is reserved for neutral objects (mineral patches, etc.). The computer and human combo will be allied with shared vision, shared supply, and shared upgrades. 

Score and Victory

I plan to use triggers to keep track of the amount of units a player/computer team has fighting on the hill. The sum of minerals and gas cost of all units on the hill will be used to determine the current popularity of the player. The value of the popularity compared to the popularity of all other players will be used to increase or decrease the players fame. Therefore, the player with the most valuable army controlling the hill for the longest time will become the winner, as that player will be the first to reach the amount of fame required to win.

Programming

Map

The map should be relatively straightforward to design. I will likely just use the 8-fold rotational symmetry and see how the bases come out. I suspect the difference between the corner and side bases will need some cleaning up after the basic layout is established. Then I'll use two circular regions, one for the hill and one for the computer control. The hill region I'll just make as the highest point in the map, and have it one large flat circular platform. The computer control region will extend along wide paths to the mouth of the players base. The point where tributes are changed from player control to computer control will be marked by some vision blocking doodad, like tall grass or a smoke screen. I think I'll start with 4 bases available on each island, and maybe block one or two with destructible rocks.

Data

I don't anticipate any major changes to the data. There is the question of scouting which needs to be answered, but I do not yet know if that will be done with triggers or data.1

Triggers

This is where I anticipate spending most of my time. We will need triggers for changing ownership of the units from the player to the computer, keeping track of and calculating popularity and fame, ensuring the proper supply count for the player, giving upgrades that the player researches to the tributes, and assigning a victor.

Closing Remarks

At the time of writing this proposal, I am about 1-2 weeks into the design and programming of this map. I will be posting my progress as if it is recent until I catch up here with my actual work. At that point, my posts will be closely in line with my progress. I have had a lot of fun working on this map so far (which is why I'm determined to make more, and want to share my experiences on this blog), and I look forward to writing my story, sharing my difficulties and the tricks I use to overcome them, and most of all the play-testing and seeing my ideas come to life!

Saturday, May 10, 2014

Introduction - Zeroth Post!

I am a big fan of Starcraft, I have been for quite some time. That being said, I am not a very strong player, when I have time to play. I have spent the last 5 years in grad school working toward my Masters and eventually (maybe) my PhD in Physics, and that has left little time to practice the game.

Throughout this time I have dabbled in the map editor for both Starcraft: Broodwar and Starcraft 2, but I have only scratched the surface. Now, with my one year old son and new job, I have a little free time and decided I wanted to delve into the realm of map editing.

Over the years I have had many ideas for Starcraft maps. Approximately all of them are unrealized. The last week I started working on one of those ideas: a 'macro-wars' type game (in contrast to the popular micro-wars) to help establish the core mechanics of the game and practice 'battle of the green bars' style play. The target for a game like this would be the bronze through gold players looking to make it into diamond (of which I am one). Today (actually, about an hour ago) I decided I wanted to document my adventures with the editor and share some of the tricks I've picked up along the way. Mostly it will serve as a means for me to remember what I did before, and document the issues yet to resolve on maps that I'm making. I thought it might be fun to do this in a more public format, such as a blog, so that others can follow along or read up on any maps that I may successfully create.

I shall do my best to document each stage of the map making process. In the case of this map, I will need to 'recreate' some of my previous work. Once I get you all caught up all my posts will be made as the map is being developed. I will also make all my maps available once the initial tests are satisfactory. There are many things to learn before good, clean maps are generated. I hope you enjoy hearing the story of how I grow from a new editor with big ideas to a skilled craftsman!