Jump to content

Scripting Questions for Devs


Oudy

Recommended Posts

Got a couple of more questions.

1. If a unit is under a move command and it is fired upon will it continue to move or will it go into Defend mode? I ask this because in the script "Move Horche" and "Move Zonder" in the Paratroopers mission tests to see if it is under the command Defend. If this is the case, what are the conditions that will make a moving unit change its current command?

2. When is it appropriate to use the "DestroyTrigger" or "DestroyTriggerInstance" command? Should all instances be destroyed once run or not? If you use "DestroyTrigger" can you call another trigger with the same name later?

Thanks

Oudy

Link to comment
Share on other sites

Although we will be waiting for the Devs answer on this one I'd like to add a few observations.

1. I find it specially annoying to see troops that were given the move command just keep on walking even when fired upon! It happens a lot.

So it kind of surprises me that you ask if they change to Defend if fired upon.

I understand that you found a script that checks for the command state and that's why you ask. I'm also curious to the hear the answer.

2. As I understand and could observe in other "official" missions they use the destroy trigger only for triggers that are loops and that are not needed anymore. I guess is to save processing cycles.

I use it for instance in submissions fail and win triggers. The mission has not finished yet but the fail (or win) trigger will be looping nonstop uselessly since the win requirement has already been met.

In the case of instances I'm not so sure. Can you call several instances of the same trigger and have them all running at the same time? Probably need to destroy it before calling another instance..!?

Since you create all triggers in the mission editor they are there at the same time when you save the mission so I don't know how they could have the same name.

Am I right in this reasoning?

--

Link to comment
Share on other sites

Boy, I gotta twell ya', mission building is sounding scarier and scarier.

Variables, loops, triggers, functions, I feel like I am back in a programming class back in college, not playing a game. Whatever happened to simply building a map, building an OOB, doing a setup, and playing it. When did this become a programming exercise?

Link to comment
Share on other sites

Thewood

The good and bad thing is that there is tremendous flexibility. There are two types of AI, the hardcoded AI and then the scripted AI. You can write a mission with virtually no scripting, but the enemy troops will will move to wherever you tell them and then stay there. They won't adapt to changing battlefield situations so it would be very easy to "game" the game. With scripting you can make the enemy troops deal with the changing flow of battle in a little more "human" way.

Oudy

Link to comment
Share on other sites

Webwing:

In the case of instances I'm not so sure. Can you call several instances of the same trigger and have them all running at the same time? Probably need to destroy it before calling another instance..!?

I have not personally used instantiated triggers yet, but given the meaning of instancing in coding I can help there.

If you weren't allowed to run multiple instances of a trigger, what would be the difference from asynch running em?

You fire up each instance and differentiate it's behaviour by providing it with it's own params (now there wouldn't be much point all instances doing the same thing).

For example, think of an elementary trigger that refreshes the current command of the unit in one of your local variables.

You'd make the trigger as

------

Param IN: @unitID

Param OUT: @current_command

Delay(5000)

@current_command = GetCurrentCommand("UNIT",@unitID)

RETURNPARAMS

------

So, you fire up an instance for each unit you want to have this functionality.

This is excellent when you want to have something like a table that keeps track of multiple things (let's say the table represents a grid of the map and the values the hostility of each grid).

You can really go far with instances.

Destroying instances is VERY important, as it is destroying objects in coding. You cannot have instances running around doing stuff when their job is done (i.e. the unit they're responsible for is dead).

Not doing so will get you angry gamers screaming "memory leak!" after playing the game for a few hours straight ;)

Bringing us on the previous subject, destroying normal triggers.

I can't imagine a well-designed situation that would need such a function, but it doesn't hurt to have it there as a last resort hack.

Hell, even GOTO is in the language, but if anyone uses it, he needs to be shot (by a 43/41 at point blank range)

Proper deaths of triggers should be the Halt command.

Oh, and Webwing. I haven't understood your background in coding man. If you're well into all these stuff just say so, from the syntax of your question I thought you didn't know of instancing in general.

[ May 18, 2007, 08:31 PM: Message edited by: nonickch ]

Link to comment
Share on other sites

...Note to self...

Take out all GOTO statements...

Or else... ;)

nonickch, what I would love to see happen is for people to write a series of triggers that handle some of the basic operations that will be used in most missions. I'm thinking about triggers to move a unit along a path of an array, or that check which units are visible, or randomize the time before reinforcements arrive. I've been collecting samples from the missions done by 1C and will post them when I can, but I suspect that many of these can be improved upon. (because they use GOTOs, hehe).

I've had some experience programming, but it is not my profession, and I would love to see people who write code professionally help to write some code that could be used by all mission builders.

Oudy

Link to comment
Share on other sites

@nonickch,

Thanks for the thorough explanation!

Originally posted by nonickch:

Oh, and Webwing. I haven't understood your background in coding man. If you're well into all these stuff just say so, from the syntax of your question I thought you didn't know of instancing in general.

You haven't understood my background cause I don't have one!!! :D

I'm an illustrator and graphic designer actually.

I read a few tutorials and tried to teach myself how to code in Java and then PHP and MySQL for a site I was designing. It came in handy when I faced some mission editors that used code later on!

So no formal background here! It's a challenge and I enjoy that.

Originally posted by nonickch:

Hell, even GOTO is in the language, but if anyone uses it, he needs to be shot (by a 43/41 at point blank range)

This language doesn't have FOR or WHILE loops so if you don't use LABEL and GOTO how can you do a loop?

--

Link to comment
Share on other sites

GOTO is considered the bane of all that is coding.

Readability and maintenance of the code becomes miserable with it.

In a big chunks of code, bugs will start creeping up on you with extensive use.

Admittedly Webwing has a point here, the lack of FOR/WHILE loops is crippling.

There are 1-2 ways that popped into my mind to sensibly go around that without breaking proper coding.

1) Recursion, the way AI languages go about solving this problem.

http://en.wikipedia.org/wiki/Recursion (follow the link for recursion in computer science)

It is admittedly expensive, especially if the firing of a trigger ("function-call overhead" in the wiki article) is a resource-costly thing to do (I have no idea on the cost of anything, will have to run benchmarks to figure it out)

2) oh god damn, I forgot it. Lemme get high, if I get high I'll remember.

... funky town ...

Ooh, I remembered. Exploit the inherent looping going on with triggers with a "while trigger" specifically coded for each case.

For example, simple iteration:

--------

PARAM IN @counter

PARAM IN @limit

IF ( @counter >= @limit) THEN

Halt

ENDIF

// Here lies the loop code

ADD ( @counter, 1 )

---------

A generalized while trigger would be possible if we could execute strings (like many other scripting languages can do). Pass a string parameter in representing the loop code.

Unfortunatelly, I don't see how we could do this.

Anyway, and now for some general ranting.

Casting. Omg, there is NO typecasting.

I was making a split_group trigger with an int representing how many units to move.

Compiler kept slapping when I passed a var where it expected an int (i.e. CreateGroupByRect).

Temporarily made a series of IF's for 1-4, but it can also be solved with recursions.

It's the type of shortcomings in the language which we will have to pay with coding sweat and endless CPU cycles.

Don't get me started on string operations...

Oudy: I'm slowly starting to write a series of support triggers that can provide some sensible level of abstraction over the currently elementary commands available.

I started with some group manipulation ones like splitting groups and fixing the hierarchy of groupings (a group can be member of multiple groups, usefull, but "ouch").

Moving units from one group to another etc...

Even this level of abstraction is quite high, I'll probably have to write quite a few supporting trigs to be able to run this kind of operations.

In other words: HELP!

I'll post some bugly snippets of code along with my rants/problems later on.

My current burning problem: Anyone found a way to get the unit ID's from a specific group?

[ May 18, 2007, 11:52 PM: Message edited by: nonickch ]

Link to comment
Share on other sites

my hair are falling off.

Just spent another 3 hours to find a way to crew an empty artillery.

You see, in staticland it's all ok. If you know the artillery unitID you can call

RunCommand ( GROUP , @new_group_ID , IN_CREW , UNIT , <artillery_ID> )

But if you're from a general-script POV, you have to locate the art piece yourself.

Easy enough, you can search the entire map for an empty piece of art BUT you can ONLY assign/know a groupnumber (via CreateGroupByRect with UnitNumber=1)

Here's the hairy part: RunCommand will roll over and die if you try it with IN_CREW and GROUP+GROUP_ID like:

RunCommand ( GROUP , @new_group_ID , IN_CREW , GROUP , @__temp_artillery_group )

Doc has the GROUP option there, but it's in red letters (as in: "I'll suck the life out of you if you try me"?)

And ofc there is no way possible to either get unit id's (or even create new unit ID's, tried CreateGroupByRect with UNIT as 1st param).

This one has effectively halted all my coding process. It is quite essential for most things I'm planning on doing.

Can anyone help? Moon, can you forward this to someone who knows?

Link to comment
Share on other sites

Nonickch

I don't believe there is a way with the limited number of commands we have available to check for a unit's ID within a group. The only way around this that I can think of is to set up a whole bunch of global variables for all of the units you want to track. For example, Set @@GunCrew_01 = [unitID]. This is unwieldy and I don't know what the impact on performance would be of having so many defined Global Variables.

One of the big problems for me is how do identify which units are visible. We really need a command like GetNUnits but called GetVUnits (for Get Visible Units). Right now you have to use the UnitsIsVisible command then loop through every unit to find which ones are visible. And that is a problem because there is no easy way to loop through all of the units or groups in your army, without defining them all as Global Variables. But, I may be missing some easier way to do it.

But, being able to get the unitIDs from within groups would be very nice.

Oudy

Link to comment
Share on other sites

Yes, storing the unitID's is one of the two possible ways that crossed my mind, but they are both tottaly inappropriate for my scope.

The other one is making any triggers that require unitID's to run instantiated and be responsible for a single unit (therefore the unitID can be immediately passed as param).

But, those would be an unacceptable workaround for a basic abstractions and a basic commands package.

First it will make code maintenance a nightmare (and hence severely limit the possible size of the project) and ofc will place an extraordinary load upon anyone that might try to use the package.

Such packages only make sense if there is a reasonable setup time and relative ease of use, and these workarounds would make a decent-size package tougher to learn than the scripting language itself.

Imagine the hell of having to input triggercode for each unit you place on the map.

Only up to 500 for each map... and that's just for enabling the package to handle units.

Not mine or anyones happy place :(

Oh, and a 43/41 for anyone making use of global vars too tongue.gif

But if the state of the language is so miserable (or to be exact, the language's basic commands), I really don't think goto's and globals will make it much worse.

EDIT:

On a coding tip here.

Some reasons for never using global vars are:

1) Maintainability. So if you choose to change the name of that global var, you have to go all over the code again

2) Don't even think on reading from a global on a threaded enviroment like this (many triggers running async). Two consecutive reads from the same global may give you different results because another trigger kicked in between the two calls and decided it don't like the value no more and changed it. This type of bug is arguably the toughest one to detect (and correct), mainly because it appears randomly (based on when the CPU decides to temporarily freeze one trigger in favor of another). A formalized approach to avoiding such problems are semaphores (try wikipedia). Something that may be coded in a package.

3) Testing. You have to compartmentalize code blocks in order to test them properly. Globals make your code randomly dependent on other parts of the code. Not good.

4) Reusability. You just can't reuse code snippets that use globals because the globals may not be there in your new program.

What to do? pass variables. Lots of em.

Propagate the information that would be stored in the global through parameters. Pass em again, and again, and again as deep your trigger-calling tree grows.

A var that was passed between 5 triggers to reach it's final resting place is a happy var ;)

If you end up passing endless vars between triggers, you did something wrong. Rethink the structure of the triggers.

[ May 19, 2007, 10:10 AM: Message edited by: nonickch ]

Link to comment
Share on other sites

Question to one of the 1C devs. Is there any possibility of getting more scripting commands added? In particular it would be nice to be able to:

1. Get the number of visible units.

2. Get a way to programatically loop through your forces.

3. It would be nice to have a FOR NEXT command.

4. It would be nice to be able to determine unit IDs from within groups.

5. It would really be nice to be able to limber and unlimber artillery via code.

Anyway, just wondering.

Oudy

Link to comment
Share on other sites

×
×
  • Create New...