Massassi Forums Logo

This is the static archive of the Massassi Forums. The forums are closed indefinitely. Thanks for all the memories!

You can also download Super Old Archived Message Boards from when Massassi first started.

"View" counts are as of the day the forums were archived, and will no longer increase.

ForumsCog Forum → killed messages, actor cogs
killed messages, actor cogs
2004-09-16, 8:35 AM #1
I am stuck trying to write a cog. The first part is fine - the touched message creates three creatures that you go hunting etc.

This is a 'mission', and the idea is that when you have killed all the creatures, the objective will be completed. But I can't write a piece of code to detect if all the creatures have been killed. I put a section in the killed message of their actor cog - but the objective was completed after only one creature died. Also, I've tried reading the health of the creatures with GetHealthThing (), and it often comes back as -1. Can anyone help me?

Code:
symbols

thing		object
thing		bug0
thing		bug1
thing		bug2

template	bugType=darosian_mite
sound		wav0
int 		X=0 local
int		pandora=0
int		bugsaGoGo	local

int	bugsLife0 local
int	bugsLife1 local
int	bugsLife2 local


model       openBox=crtz.3do

message 	touched


end

code

startup:
Sleep(0.5);
bugsaGoGo = 0;
return;

touched:
 player = GetSenderID();


   if (GetSenderID() == player)

	{
	
	if(pandora == bugsaGoGo)
	{
	for (X=0;X<3;X=X+1) CreateThing(bugType, bug0[X]);
	for (X=0;X<3;X=X+1) SetThingHealth(bug0[X], 10);
	SetThingModel(object, openBox); 
	Print("SITH OFFICER: Typical!  You've let the Darosian hunting mites out!");
	Print ("SITH OFFICER: Maybe you'd better find a way to get rid of them, seeing as its your fault.");
	Print ("SITH OFFICER: Or would you rather spend a night in the detention wing?");
	PlaySoundThing(wav0, object, 1, -1, -1, 0);
	questPlayer = GetLocalPlayerThing();
	SetGoalFlags(questPlayer, 4, 1);
	bugsAgogo = bugsaGoGo + 1;
	
	}}

	return;
end


And here is my attempt at a killed message to see if all three creatures are dead:

Code:
killed:

	for (X=0;X<3;X=X+1)	bug0[X] = GetSenderID();
	for (X=0;X<3;X=X+1)	bugsLife0[X] = GetThingHealth();

		if (GetSenderID() == bug0)
		call bug0died;
		else
		if (GetSenderID() == bug1)
		call bug1died;
		else
		if (GetSenderID() == bug2)
		call bug2died;
		else
		return;

bug0died:
	if (bugsLife1 >0 && bugsLife2 >0)
	{
	Print("Bug 0 is dead, but you still gotta find some bugs...");	
	return;
	}
	else
		{
		questPlayer = GetLocalPlayerThing();
		SetGoalFlags(questplayer, 4, 2);
		PlaySoundThing(wav1, questplayer, 1, -1, -1, 0);
		Print("You killed all the little critters ... shame on you!");
		return;
		}

bug1died:
	if (bugsLife0 >0 && bugsLife2 >0)
	{
	Print("Bug 1 is dead, but you still gotta find some bugs...");
	return;
	}
	else
		{
		questPlayer = GetLocalPlayerThing();
		SetGoalFlags(questplayer, 4, 2);
		PlaySoundThing(wav1, questplayer, 1, -1, -1, 0);
		Print("You killed all the little critters ... shame on you!");
		return;
		}
   return;

bug2died:
	if (bugsLife0 >0 && bugsLife1 >0)
	{
	Print("Bug 2 is dead, but you still gotta find some bugs...");	
	return;
	}
	else
		{
		questPlayer = GetLocalPlayerThing();
		SetGoalFlags(questplayer, 4, 2);
		PlaySoundThing(wav1, questplayer, 1, -1, -1, 0);
		Print("You killed all the little critters ... shame on you!");
		return;
		}

end
2004-09-16, 2:50 PM #2
You need to use a set of symbols for the actual bugs created, then reference those symbols properly.

Insert into the symbols section:
int bugCreated local
int bugCreated1 local
int bugCreated2 local

Change this line:
for (X=0;X<3;X=X+1) CreateThing(bugType, bug0[X]);

to:
for (X=0;X<3;X=X+1) bugCreated[X] = CreateThing(bugType, bug0[X]);

Delete this line:
for (X=0;X<3;X=X+1) bug0[X] = GetSenderID();

Change these lines:
if (GetSenderID() == bug0)
if (GetSenderID() == bug1)
if (GetSenderID() == bug2)

to:
if (GetSenderID() == createdBug[0])
if (GetSenderID() == createdBug[1])
if (GetSenderID() == createdBug[2])

There might be more errors, but that should move things along.

:)
2004-09-17, 1:03 AM #3
Thanks ZeqMacaw, I'm going to add your code right now. I really appreciate your help. It's really hard for someone like me to learn COG without a programming background, but I reckon my games will be more interesting to make if I try to learn.

So, do I understand correctly: GetSenderID() looks for an Int value given by a Thing, and it doesn't look for the Thing itself. And I had confused the programme by using the Thing name 'bug0' etc, and it was looking for an Int variable with that same name?
2004-09-17, 2:29 AM #4
I tried out the cogs with the new code. When you kill just one of the creatures, it still automatically completes the objective, and lists the health of all three as -1. Here is the revised first cog:

Code:
# bughunt_mission_cog
#
# It replaces a crate 3do with a model of an open crate
# and creates bug creatures for you to hunt down.
# Want more creatures? Set a number for 'pandora'.  This will be a multiplier
# every time you touch the crate. 0 is the default.
#
# rob_whatman
#
# This COG is not supported by Lucasarts.

symbols

thing		object
thing		bug0
thing		bug1
thing		bug2

template	bugType=darosian_mite
sound		wav0
int 		X=0 local
int		pandora=0
int		bugsaGoGo	local

int	bugsLife0 local
int	bugsLife1 local
int	bugsLife2 local

int            bugCreated local
int            bugCreated1 local
int            bugCreated2 local

model       openBox=crtz.3do

message 	touched


end

code

startup:
Sleep(0.5);
bugsaGoGo = 0;
return;

touched:
 player = GetSenderID();


   if (GetSenderID() == player)

	{
	
	if(pandora == bugsaGoGo)
	{
	for (X=0;X<3;X=X+1) bugCreated[X] = CreateThing(bugType, bug0[X]);
	for (X=0;X<3;X=X+1) SetThingHealth(bug0[X], 10);
	SetThingModel(object, openBox); 
	Print("SITH OFFICER: Typical!  You've let the Darosian hunting mites out!");
	Print ("SITH OFFICER: Maybe you'd better find a way to get rid of them, seeing as its your fault.");
	Print ("SITH OFFICER: Or would you rather spend a night in the detention wing?");
	PlaySoundThing(wav0, object, 1, -1, -1, 0);
	questPlayer = GetLocalPlayerThing();
	SetGoalFlags(questPlayer, 4, 1);
	bugsAgogo = bugsaGoGo + 1;
	
	}}

	return;

end


And here is the actor cog (its just the mousebot cog modified):

Code:
# actor_darosianmite.cog
#
# ACTOR Script - Standard Mousebot adapted in the killed message
#
# [CR]

symbols

message		killed
message		skill
message		damaged
message		created
message		timer

template		powerup=	    	local
thing			newThing	             	local
flex			damageAmount		    	local
flex			damageType		       	local
flex			totalDamage		       	local
thing			player                	local
thing			killer                	local

int		bugsLife0	local
int		bugsLife1	local
int		bugsLife2	local

int		bugCreated	local
int		bugCreated1	local
int		bugCreated2	local

sound		wav1

end

# ========================================================================================

code

created:
	// Delay the created message, so that the player definitely exists.
	SetTimerEx(1.0, 1, 0.0, 0.0);
	return;

killed:
	player = GetLocalPlayerThing();
	killer = GetSourceRef();

   	newThing = CreateThing(powerup, GetSenderRef());
   	SetLifeleft(newThing, 200.0);

   // Player killed a lovely critter!
	if (player == killer)
   		{
      		ChangeInv( player, 72, 0.5 );
   		}

	// Now, we check to see if the other critters are also dead yet... you bully!


for (X=0;X<3;X=X+1)	bugsLife0[X] = GetThingHealth(bugCreated[X]);
for (X=0;X<3;X=X+1)	PrintInt(bugsLife0[X]);

		if (GetSenderID() == bugCreated[0])
		call bug0died;
		else
		if (GetSenderID() == bugCreated[1])
		call bug1died;
		else
		if (GetSenderID() == bugCreated[2])
		call bug2died;
		else
		return;

bug0died:
	if (bugsLife1 >0 && bugsLife2 >0)
	{
	Print("Bug 0 is dead, but you still gotta find some bugs...");
	PrintInt(bugsLife1);
	PrintInt(bugsLife2);	
	return;
	}
	else
		{
		questPlayer = GetLocalPlayerThing();
		SetGoalFlags(questplayer, 4, 2);
		PlaySoundThing(wav1, questplayer, 1, -1, -1, 0);
		Print("You killed all the little critters ... shame on you!");
		return;
		}

bug1died:
	if (bugsLife0 >0 && bugsLife2 >0)
	{
	Print("Bug 1 is dead, but you still gotta find some bugs...");
	PrintInt(bugsLife0);
	PrintInt(bugsLife2);	
	return;
	}
	else
		{
		questPlayer = GetLocalPlayerThing();
		SetGoalFlags(questplayer, 4, 2);
		PlaySoundThing(wav1, questplayer, 1, -1, -1, 0);
		Print("You killed all the little critters ... shame on you!");
		return;
		}
   return;

bug2died:
	if (bugsLife0 >0 && bugsLife1 >0)
	{
	Print("Bug 2 is dead, but you still gotta find some bugs...");	
	PrintInt(bugsLife1);
	PrintInt(bugsLife0);		
	return;
	}
	else
		{
		questPlayer = GetLocalPlayerThing();
		SetGoalFlags(questplayer, 4, 2);
		PlaySoundThing(wav1, questplayer, 1, -1, -1, 0);
		Print("You killed all the little critters ... shame on you!");
		return;
		}


	
   return;


# ........................................................................................

skill:
	bin = GetParam(0);
	if (bin == 24)			// Force Pull
	{
		ReturnEx(GetSenderRef());
		return;
	}
	ReturnEx(-1);
	return;


# ........................................................................................

damaged:
   damageAmount = GetParam(0);
	damageType = GetParam(1);

	totalDamage = damageAmount;

	if (BitTest(damageType, 0x01)) totalDamage = 4;

   ReturnEx(totalDamage);
   return;
	
# ........................................................................................

timer:
	player = GetLocalPlayerThing();
   ChangeInv( player, 73, 0.5 );
	return;

end


What else could I try to make it function? I wondered about how the actor cog knows what 'bugCreated' is, as it is defined in a different cog. Is that a problem?
2004-09-17, 5:52 AM #5
Call me daft here, but as an alternative suggestion: wouldn't it more sensible to place the bug count code in a new separate cog and leave the actor cog for the specified things (in this case "bugs") well alone?

The actor cogs are class cogs which means that they control generic messages for every actor of that type that is created. Personally, placing the bug count code in a separate cog (maybe even the original cog?) would seem a more logical implementation, given the MVC (Model-View-Controller) relationship they share.

Just my tuppence worth :). Hope this information helps :D

-Jackpot

PS: Apologies for the programming terminology :o...
"lucky_jackpot is the smily god..." -gothicX
"Life is mostly froth and bubble, but two things stand in stone,
Kindness in another's trouble, courage in your own"
- "Ye Wearie Wayfarer"
|| AI Builder: compatible with both JK & MotS || My website ||
2004-09-17, 5:54 AM #6
I think you want to be using GetSenderRef() instead of GetSenderId(). Timers and sendtriggers use a senderID but most messages only have GetSenderRef() and GetSourceRef()...

...and some other params specific to the message type (GetParam(X) for instance...the damaged section of kyle cog makes use of this to get the type of damage)

Regardless, I think GetSenderId() is not used in the killed message and would consistently return -1 when used there....or it would grab some random thing whose health value is most like not set. I know it would return the wrong value, whatever it returns. GetSenderRef() used in a killed message will return whatever was just killed, which is what I think you were really after there.

Please check out the datamaster for a detailed explaination on the sender/source refs of all messages. Its really a great help.
-El Scorcho

"Its dodgeball time!" -Stormy Waters
2004-09-17, 5:59 AM #7
Oh, and yes after looking at what we're actually trying to accomplish here...LJ is right. You'd really be better off handling the bugcount stuff in your original cog, and simply having killed SendTrigger to that cog to inform it of their death.

class cogs are reused for every instance of a thing, which makes them a dicy place to do things like this. One cog could reset a value before a timer finishes for instance, and all kinds of other fun things that make my head hurt just thinking about.
-El Scorcho

"Its dodgeball time!" -Stormy Waters
2004-09-17, 7:53 AM #8
I'm a little confused, but it's none of your faults. My response will be a little cluttered.

First of all, GetSender anything to find out what killed something is poor in that the killer is most often defined as the projectile that did the killing, not the shooter.

Also, as for your array, you should name it more like this:

bugCreated0
bugCreated1
bugCreated2

and then specify it in your for loop as:

bugCreated0[x]

To answer your recent question, cogs won't recognize variables from other cogs as you have it.

Here's my suggestion, and although it might be a little annoying to implement, it'll make everything a lot easier in the end, and will even allow you to add limitless bugs later if you like... but I've gotta go. I'll type this up later.
Cordially,
Lord Tiberius Grismath
1473 for '1337' posts.
2004-09-17, 8:00 AM #9
Quote:
Originally posted by Lord_Grismath

First of all, GetSender anything to find out what killed something is poor in that the killer is most often defined as the projectile that did the killing, not the shooter.


That's actually partially correct. It will get the projectile. So what you want to do is use GetThingParent(GetSenderRef()). If they used the lightsaber which is a direct damage, or a skilltarget or something it should still return the correct value...because in all my testing, things without their parent set either via fireprojectile() or setthingparent() (from MotS) have their parent set to themselves by default. Or the verb just gets the original thing as a failsafe, regardless the outcome is the same.

I should have mentioned that before. Oops!
-El Scorcho

"Its dodgeball time!" -Stormy Waters
2004-09-17, 12:25 PM #10
This post looks long, but that's because of the quotes taking up too much space. :(

From rob_whatman:
Quote:
I wondered about how the actor cog knows what 'bugCreated' is, as it is defined in a different cog. Is that a problem?

From Lord_Grismath:
Quote:
To answer your recent question, cogs won't recognize variables from other cogs as you have it.

Oops! I'm sorry. I goofed. Somehow I thought there was only one cog. So my code will not work as I gave it. Yes, the bugsCreated symbols won't be recognized in the actor cog.

From rob_whatman:
Quote:
So, do I understand correctly: GetSenderID() looks for an Int value given by a Thing, and it doesn't look for the Thing itself. And I had confused the programme by using the Thing name 'bug0' etc, and it was looking for an Int variable with that same name?

I don't understand all that you are saying here, but it does sound like you might be confused by the use of Int and Thing in the symbols. There is no known difference between using Int and Thing in the symbols; Thing seems to be another name for Int.

From lucky_jackpot:
Quote:
wouldn't it more sensible to place the bug count code in a new separate cog

From El Scorcho:
Quote:
You'd really be better off handling the bugcount stuff in your original cog, and simply having killed SendTrigger to that cog to inform it of their death.

I agree with separating the code (now that I know there are two cogs), but not with using SendTrigger. By using SendTrigger from the killed message handler there would still be some of the problems El Scorcho mentioned. The proper separation would be achieved via capturing (explained below).

From El Scorcho:
Quote:
GetSenderRef() used in a killed message will return whatever was just killed, which is what I think you were really after there.

I agree. Looking this up in the DataMaster, GetSenderRef returns the "creature that died". If you have not done so, you need to retrieve the DataMaster (and possibly other references) for cogging.

From Lord_Grismath:
Quote:
Also, as for your array, you should name it more like this:
bugCreated0
bugCreated1
bugCreated2
...

Placing the 0 at the end of the first symbol in an array is entirely subjective. The symbol names used in an array can be anything; look it up in the DataMaster tutorials (Chapter 2: Arrays). I prefer to leave off the 0 so the array name in the code is more meaningful. (By the way, I have used array names without the 0 successfully.)

From El Scorcho:
Quote:
So what you want to do is use GetThingParent(GetSenderRef()).

This looks correct for finding the killer (in the killed message handler).

Here is my next set of suggestions to make the cogs work:

Change this in the first cog:
for (X=0;X<3;X=X+1) bugCreated[X] = CreateThing(bugType, bug0[X])
for (X=0;X<3;X=X+1) SetThingHealth(bug0[X], 10);

Into this:
for (X=0;X<3;X=X+1)
{
bugCreated[X] = CreateThing(bugType, bug0[X]);
SetThingHealth(bugCreated[X], 10);
CaptureThing(bugCreated[X]);
}

Note that SetThingHealth is used on the bugCreated symbols, because they represent the bugs that are created. The bug0, bug1, and bug2 things are being used only for creating and positioning the created bugs.

Cut and paste the killed and "bug died" message handlers (and the symbols they use) from the second cog to the first cog. This step and the previous step (CaptureThing) sets up the first cog to be a "capture" cog for the bugCreated things. A capture cog receives all messages that a class cog also receives for a thing, but only for the one thing. So now, the first cog can handle the killed message, and it will do it for only those 3 bugCreated things, not for any others that might be used in the level. If you don't understand what I just said here, be sure to look in the DataMaster under "Cog Verbs>Thing Action>CaptureThing".

Delete the final else statement in this code:
if (GetSenderID() == bugCreated[0])
call bug0died;
else
if (GetSenderID() == bugCreated[1])
call bug1died;
else
if (GetSenderID() == bugCreated[2])
call bug2died;
else
return;

This last step is needed so that after calling any of the "bug died" handlers, the killed message handler will return. Keeping the else statement would make the cog continue into the bug0died handler. You might have thought that the "bug died" handlers were actually part of the killed handler, but they are actually handlers just like killed and touched, except they do not use a message symbol. For more info, look in the DataMaster Old Tutorials: Messages.

Whew, I hope that helps.

:)
2004-09-18, 12:25 PM #11
Thank you everybody for your ideas, some of it is making sense. Sorry for confusing you, ZeqMacaw, with the two cogs - I thought I had read in Datamaster that killed messages had to go in actor cogs - or that is what i thought it meant, anyway! I see how using the actor cog could go wrong, LJ - I guess it doesn't know that there are any other things with the same template in the level. I'll input everything tomorrow, and see how I get on. Is it Ok to write back again if I have another query about this? I feel like I'm making you write my cog for me, which I know is not very fair. I just don't always know where to look for the problem.
2004-09-18, 12:38 PM #12
From rob_whatman:
Quote:
Is it Ok to write back again if I have another query about this?
As long as you're learning, keep asking questions.

:)
2004-09-19, 5:32 AM #13
The wonderful thing about class cogs is that they are specific to each type of that actor that is created - essentially, they look after all the fiddly controls of what that particular actor does, with all the code being in one central place. If you will, think of it in terms of every actor type "thing" that you insert into your level editor. Say you inserted 40 stormtroopers in your level - wouldn't it be tedious to write 40 cog scripts to control how those actors behaved? The solution: write one class cog and apply it to all the stormtroopers. Makes modification easier (change one thing and the changes are reflected for all the actors), not to mention it cuts down file-size to boot ;)

In contrast, the beauty about normal (or "level" cogs) is that you can do other "external" events without them being directly linked to an actor's class cog. Once again, take the troopers example, but you want it so that only one of them gives you a key when you kill them. Instead of placing the "generate key" code in the actor's class cog (which would spawn 40 keys :o), you could write a new cog with the "killed" message in it and specify a "thing" as the one special trooper who should drop a key when killed. This way, you are keeping the structure of the actor's controlling class cog the same (the special actor will die just like any of the other 40) but the "level" cog will also kick in and have the effect of generating the key when only that one particular actor dies. I hope that's a bit more informative for you :)

Quote:
Originally posted by rob_whatman:
Is it Ok to write back again if I have another query about this?


Heck yes !!! :) I second everything that ZeqMacaw posted ;). That's why we're a community afterall, to help each other out to the best of our abilities.

Also, it helps pass the knowledge around for the "next generation" of fledgling coggers ;). I have one main aim as long as I'm at Massassi and that's to keep JK and MotS editing alive for as long as possible - heck - as long as I still enjoy playing JK, I'll continue to help out where I can :D (...and maybe just maybe release a level of my own sometime... ;))

-Jackpot

PS: Wait until you start looking at serious vector based math in your cogs Rob - that's when you know you've crossed the line from being a "cogger" to "insanity"... :o :D
"lucky_jackpot is the smily god..." -gothicX
"Life is mostly froth and bubble, but two things stand in stone,
Kindness in another's trouble, courage in your own"
- "Ye Wearie Wayfarer"
|| AI Builder: compatible with both JK & MotS || My website ||
2004-09-23, 11:55 PM #14
I did it! Thanks guys - in the end, I realised you could just count how many times the killed message was called for, and there was the way to check the bugs were dead. Now why didn't I think of that before? ...:o

Anyway, if anyone would like to have the cog for themselves, here it is:
Code:
# COG Program
# 
# bughunt_mission_cog
#
# It replaces a crate 3do with a model of an open crate
# and creates bug creatures for you to hunt down.
# Want more creatures? Set a number for 'pandora'.  This will be a multiplier
# every time you touch the crate. 0 is the default.
#
# rob_whatman
# with lots of help from ZeqMacaw, Lord_Grismath, Lucky_Jackpot, El Scorcho ...
#
# This COG is not supported by Lucasarts.

symbols

thing		object
thing		bug0
thing		bug1
thing		bug2

template	bugType=darosian_mite

sound		wav0
sound		wav1
int 		X=0 local
int		pandora=0
int		bugsaGoGo	local

int	bugsKilled local

int bugCreated0 local
int bugCreated1 local
int bugCreated2 local

model       openBox=crtz.3do

message 	touched
message	killed


end

code

startup:
Sleep(0.5);
bugsaGoGo = 0;
bugsKilled = 0;
return;

touched:
 player = GetSenderID();


   if (GetSenderID() == player)

	{
	
	if(pandora == bugsaGoGo)
	{
	for (X=0;X<3;X=X+1)
		{
		bugCreated0[X] = CreateThing(bugType, bug0[X]);
		SetThingHealth(bugCreated0[X], 10);
		CaptureThing(bugCreated0[X]);
		}
	SetThingModel(object, openBox); 
	Print("SITH OFFICER: Typical!  You've let the Darosian hunting mites out!");
	Print ("SITH OFFICER: Maybe you'd better find a way to get rid of them, seeing as its your fault.");
	Print ("SITH OFFICER: Or would you rather spend a night in the detention wing?");
	PlaySoundThing(wav0, object, 1, -1, -1, 0);
	questPlayer = GetLocalPlayerThing();
	SetGoalFlags(questPlayer, 4, 1);
	bugsAgogo = bugsaGoGo + 1;
	
	}}

	return;


# This next section should check to see if you've killed all of the bugs, then reward you!
# The message killed makes a simple count to see if they are all dead,
# then the cog sets the new Objective flags.
#
# 19.9.04 ZeqMacaw has suggested new code.


# Lord_Grismath suggests using GetSenderRef to find the victim, and GetThingParent to find the killer.


killed:

	player = GetLocalPlayerThing();
	killer = GetThingParent(GetSenderRef());

   // Player killed a lovely critter!
	if (player == killer)
   		{
      		ChangeInv( player, 72, 0.5 );
   		}


// Now, we check to see if the other critters are also dead yet... you bully!


bugsKilled = bugsKilled + 1;


	if (bugsKilled == 3)
		{
		questPlayer = GetLocalPlayerThing();
		SetGoalFlags(questplayer, 4, 2);
		PlaySoundThing(wav1, questplayer, 1, -1, -1, 0);
		Print("You killed all the little critters ... shame on you!");
		return;
		}

	return;

end

↑ Up to the top!