Jump to content

Help with a script


Metatron

Recommended Posts

Background: I intended to write a creature script that, each turn, cycles through all monsters in the level (while i <= 120). For each monster, the script would check that the monster is

 

  • alive
  • hostile to the script runner
  • visible to the script runner

If those conditions are true, the script should check that the monster is in a select hemisphere determined at initialization.

 

The way I checked for this was to use xchange and ychange to calculate the difference between the x position and y position of the script runner and of the target. It is always change = origin location - monster location.

  • If a monster is to the north, ychange is positive
  • If a monster is to the west, xchange is negative
  • If a monster is to the south, ychange is negative
  • If a monster is to the east, xchange is negative

If the monster is in the correct hemisphere (north of origin, south of origin, east of origin, west of origin) then we proceed to state 3 and attack the monster, and am done for the turn. See the complete code here or just open the spoiler.

Click to reveal..

Code:
// turret.txt// Memory Cells://   Cell 0 - Where creature faces//     0 - print my number, print an error alert//	   1 - facing north//     2 - facing west//     3 - facing south//     4 = facing east//   Cell 1,2 - Stuff done flag. If both 0, nothing. Otherwise when this //     is killed, set to 1. (Example: If cell 1 is 3 and cell 2 is 5, when//     creature is killed, sets SDF(3,5) to 1.)//   Cell 3 - Dialogue node to start with if talked to. if left at 0, this//     character doesn't talk.begincreaturescript;variables;short i,target;short last_abil_time;short xorigin,yorigin;short xchange,ychange;short quadrant;body;beginstate INIT_STATE;	target = -1;	set_mobility(ME,0);	last_abil_time = get_current_tick();	if (get_memory_cell(0) == 0) {		print_named_str(ME,"does not have a set direction to face.");		print_num(my_number());		}	if (get_memory_cell(0) == 1)		set_character_facing(ME,0);	if (get_memory_cell(0) == 2)		set_character_facing(ME,2);	if (get_memory_cell(0) == 3)		set_character_facing(ME,4);	if (get_memory_cell(0) == 4)		set_character_facing(ME,6);	force_instant_terrain_redraw();break;beginstate DEAD_STATE;	// Set the appropriate stuff done flag for this character being dead	if ((get_memory_cell(1) != 0) || (get_memory_cell(2) != 0))		set_flag(get_memory_cell(1),get_memory_cell(2),1);break;beginstate START_STATE; 	i = 0;	//target = -1;	// Conjecture: if you run this state and set target equal to something, it will not progress immediately to state 3	// it will instead run this stupid state again, thereby resetting i and target. i has checks so that is 	// not a problem, but target gets reset so that in state 3, the turret ends up attacking a character of value -1		if (tick_difference(last_abil_time,get_current_tick()) >= 1) {		// not going to waste all that script time if you have already done your ability this turn		// perhaps calling this in the START_STATE will take up too much run time... this is distressing		// should stress-test BoA to see if a large number of turrets slows down the game. Meh. Burn that bridge when you come to it		i = 0;		target = -1;		xorigin = my_loc_x();		yorigin = my_loc_y();		while (i <= 120) {			// one flaw of this procedure is that if one character is in the range of two turrets, and if that character is the first character,			// he will be targeted twice. The lowest person is very unlucky			// check ALL monsters to see if they fit my criteria						if (char_ok(i) && char_attitude_to_char(ME,i) == 2 && can_see_char(i) == 1) {				//print_num(i);				print_named_str(ME,"got to the if checks.");				// just watching the script closely, and not trusting it								// so we've established that I don't like this guy, and he's at some unknown range. Now let's check if he's in my attack field				// Me, the turret, is at the center of the universe; at point (0,0);				// as you move west, x goes down				// as you move east, x goes up				// as you move north, y goes down				// as you move south, y goes up				// if the target is in the hemisphere that I want, and if he is a valid i (as calculated above with the if chain)				// then I can set target = i, set i = 121, and then go to state 3; from there, do the damage and animation and all that [censored]				// if I set i to several different values, it'll be unexpected and unexplained but eh								//1 = north, 2 = west, 3 = south, 4 = east								xchange = xorigin - char_loc_x(i);				ychange = yorigin - char_loc_y(i);								if (get_memory_cell(0) == 1 && ychange > 0) {					i = target;					set_state(3);					last_abil_time = get_current_tick();					i = 120;					print_str("North");					//set_state(3);					}				if (get_memory_cell(0) == 2 && xchange > 0) {					i = target;					set_state(3);					last_abil_time = get_current_tick();					i = 120;					print_str("West");					//set_state(3);					}				if (get_memory_cell(0) == 3 && ychange <= 0) {					i = target;					set_state(3);					last_abil_time = get_current_tick();					i = 120;					print_str("South");					//set_state(3);					}				if (get_memory_cell(0) == 4 && xchange <= 0) {					i = target;					set_state(3);					last_abil_time = get_current_tick();					i = 120;					print_str("East");					//set_state(3);					}								}			i = i + 1;			}			//i = i + 1;		// remember to set last_abil_time at the end of this, once you've actually done the attack sequence		}break;beginstate 3; // attacking	print_named_str(ME,"got to the attack state.");	if (char_ok(target))		print_str("char ok");	if (char_attitude_to_char(ME,target) == 2)		print_str("hates target");	if (can_see_char(target) == 1)		print_str("can see target");	if (char_ok(target) && char_attitude_to_char(ME,target) == 2 && can_see_char(target) == 1) {		print_named_str(ME,"has a target with the right traits");		print_num(target);		print_named_str(ME,"fires at an enemy.");		put_straight_zap(my_loc_x(),my_loc_y(),char_loc_x(target),char_loc_y(target),0);		change_char_health(target,-1 * get_ran(2,1,get_level(my_number())));		print_num(target);		run_animation_sound(104);		}		if (target < 0 || char_ok(target) == 0 || char_attitude_to_char(ME,target) != 2 || can_see_char(target) == 0) {		print_named_str(ME,"had an invalid target");		//set_state(START_STATE);		}break;beginstate TALKING_STATE;	if (get_memory_cell(3) == 0) {		print_str("Talking: Turrets cannot talk. You idiot.");		end();		}	begin_talk_mode(get_memory_cell(3));break;

 

This code does not work. It seems to think that target = -1. When a party member is positioned so that an attack should proceed, the script prints the following messages:

  • Sentry turret got to the attack state
  • hates target
  • can see target
  • Sentry turret had an invalid target
  • Notice that what the script does NOT say is that, while in state 3, target is a character that is alive and okay.

 

Problems:

Does anyone have insight into why the target gets set, but is an invalid character?

 

Also, I couldn't get the call dist_to_char(i) to work properly; when I tried to add this check to my if () conditionals, the game told me that I had a unary error, I believe. Not a big problem, but it would be good to know why I was using it incorrectly.

 

Finally, almost all of a monster's attacks seem to only be prompted by a do_attack call. All except one... When a character moves away from a monster and the two are hostile to each other, the stationary monster always gets an attack of opportunity, regardless of what the script has to say about this. If I have a character who move away from a turret, the turret can attack my character. This is of course silly because a stationary robot turret should not get an attack of opportunity, but there's little to be done about it except to either set the turret's strength to 0 or set it to do burning damage. Unless someone has any idea what else to do about this.

Link to comment
Share on other sites

Should each of those 'i = target;' lines be 'target = i;'? Because i'm fairly sure that target only gets assigned to in the INIT_STATE.

 

Quote:
Also, I couldn't get the call dist_to_char(i) to work properly

Could you show how you tired to use it? As far as I recall that call should work, and in a pretty straightforward manner.

 

Quote:
Finally, almost all of a monster's attacks seem to only be prompted by a do_attack call. All except one... When a character moves away from a monster and the two are hostile to each other, the stationary monster always gets an attack of opportunity, regardless of what the script has to say about this. If I have a character who move away from a turret, the turret can attack my character. This is of course silly because a stationary robot turret should not get an attack of opportunity, but there's little to be done about it except to either set the turret's strength to 0 or set it to do burning damage. Unless someone has any idea what else to do about this.

There is, sadly, no way known, I think, to turn this off. The best you can do is change the creature so that it will always miss or do no damage. This is why the tables in Echoes: Renegade will, in some way that is unclear upon reflection, try to strike unwary enemies during a certain fight.

Link to comment
Share on other sites

Originally Posted By: Niemand
Should each of those 'i = target;' lines be 'target = i;'? Because i'm fairly sure that target only gets assigned to in the INIT_STATE.

... D'oh.
Quote:

Could you show how you tired to use it? As far as I recall that call should work, and in a pretty straightforward manner.

Code:
if (char_ok(i) && char_attitude_to_char(ME,i) == 2 && can_see_char(i) == 1 && dist_to_char(i) <= 8) {
gives an error, saying "turret Error: Function call error (unary) in line 72." where line 72 is the line where I just added && "dist_to_char(i) <= 8)" to. The line if
Code:
(char_ok(i) && char_attitude_to_char(ME,i) == 2 && can_see_char(i) == 1) {
works.

Quote:

There is, sadly, no way known, I think, to turn this off. The best you can do is change the creature so that it will always miss or do no damage. This is why the tables in Echoes: Renegade will, in some way that is unclear upon reflection, try to strike unwary enemies during a certain fight.

I see. Oh well; it's just nice to actually know why this problem exists.
Link to comment
Share on other sites

Okay, there was another error, but I sorted that out reasonably well. I must have spent at least an two hours trying to figure out why my target was -1, and it was as simple as that... Thanks Niemand!

 

Some information which I have discovered and which I don't think are readily available:

1) Variables can be negative and store their negative value. However, print_num(variable) will not print a number. It will print a blank space.

2) A creature will run through the state that it was last in, three more times. That is, its final state will be called four times.

3) if (dist_to_char(i) <= 8) and while (i < 3) are both interesting. Or I spend too much time on instant messenger programs.

4) I would like to reaffirm this, although it's probably known: if you use set_state(state_number), anything after this call in this state will not be read.

Link to comment
Share on other sites

4), start in First State, a set state continue takes you to the Second State. Anything in First State after the Set state continue call won't be read. Here you would need some way to return to the First state, a set state continue in the Second State. Then you would need some way to avoid triggering the set state continue. You can use algebraic variables for the set state continue call.

Link to comment
Share on other sites

If all else fails, put more parenthesises in your conditions.

i.e: if ((foo() == 1) && (lol < 6)){

Might help, might not.

 

Perhaps there is a way to avoid attacks of opportunity, but it would be a messy, roundabout way. I only have the barest concept in mind but it would work like this:

 

-Have terrain scripts one space away from the turret. (Good it's stationary.)

-When they are walked in, first block entrance.

-Check to see if they are trying to enter from the turret's side, i.e. they try to move away from the turret.

-If yes, make the turret friendly.

-Unblock them and move them where they wanted to be. Reduce ap, if needed.

-Make the turret hostile again.

 

That is, if you are willing to bother. Perhaps you could use relocate instead of playing with the turret's attitude.

Link to comment
Share on other sites

Originally Posted By: Metatron
1) Variables can be negative and store their negative value. However, print_num(variable) will not print a number. It will print a blank space.
You should probably be able to display a number with the string buffering calls, though. I suspect they are merely a wrapper around C's sprintf function.

Originally Posted By: Metatron
2) A creature will run through the state that it was last in, three more times. That is, its final state will be called four times.
Did you call the end_combat_turn() function? (I think that's what it's called.) If I'm not mistaken, the creature will loop through its state until it runs out of action points, though there is probably also a limit on the number of times it will run through (maybe four, as you've found).

Originally Posted By: Metatron
3) if (dist_to_char(i) <= 8) and while (i < 3) are both interesting. Or I spend too much time on instant messenger programs.
Um, what?

Originally Posted By: Metatron
4) I would like to reaffirm this, although it's probably known: if you use set_state(state_number), anything after this call in this state will not be read.
Yes, set_state stops the script from running and changes the state to be called each turn.
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...