Sunday, September 9, 2007

[log] design of the map language

The language for the map files is not fully designed yet.

Using Python to describe maps is not really an option, because the eval function and the exec statement, used to interpret easily Python code, are dangerous when applied to an untrusted source. There will be custom maps, and they should not be dangerous to use.

If possible, the language should be safe, powerful enough, easy to learn and concise.

The first examples I designed are very concise (even if I didn't use abbreviations in keywords). They are easy to learn if you start from the examples and don't go too far from them. But they may not be powerful enough, and, worse, become complex if additional features are needed (for example, testing more than one condition in a trigger, or doing more than one action in a trigger; use parenthesis?).

To be powerful enough, the language should allow, sooner or later, at least the following possibilities (annotated excerpt from a suggestion in the audiogames.net forum):
A few basic scenario types you might want to consider:

1. Survive for thirty minutes till reinforcements arrive (have waves of attackers at, say, four minutes, nine minutes, fifteen minutes, twenty-two minutes, and then a huge one at twenty-eight minutes...the kind that's so big that you're going to, as a player, simply hunker down and take it and hope you're not dead by the time thirty minutes hits).

Comment:

The triggers to send the waves of attackers are the same than for solo map 2 or 3.

A trigger must be added to activate victory after 30 minutes. No problem:
trigger player1 timer 30 victory

Another trigger should send messages like "5 minutes left". Maybe we only need some triggers like (not perfect but maybe enough):
trigger player1 timer 25 play_sound 5_minutes_left.mp3

2. Kill such-and-such a special unit (sa the enemy has a high priest that, for some reason or other in your storyline, you're being ordered to kill).

Comment:

Not sure yet. Maybe this trigger:
trigger computer 1 has_not special_unit1 defeat

Instead of has_not, something with a not operator would be more powerful, for example:
trigger computer 1 (not (has special_unit1)) defeat
But I don't like this example. A more Python-like language would be better then. Or a LISP-like one, but it may not be easy to learn and use for many people, even if it may be easier to implement. So these complications should be avoided if possible.

The special unit will have to be defined. I must add a command named "special_unit" or "custom_unit" for example.

3. Capture an enemy building (a unique building, and have it so that your warriors don't automatically go and destroy it).

Comment:

A new style of unit will be added: the neutral units that can be saved/captured and will be part of your units. Then the following trigger should be enough:
trigger player 1 has special_unit1 victory

4. Establish a safe trade route across a map. To explain: let's say you've got a base at a1 and a2 and b1. There's a friendly outpost down at d7, e7, d6 and e6. The only available path between those bases is blocked by little camps of enemy troops that it periodically re-establishes if you wait too long. You'd have to force your way through them, kill them, then set up a patrol between the two bases perhaps.

Comment: This example is not that easy, or maybe... Maybe a timer to give time to prepare before the convoy starts, then a series of triggers to make the convoy slowly move to destination. A trigger to activate defeat if it is destroyed. A trigger to activate victory: the condition would be a timer or a test of the square of the convoy. The convoy would be neutral for the player, vulnerable to the computer.

5. A simple "destroy the enemy" scenario, with a catch. Give the player one unique unit, or one group of them, and add the stipulation that all such units must survive. If you want to be nasty, make the units great at attacking so the player is perhaps goaded to use them.

Comment: Nothing more is needed.

6. Ensure that all resources are stopped from reaching the enemy encampment. This one would be hard, and probably for a later scenario, but the idea is this: the enemy base itself is fairly passive, but rather large and extremely well-fortified. You yourself are given fair resources and a bit of room to play with, but perhaps your tech tree is limited or your food is. Either way, you're slightly crippled, so a full-out assault on the enemy base is basically suicide. What yo u'd have to do, therefore, is to find all the unexplored mines and woods on the map and ensure that the enemy did not control them. Essentially, the match would end in success if the enemy had its base, you had yours, and all the resources were depleted without you dead; it would end in failure if you were killed/rendered helpless in the attempt.

Comment:

Maybe here we need more than one conditions, maybe not (but there might be to many specialized functions). For example:
trigger player1 no_resources_in a1 f3 d5 victory

7.Another scenario idea, and there's a lot of potential for this one, you can make it easy, moderate, or murderous, depending on your mood, and you could probably do it with the current level of AI and programming that RTS already has:
You are sent down to an area where a battle has taken place and your troops have been decimated and scattered. The enemy did not totally destroy either the base or the troops that manned it, but will regroup eventually and scour the area for all threats in due time. Your mission, in the meantime, is to take a couple of troops (maybe two footmen, two archers and a peasant, or two peasants and two knights) down to the field of battle and sniff out what's left. On different squares of the map, you'll find abandoned buildings that may or may not be damaged, and a few remaining troops (maybe a total of three peasants, four footmen and a couple of archers or something...perhaps most of them will be wounded, too). Your goal would be to muster as much of this stuff as you can/as much as you wish (perhaps make the finding of all things a must for the completion of the mission), then build a base with what you have and wipe out the enemy presence. In easier scenarios using this method, the base you are already given (damaged though it might be) might be fairly advanced, requiring little upgrade, and you might have a fair bit of resources on hand, so the real challenge is just finding everything; in harder scenarios, the base itself might be minimal. The aggressiveness/placement of the enemy would depend upon the difficulty of the scenario too. In an easier scenario, the enemy would be fairly quiet. They'd attack you if you got too close to them in your explorations, and would definitely come forth to sniff things out from time to time, but wouldn't launch full-out assaults...they're hutring from the battle, too. On harder scenarios, it would be nothing at all to have small enemy placementsscattered on the mapawaiting the chance to spring ambushes should you wander across them, and the AI would attack you quite mercilessly once they realized where the rest of your base was and that the threat was once again being established.

Comment: Nothing more is needed for this example.
To this list I would add (if it isn't already implied by the above list):
  • for tutorials, triggers to wait for a key to be pressed;
  • play sound files (for cinematic scenes or instructions, for example);
The next step will be to refine these requirements to deduce the minimal list of triggers and features the language should allow.

Another possibility of language is a verbose language that doesn't need parenthesis. For example:
trigger for player1 if has 2 farm 1 barracks then victory
I'm not sure it would be a good idea. The "then" keyword might be useful though.

1 comment:

Anonymous said...

Quote : Using Python to describe maps is not really an option, because the eval function and the exec statement, used to interpret easily Python code, are dangerous
when applied to an untrusted source. There will be custom maps, and they should not be dangerous to use.

In general, the function eval is not a solution... in python, in javascript, in php, or whatever else. There are always security holes with eval.
Now I don't know python very well (only the very basics).


Quote : If possible, the language should be safe, powerful enough, easy to learn and concise.

All what a good language must have.

I think that the best thing is to define a set of keywords/variables/functions which we can access.

Statement suggestions :


if [player] has {not|more than|less than} {number} [unit name] then [action]

if [player] has {not|less than|more than} {number} [unit name] in [location] then [action]

if [number] {seconds|minutes|hours} elapsed then [action]

if [number] {seconds|minutes|hours} elapsed since [condition] then [action]

if [player] press [key combination] then [action]

Someting like that for trigger conditions would be
fine. Don't forget to add keywords "and" and "or" to combine 2 or more conditions in the same trigger

For the actions, we need to allow :
- Give orders to computer troops.
Maybe something like these :
2 footmen go to d4
3 footmen and 1 archer attack c3

- Play sounds
- Declare victory or defeat
- Wait for the user to press a key, and store the result for later use... for tutorials or to have maybe Y/N questions ?

For stories, maybe it would be interesting to add :
- A building very long and very expensive which creates no units, but which is important to be the king... something like colosseum. The goal could be destroy the enemy one, or create your own one to win.
- A special unit like artefact, which you have to capture without destroying and/or keep safe to win


P.S. Notation
{...} = optionnal
[...] = required
A|B = A or B


Good luck in creating map language. It's a very very hard challenge but it gives a lot of new game possibilities.