my method of adding multi-character switching

Need help with using DizzyAGE then look here
Colin
Hard Boiled Egg
Posts: 594
Joined: Mon May 28, 2007 8:34 am
Location: Worthing, West Sussex, UK

my method of adding multi-character switching

Post by Colin » Tue Sep 22, 2009 5:45 pm

here is the info and code to add multi-character switching into a game
as used in summer blast dizzy.

firstly you need to add those characters to your map!
place them all in their start positions. Dizzy's exact start location isn't as important,
as the player initial start position, is still controlled by beginx and beginy in gamedef.gs
each one is an actionable dynamic object and for the code to work with the right tiles,
you need to set them up with the right ID numbers.

1 Dizzy
2 Daisy
3 Dylan
4 Denzil
5 Dora
6 Dozy
7 Grand Dizzy

you don't need to use all of them(except for dizzy)
***BUT***
those that you do, must have the right id

once that is done, you can start adding the switching functions that will
be called by your game,into game.gs

The first function will save the existing player id and inventory, then paste the character
as an actionable object again

Code: Select all

func OldChar()
{
	i=0;				
	PlayerSet(P_DISABLE,1);			//pause player
	OldCharScuba(); 			//checks to see if wearing scuba
	count = InventoryCount(); 		
	chrx = ObjFind(chr);			//	
	ObjSet(ObjFind(1),O_USER+10,chr);	//saves last character id
	x = PlayerGet(P_ X) ;			
	y = PlayerGet(P_Y);			//finds player x and y location
	ObjSet(chrx,O_X,x-12); 			//
	ObjSet(chrx,O_Y,y-14);			//replaces player with last character tile
	ObjSet(chrx,O_DISABLE,0);		//
	ObjPresent(chrx);			//
	ObjSet(chrx,O_USER+11,count);		//saves number of items in inventory
	if(count>0)
	{
		for(i=count-1;i>=0;i--)		//
		{				
		idx = InventoryGet(i);		//saves each item id to
		chrx = ObjFind(chr);		//that characters id
		ObjSet(chr,O_USER+i,idx);	//user variables
		}
	}	
	
	InventoryClear();			//wipes current inventory ready for new character
	return;
}
The next function will load the new player inventory and set the costume to the new character

Code: Select all

func NewChar()
{
		i=0;
		chrx = ObjFind(chr);		//
		count = ObjGet(chrx,O_USER+11);	//calls up number of items new character holds
		x = ObjGet(chrx,O_ X) ;		//
		y = ObjGet(chrx,O_Y);		//finds new character x and y location
		scb = ObjFind(chr);
		chrf = ObjGet(scb,O_TILE);	 //finds new characters idle tile	
		ObjSet(ObjFind(1),O_USER+10,chr);//saves new player id

		PlayerSet(P_TILE,chrf);		//switches player tile to new idle tile
		c=PlayerGet(P_COSTUME);
		if(c==330)
		{
		PlayerSet(P_TILE,340);		//initially switches to scuba tile if previously wearing
		}
		PlayerSet(P_COSTUME,chrf);	
		PlayerSet(P_X,x+12);		//
		PlayerSet(P_Y,y+14);		//moves to new characters location


	if(count>0)
	{
		for(i=count-1;i>=0;i--)		//loads each item id from
		{
		idx = ObjGet(chr,O_USER+i);	//that characters id
		GameSet(G_INVENTORY+i,idx);	//user variables
		}
 	}
	chrx = ObjFind(chr);

	ObjSet(chrx,O_DISABLE,1);		//disables new characters action tile
	GamePause(0);
	PlayerSet(P_DISABLE,0);			//re enable player control
	return;
}
This next function checks if the player is carrying the scuba, if so then the actionable object will appear
still wearing it!

Code: Select all

func OldCharScuba()
{
	scuba = 0;
	if(ID_SCUBA!=-1) scuba = InventoryHasItem(ID_SCUBA) ? 30 : 0;//offset tiles by 30 with scuba
	if(chr==1) scuba+=10;		//dizzy tile set start from 10 onwards
	if(chr==2) scuba+=310;		//daisy tile set start from 310 onwards
	if(chr==3) scuba+=360;		//dylan tile set start from 360 onwards
	if(chr==4) scuba+=410;		//denzil tile set start from 410 onwards
	if(chr==5) scuba+=460;		//dora tile set start from 460 onwards
	if(chr==6) scuba+=510;		//dozy tile set start from 510 onwards
	if(chr==7) scuba+=560;		//g dizzy tile set start from 560 onwards
	scb = ObjFind(chr);
	ObjSet(scb,O_TILE,scuba);	//switches action tile to the right costume	
}
Now in the func BeginNewGame() in game.gs
you need to add 4 lines to initialize the player start id

Code: Select all

	chr = 1;			//initialises dizzy as start character
	chrx = ObjFind(chr);
	ObjSet(chrx,O_DISABLE,1);	//disables dizzys action tile
	ObjSet(ObjFind(1),O_USER+10,chr); //initialises dizzy for load/save
also in game.gs you need to add the inventory saving to the load/save game
so that you will continue with the right items on reloading.
in func SaveUserData( file ), add

Code: Select all

func SaveUserData( file )
{	
	//..
	return 1;
}
and func LoadUserData( file )

Code: Select all

func LoadUserData( file )
{
	chr = ObjGet(ObjFind(1),O_USER+10); //calls switch to that character
	return 1;
}
that is it for the game.gs for the moment!

you now need to add some code into the handlers.gs file
this code will always make sure the player tile is set to the right character id's

look for the func HandlerPlayerUpdate()
and replace the // Player set costume section with

Code: Select all

	costume = 0;
	if(chr==1)
	{
	if(ID_SCUBA!=-1) costume = InventoryHasItem(ID_SCUBA) ? 30 : 0;
	}
	if(chr==2) costume+=300;
	if(chr==3) costume+=350;
	if(chr==4) costume+=400;
	if(chr==5) costume+=450;
	if(chr==6) costume+=500;	
	if(chr==7) costume+=550;	
	PlayerSet(P_COSTUME,costume);
this is where dizzyage updates the player costume!

also important, in gamedef.gs
you will need to set a global variable for chr so all the scripts can see it

so add

Code: Select all

#def chr		7
i added mine at the top of the list



now back to game.gs and actually switching between characters in game!

say you were another character and you wanted to switch to daisy
here is the basic code to switch.

Code: Select all

/////////////////////////////////////////////////////////////////////
//daisy switch

func ActionObject_2()
{
	OldChar();	//calls the old character save function
	chr=2;		//sets chr variable to the daisy id
	NewChar();	//loads new character chr id as player
}
this you can expand upon, so it can display messages when switching.
you can also for instance, use status checks to disable or enable
the switching to each character as your game progresses.

have fun!
ImageImageImage

Grandad
Hard Boiled Egg
Posts: 1492
Joined: Sat Aug 08, 2009 10:47 am
Location: Balham - gateway to the south

Post by Grandad » Wed Sep 23, 2009 2:30 pm

Brilliant Colin ...I've actually been ploughing through all the scripts of Summer Blast for details of character switiching and keeping the inventories separate, so this should help a lot. Thanks for posting this.

Grandad

Meph
Hard Boiled Egg
Posts: 2973
Joined: Fri Apr 13, 2007 12:47 am
Location: England, Suffolk

Post by Meph » Wed Sep 23, 2009 4:38 pm

Cool,

But is it possible to switch to a character thats not in the same room?
Dizzy could be in room 1 and Dozy could be in room 10, and you wanted to switch.
Its always the cracked ones that let the light in

Colin
Hard Boiled Egg
Posts: 594
Joined: Mon May 28, 2007 8:34 am
Location: Worthing, West Sussex, UK

Post by Colin » Wed Sep 23, 2009 5:08 pm

yes, the code does do that. it takes the new player position from where they were standing. When I originally wrote the code in a test map. I had the switching performed from a menu (if you look in the sbd game script in multicharacter.gs, the menu code is still there, it's just deactivated for the game.
ImageImageImage

Meph
Hard Boiled Egg
Posts: 2973
Joined: Fri Apr 13, 2007 12:47 am
Location: England, Suffolk

Post by Meph » Wed Sep 23, 2009 5:48 pm

Excellent.
:dizzy_cool:
Its always the cracked ones that let the light in

Grandad
Hard Boiled Egg
Posts: 1492
Joined: Sat Aug 08, 2009 10:47 am
Location: Balham - gateway to the south

Post by Grandad » Fri Jun 18, 2010 10:52 am

I'm having trouble getting this to work. I'm only using two characters. The main character (Daisy) tiles start at 10 and the second character (Annie) start at 310, so have set the handler PlayerSetCostume as:

Code: Select all

// Player set costume
	costume = 0;
	if (chr == 2) costume +=300;
	PlayerSet(P_COSTUME, costume);
I've ignored the scuba stuff as I'm not using a scuba ...and can't be bothered to draw the scuba tiles for the second character. Initially I screwed this right up cos I thought that 1 Dizzy, 2 Daisy etc were just the list numbers, not the ID you have to give them.

Everything is working fine except the costume change. The inactive player's tile is fine (both for Daisy and Annie), but the active player's costume remains as Daisy even though the inventory switches correctly. The tiles follow the same sequence, ie idle = 10 and 310, walk = 11 and 311, up is 12 and 312 etc. Really not sure what I'm doing wrong as I've double checked the coding for old/new char functions.

Grandad

Colin
Hard Boiled Egg
Posts: 594
Joined: Mon May 28, 2007 8:34 am
Location: Worthing, West Sussex, UK

Post by Colin » Fri Jun 18, 2010 12:44 pm

Hmm! are you sure you have placed a dizzy idle tile, just off your game map, with an object ID set to 1?
as explained at the beginning, even if you are not having dizzy in the game, you still need it

it is important that you have this!!
when the script switches characters, it saves the current character info into one of ID 1's user variables. this is so it knows which character to switch to, when you reload a save game.
at game start it writes the start character id into this. as it can't find this object id to write into, it shows an error

if you are starting with daisy for instance. in begin new game, you would set chr = 2
and also call a
NewChar();
so that you are now switched into the right character at the beginning.

I also noticed that your using
ObjSet(ObjFind(10000), O_STATUS, 1);
to find which character you are

you can find this out anytime by checking up the chr variable
ImageImageImage

Grandad
Hard Boiled Egg
Posts: 1492
Joined: Sat Aug 08, 2009 10:47 am
Location: Balham - gateway to the south

Post by Grandad » Fri Jun 18, 2010 1:22 pm

Thanks Colin, yet again I'm being an idiot and looking in the wrong place. Because I was having problems with the engine not finding the scuba stuff I disabled all the references to scuba ...and have just realised that I also disabled the costume change in the Player Set Costume in the Handler Player Update.

I don't think I need a Dizzy brush as for the last couple of games I've made, the Daisy tiles always start at 10 and the engine seems to accept this with no problem even when saving and loading. I suppose that the default for Dizzy normally starts with a id of 10 for the idle tile, but I will check out saving for this new game and if there is a problem I'll add a Dizzy tile and change the ids of Daisy and Annie to '2' and '3'.

regarding my 'check' brush (10000), I set this as I want Annie to have different reactions to Daisy for the same object Are you saying that instead of adding ..ObjGet(ObjFind(10000), O_STATUS) == 1) to the end of an 'if' function I could just add ...&& chr = 2) to check that it is Annie not Daisy as that would save a lot of typing. Or even better something like:

Code: Select all

func ActionObject_888(idx)
{
if (chr == 2)
{
Message1 (4,4, "MESSAGE");
MessagePop();
}

else
{
ObjSet(ObjFind(666), O_DISABLE, 1);
}
}
By the way, I've managed to get your climbing code off pat now, so have included a section of lots of ivy hanging off rocks that Daisy has to climb ..and jump to. Thanks for creating it.

Grandad

PS - loading after saving a game does bring the correct character into play, but no matter at what position you save the game, it always loads at the place where you switched characters.

PPS - same happens when add a 'dizzy' as char 1 and switch daisy to 2 and annie to 3, plus amend the def, handler and switch functions

Grandad
Hard Boiled Egg
Posts: 1492
Joined: Sat Aug 08, 2009 10:47 am
Location: Balham - gateway to the south

Post by Grandad » Fri Jun 18, 2010 3:27 pm

Now it's really acting silly. OK I've added a new actionable object with an ID of 1 (to be Dizzy), switched Daisy to '2' and Annie to '3'. Changed the Def.gs to #def chr 3. Changed the Handler Player Update to :

Code: Select all

// Player set costume
	costume = 0;
	if (chr == 2) costume+= 0;
	if (chr == 3) costume+= 300;
	PlayerSet(P_COSTUME, costume);
and amended the switch function so that Daisy is '2' and Annie is '3'. Looking at the 'new char' coding it should 'find' the location of the current active 'costume' then set it:

Code: Select all

func NewChar()  // load new player inventory and set costume
{
i = 0;
chrx = ObjFind(chr);
count = ObjGet(chrx, O_USER +11);
x = ObjGet(chrx, O_ X) ;
y = ObjGet(chrx, O_Y);
scb = ObjFind(chr);
chrf = ObjGet(scb, O_TILE);
ObjSet(ObjFind(1), O_USER +10, chr);
PlayerSet(P_TILE, chrf);
PlayerSet(P_COSTUME, chrf);
PlayerSet(P_X, x+12);
PlayerSet(P_Y, y+14);
if (count >0)
{
for (i = count -1; i >=0; i--)
{
idx = ObjGet(chr, O_USER+i);
GameSet(G_INVENTORY +i, idx);
}
}
chrx = ObjFind(chr);
ObjSet(chrx, O_DISABLE, 1);
GamePause(0);
PlayerSet(P_DISABLE, 0);
return;
}
If I save the game after switching characters the screen flips back to the position of where the switch took place and saves there. Loading starts at the place the switch took place but the correct character is active and the relevant inventories are correct. However, if I try to save the game before switching characters it crashes with this error message:

Code: Select all

GS_ERROR:   USER, fn=ObjGet, line=-1, file="unknown"
GS_DESC:    -1, 853, "invalid object index"
CALLSTACK:  ObjGet:-1 < NewChar:311 < SaveUserData:159 < SaveGame:145 < OpenDialogFiles:348 < OpenDialogGameMenu:164 < .

APP: activate off
APP: activate on
ERROREXIT: GS9 ERROR
_gserrorexit < GSErrHandler < gsVM::Error < gsObjGet < gsVM::Run < cDizScript::Update < cDizGame::Update < cDizApp::Update < AppOnRun < e9App::Run < main
APP: activate off
APP: activate on
and yet there is definitely an actionable object with an ID of 1 on the saved map. My brain hurts!

Grandad

Colin
Hard Boiled Egg
Posts: 594
Joined: Mon May 28, 2007 8:34 am
Location: Worthing, West Sussex, UK

Post by Colin » Fri Jun 18, 2010 5:04 pm

when I said you need a tile of dizzy idle with an id of 1, this would be because i didn't read that you weren't using the original character tilesets

if you can, revert back to when it was working.
place a tile of annie idle with ID 1
This is the tile that will appear when you switch to the new character. so needs to be of the right tile.

to explain how the switch works (original tilesets)

placing the dizzy idle tile ID (1)
as you normally start with dizzy, I place this off the game area. you can place it where you start, but make sure it is disabled

when you action on another character say daisy ID (2)
it checks current character ID from chr
it then counts how many items in the inventory and saves the amount and the item ids into the old character ID(1) user variables
then it moves the dizzy idle ID(1) to the current player position and reenables it
it sets the chr to the new character ID(2)
now saves the new chr to ID(1) user variable, so it knows which character to save game
it then reads the new character ID(2) user variables back into the inventory
disables the ID(2) daisy idle tile from view
switches the player tile from dizzy to daisy
ImageImageImage

Post Reply