Exemplo n.º 1
0
/**
 * Loads a new script for the current team.
 *
 * Stack: 1 - The script type.
 *
 * @param script The script engine to operate on.
 * @return The value 0. Always.
 */
uint16 Script_Team_Load(ScriptEngine *script)
{
	Team *t;
	uint16 type;

	t = g_scriptCurrentTeam;
	type = STACK_PEEK(1);

	if (t->action == type) return 0;

	t->action = type;

	Script_Reset(&t->script, g_scriptTeam);
	Script_Load(&t->script, type & 0xFF);

	return 0;
}
Exemplo n.º 2
0
/**
 * Loads a new script for the current team.
 *
 * Stack: *none*.
 *
 * @param script The script engine to operate on.
 * @return The value 0. Always.
 */
uint16 Script_Team_Load2(ScriptEngine *script)
{
	Team *t;
	uint16 type;

	VARIABLE_NOT_USED(script);

	t = g_scriptCurrentTeam;
	type = t->actionStart;

	if (t->action == type) return 0;

	t->action = type;

	Script_Reset(&t->script, g_scriptTeam);
	Script_Load(&t->script, type & 0xFF);

	return 0;
}
Exemplo n.º 3
0
M4Err SG_ApplyCommand(LPSCENEGRAPH graph, SGCommand *com, Double time_offset)
{
	M4Err e;
	CommandFieldInfo *inf;
	FieldInfo field;
	SFNode *def, *node;
	void *slot_ptr;

	if (!com || !graph) return M4BadParam;

	e = M4OK;
	switch (com->tag) {
	case SG_SceneReplace:
		/*unregister root*/
		Node_Unregister(graph->RootNode, NULL);
		/*remove all protos and routes*/
		while (ChainGetCount(graph->routes_to_activate)) 
			ChainDeleteEntry(graph->routes_to_activate, 0);
		
		/*destroy all routes*/
		while (ChainGetCount(graph->Routes)) {
			Route *r = ChainGetEntry(graph->Routes, 0);
			/*this will unregister the route from the graph, so don't delete the chain entry*/
			SG_DeleteRoute(r);
		}
		/*destroy all proto*/
		while (ChainGetCount(graph->protos)) {
			PrototypeNode *p = ChainGetEntry(graph->protos, 0);
			/*this will unregister the proto from the graph, so don't delete the chain entry*/
			SG_DeleteProto(p);
		}
		/*DO NOT TOUCH node registry*/
		/*DO NOT TOUCH UNREGISTERED PROTOS*/

		/*move all protos in graph*/
		while (ChainGetCount(com->new_proto_list)) {
			PrototypeNode *p = ChainGetEntry(com->new_proto_list, 0);
			ChainDeleteEntry(com->new_proto_list, 0);
			ChainDeleteItem(graph->unregistered_protos, p);
			ChainAddEntry(graph->protos, p);
		}
		/*assign new root (no need to register/unregister)*/
		graph->RootNode = com->node;
		com->node = NULL;
		break;

	case SG_NodeReplace:
		if (!ChainGetCount(com->command_fields)) return M4OK;
		inf = ChainGetEntry(com->command_fields, 0);
		e = Node_ReplaceAllInstances(com->node, inf->new_node, 0);
		if (inf->new_node) Node_Register(inf->new_node, NULL);
		break;

	case SG_MultipleReplace:
	case SG_FieldReplace:
	{
		u32 i, j;
		Chain *container, *list;
		for (j=0; j<ChainGetCount(com->command_fields); j++) {
			inf = ChainGetEntry(com->command_fields, j);

			e = Node_GetField(com->node, inf->fieldIndex, &field);
			if (e) return e;

			switch (field.fieldType) {
			case FT_SFNode:
			{
				node = *((SFNode **) field.far_ptr);
				e = Node_Unregister(node, com->node);
				*((SFNode **) field.far_ptr) = inf->new_node;
				if (!e) Node_Register(inf->new_node, com->node);
				break;
			}
			case FT_MFNode:
				container = * ((Chain **) field.far_ptr);
				list = * ((Chain **) inf->field_ptr);
				Node_UnregisterChildren(com->node, container);

				for (i=0; i<ChainGetCount(list); i++) {
					node = ChainGetEntry(list, i);
					ChainAddEntry(container, node);
					if (!e) Node_Register(node, com->node);
				}
				break;
			default:
				/*this is a regular field, reset it and clone - we cannot switch pointers since the
				original fields are NOT pointers*/
				if (!VRML_IsSFField(field.fieldType)) {
					e = VRML_MF_Reset(field.far_ptr, field.fieldType);
				}
				if (e) return e;
				VRML_FieldCopy(field.far_ptr, inf->field_ptr, field.fieldType);
				if (field.fieldType==FT_SFTime) *(SFTime *)field.far_ptr = *(SFTime *)field.far_ptr + time_offset;
				break;
			}
			SG_CheckFieldChange(com->node, &field);
		}
		break;
	}

	case SG_MultipleIndexedReplace:
	case SG_IndexedReplace:
	{
		u32 sftype, i;
		for (i=0; i<ChainGetCount(com->command_fields); i++) {
			inf = ChainGetEntry(com->command_fields, i);

			e = Node_GetField(com->node, inf->fieldIndex, &field);
			if (e) return e;

			/*if MFNode remove the child and set new node*/
			if (field.fieldType == FT_MFNode) {
				/*we must remove the node before in case the new node uses the same ID (not forbidden) and this
				command removes the last instance of the node with the same ID*/
				Node_ReplaceChild(com->node, *((Chain**) field.far_ptr), inf->pos, inf->new_node);
				Node_Register(inf->new_node, com->node);
			}
			/*erase the field item*/
			else {
				if ((inf->pos < 0) || ((u32) inf->pos >= ((GenMFField *) field.far_ptr)->count) ) {
					inf->pos = ((GenMFField *)field.far_ptr)->count - 1;
					/*may happen with text and default value*/
					if (inf->pos < 0) {
						inf->pos = 0;
						VRML_MF_Alloc(field.far_ptr, field.fieldType, 1);
					}
				}
				e = VRML_MF_GetItem(field.far_ptr, field.fieldType, & slot_ptr, inf->pos);
				if (e) return e;
				sftype = VRML_GetSFType(field.fieldType);
				VRML_FieldCopy(slot_ptr, inf->field_ptr, sftype);
				/*note we don't add time offset, since there's no MFTime*/
			}
			SG_CheckFieldChange(com->node, &field);
		}
		break;
	}
	case SG_RouteReplace:
	{
		LPROUTE r;
		char *name;
		r = SG_FindRoute(graph, com->RouteID);
		def = SG_FindNode(graph, com->fromNodeID);
		node = SG_FindNode(graph, com->toNodeID);
		if (!node || !def) return M4InvalidNode;
		name = NULL;
		if (r) {
			name = r->name;
			r->name = NULL;
			SG_DeleteRoute(r);
		}
		r = SG_NewRoute(graph, def, com->fromFieldIndex, node, com->toFieldIndex);
		SG_SetRouteID(r, com->RouteID);
		if (name) {
			SG_SetRouteName(r, name);
			free(name);
		}
		break;
	}
	case SG_NodeDeleteEx:
	case SG_NodeDelete:
	{
		if (com->node) Node_ReplaceAllInstances(com->node, NULL, (com->tag==SG_NodeDeleteEx) ? 1 : 0);
		break;
	}
	case SG_RouteDelete:
	{
		return SG_DeleteRouteByID(graph, com->RouteID);
	}
	case SG_IndexedDelete:
	{
		if (!ChainGetCount(com->command_fields)) return M4OK;
		inf = ChainGetEntry(com->command_fields, 0);

		e = Node_GetField(com->node, inf->fieldIndex, &field);
		if (e) return e;
		if (VRML_IsSFField(field.fieldType)) return M4NonCompliantBitStream;

		/*then we need special handling in case of a node*/
		if (VRML_GetSFType(field.fieldType) == FT_SFNode) {
			e = Node_ReplaceChild(com->node, * ((Chain **) field.far_ptr), inf->pos, NULL);
		} else {
			if ((inf->pos < 0) || ((u32) inf->pos >= ((GenMFField *) field.far_ptr)->count) ) {
				inf->pos = ((GenMFField *)field.far_ptr)->count - 1;
			}
			/*this is a regular MFField, just remove the item (realloc)*/
			e = VRML_MF_Remove(field.far_ptr, field.fieldType, inf->pos);
		}
		/*deletion -> node has changed*/
		if (!e) SG_CheckFieldChange(com->node, &field);
		break;
	}
	case SG_NodeInsert:
	{
		if (!ChainGetCount(com->command_fields)) return M4OK;
		inf = ChainGetEntry(com->command_fields, 0);

		e = Node_InsertChild(com->node, inf->new_node, inf->pos);
		if (!e) Node_Register(inf->new_node, com->node);
		/*notify (children is the 3rd field, so 2 0-based)*/
		if (!e) Node_OnEventOut(com->node, 2);
		break;
	}
	case SG_RouteInsert:
	{
		LPROUTE r;
		def = SG_FindNode(graph, com->fromNodeID);
		node = SG_FindNode(graph, com->toNodeID);
		if (!node || !def) return M4InvalidNode;
		r = SG_NewRoute(graph, def, com->fromFieldIndex, node, com->toFieldIndex);
		if (com->RouteID) SG_SetRouteID(r, com->RouteID);
		if (com->def_name) {
			SG_SetRouteName(r, com->def_name);
			free(com->def_name);
			com->def_name = NULL;
		}
		break;
	}
	case SG_IndexedInsert:
	{
		u32 sftype;
		if (!ChainGetCount(com->command_fields)) return M4OK;
		inf = ChainGetEntry(com->command_fields, 0);
		e = Node_GetField(com->node, inf->fieldIndex, &field);
		if (e) return e;

		/*rescale the MFField and parse the SFField*/
		if (field.fieldType != FT_MFNode) {
			if (inf->pos == -1) {
				e = VRML_MF_Append(field.far_ptr, field.fieldType, & slot_ptr);
			} else {
				e = VRML_MF_Insert(field.far_ptr, field.fieldType, & slot_ptr, inf->pos);
			}
			if (e) return e;
			sftype = VRML_GetSFType(field.fieldType);
			VRML_FieldCopy(slot_ptr, inf->field_ptr, sftype);
		} else {
			if (inf->new_node) {
				e = InsertSFNode(field.far_ptr, inf->new_node, inf->pos);
				if (e) return e;
				Node_Register(inf->new_node, com->node);
			}
		}
		if (!e) SG_CheckFieldChange(com->node, &field);
		break;
	}
	case SG_ProtoInsert:
		/*destroy all proto*/
		while (ChainGetCount(com->new_proto_list)) {
			PrototypeNode *p = ChainGetEntry(com->new_proto_list, 0);
			ChainDeleteEntry(com->new_proto_list, 0);
			ChainDeleteItem(graph->unregistered_protos, p);
			ChainAddEntry(graph->protos, p);
		}
		return M4OK;
	case SG_ProtoDelete:
		{
			u32 i;
			for (i=0; i<com->del_proto_list_size; i++) {
				/*note this will check for unregistered protos, but since IDs are unique we are sure we will 
				not destroy an unregistered one*/
				PrototypeNode *proto = SG_FindProto(graph, com->del_proto_list[i], NULL);
				if (proto) SG_DeleteProto(proto);
			}
		}
		return M4OK;
	case SG_ProtoDeleteAll:
		/*destroy all proto*/
		while (ChainGetCount(graph->protos)) {
			PrototypeNode *p = ChainGetEntry(graph->protos, 0);
			ChainDeleteEntry(graph->protos, 0);
			/*this will unregister the proto from the graph, so don't delete the chain entry*/
			SG_DeleteProto(p);
		}
		/*DO NOT TOUCH UNREGISTERED PROTOS*/
		return M4OK;
	/*only used by BIFS*/
	case SG_GlobalQuantizer:
		return M4OK;
	default:
		return M4NotSupported;
	}
	if (e) return e;

	if (com->scripts_to_load) {
		while (ChainGetCount(com->scripts_to_load)) {
			SFNode *script = ChainGetEntry(com->scripts_to_load, 0);
			ChainDeleteEntry(com->scripts_to_load, 0);
			Script_Load(script);
		}
		DeleteChain(com->scripts_to_load);
		com->scripts_to_load = NULL;
	}
	return M4OK;
}
Exemplo n.º 4
0
int EOF_IMPORT_VIA_LC(EOF_VOCAL_TRACK *tp, struct Lyric_Format **lp, int format, char *inputfilename, char *string2)
{
	char * returnedfn = NULL;	//Return string from dialog window
	FILE *inf;	  //Used to open the input file
	struct Lyric_Format *detectionlist;
	unsigned long i;
	int jumpcode = 0;

	eof_log("EOF_IMPORT_VIA_LC() entered", 1);

//Validate parameters
	if((tp == NULL) || (inputfilename == NULL))
		return 0;	//Return failure

	if((format == 0) && (lp == NULL))
		return 0;	//Return failure

//Perform detection logic
	InitLyrics();	//Initialize all variables in the Lyrics structure
	InitMIDI();		//Initialize all variables in the MIDI structure
	if(format == 0)		//Auto-detect lyric format
	{
		detectionlist=DetectLyricFormat(inputfilename);
		if(detectionlist == NULL)
			return 0;	//Return invalid lyric file

		if(detectionlist->format == PITCHED_LYRIC_FORMAT)
		{	//If the detection format is Pitched Lyrics, the user must specify the corresponding Vocal Rhythm MIDI
			*lp=detectionlist;	//Return the detected lyric information via the lp pointer
			return -1;			//Return prompt for user selection
		}

		if(detectionlist->next != NULL)
		{	//If there was more MIDI track with lyrics, the user must specify which track to import
			*lp=detectionlist;	//Return the detected lyric information via the lp pointer
			return -2;			//Return prompt for user selection
		}

		Lyrics.in_format=detectionlist->format;		//Format to import
		if(detectionlist->track != NULL)
			Lyrics.inputtrack=detectionlist->track;	//Track to import from
		DestroyLyricFormatList(detectionlist);		//Deallocate the linked list returned by DetectLyricFormat()
		detectionlist=NULL;
	}
	else			//Import specific format
	{
		Lyrics.in_format=format;

		if(Lyrics.in_format == KAR_FORMAT)
		{	//If this is a format for which string2 (pitched file or track name) must be specified
			if(string2 == NULL)	//If the track name to import is not given
				return 0;	//Return failure

			Lyrics.inputtrack=DuplicateString(string2);	//Make a duplicate, so its de-allocation won't affect calling function
		}
		else if(Lyrics.in_format == PITCHED_LYRIC_FORMAT)
		{	//If importing Pitched Lyrics, user must provide the Vocal Rhythm MIDI
			returnedfn = ncd_file_select(0, eof_filename, "Select Vocal Rhythm MIDI", eof_filter_midi_files);
			eof_clear_input();
			if(!returnedfn)
				return 0;	//Return error or user canceled
		}
	}

	Lyrics.infilename=DuplicateString(inputfilename);	//Make a duplicate, so it's de-allocation won't affect calling function

	jumpcode=setjmp(jumpbuffer); //Store environment/stack/etc. info in the jmp_buf array
	if(jumpcode!=0) //if program control returned to the setjmp() call above returning any nonzero value
	{
		(void) puts("Assert() handled sucessfully!");
		free(Lyrics.infilename);
		Lyrics.infilename = NULL;
		ReleaseMemory(1);	//Release memory allocated during lyric import
		return 0;	//Return error
	}

//Import lyrics
	switch(Lyrics.in_format)
	{
		case SCRIPT_FORMAT:	//Load script.txt format file as input
			inf=fopen_err(Lyrics.infilename,"rt");	//Script is a text format
			Script_Load(inf);
		break;

		case VL_FORMAT:	//Load VL format file as input
			inf=fopen_err(Lyrics.infilename,"rb");	//VL is a binary format
			VL_Load(inf);
		break;

		case MIDI_FORMAT:	//Load MIDI format file as input
			if(string2 == NULL)	//If no track name was given
				Lyrics.inputtrack=DuplicateString("PART VOCALS");	//Default to PART VOCALS
			else
				Lyrics.inputtrack=DuplicateString(string2);	//Make a duplicate, so its de-allocation won't affect calling function

			inf=fopen_err(Lyrics.infilename,"rb");	//MIDI is a binary format
			Parse_Song_Ini(Lyrics.infilename,1,1);	//Load ALL tags from song.ini first, as the delay tag will affect timestamps
			MIDI_Load(inf,Lyric_handler,0);		//Call MIDI_Load, specifying the new KAR-compatible Lyric Event handler
		break;

		case USTAR_FORMAT:	//Load UltraStar format file as input
			inf=fopen_err(Lyrics.infilename,"rt");	//UltraStar is a text format
			UStar_Load(inf);
		break;

		case LRC_FORMAT:	//Load LRC format file as input
		case ELRC_FORMAT:
			inf=fopen_err(Lyrics.infilename,"rt");	//LRC is a text format
			LRC_Load(inf);
		break;

		case VRHYTHM_FORMAT:	//Load vocal rhythm (MIDI) and pitched lyrics
			inf=fopen_err(returnedfn,"rb");	//Vrhythm is a binary format
			VRhythm_Load(inputfilename,returnedfn,inf);
		break;

		case PITCHED_LYRIC_FORMAT:
			inf=fopen_err(returnedfn,"rb");	//Vrhythm is a binary format
			VRhythm_Load(eof_filename,returnedfn,inf);
		break;

		case KAR_FORMAT:	//Load KAR MIDI file
			inf=fopen_err(Lyrics.infilename,"rb");	//KAR is a binary format
			MIDI_Load(inf,Lyric_handler,0);	//Call MIDI_Load, specifying the new KAR-compatible Lyric Event handler
		break;

		case SKAR_FORMAT:	//Load SKAR MIDI file
			inf=fopen_err(Lyrics.infilename,"rb");	//KAR is a binary format
			Lyrics.inputtrack=DuplicateString("Words");
			MIDI_Load(inf,SKAR_handler,0);	//Call MIDI_Load, specifying the Simple Karaoke Event handler
			EndLyricLine();	//KAR files do not mark the end of the last line of lyrics
		break;

		case ID3_FORMAT:	//Load MP3 ID3 tag
			inf=fopen_err(Lyrics.infilename,"rb");	//MP3 is a binary format
			ID3_Load(inf);
		break;

		case SRT_FORMAT:	//Load SRT file
			inf=fopen_err(Lyrics.infilename,"rt");	//SRT is a text format
			SRT_Load(inf);
		break;

		case XML_FORMAT:	//Load XML file
			inf=fopen_err(Lyrics.infilename,"rt");	//XML is a text format
			XML_Load(inf);
		break;

		case C9C_FORMAT:	//Load JamBand file
			inf=fopen_err(Lyrics.infilename,"rt");	//JamBand is a text format
			JB_Load(inf);
		break;

		case RS_FORMAT:		//Load Rocksmith XML file
		case RS2_FORMAT:
			inf=fopen_err(Lyrics.infilename,"rt");	//Rocksmith XML is a text format
			RS_Load(inf);
		break;

		default:
		return 0;	//Return failure
	}//switch(Lyrics.in_format)

	free(Lyrics.infilename);
	Lyrics.infilename = NULL;

//Validate imported lyrics
	if((Lyrics.piececount == 0) || (MIDI_Lyrics.head != NULL))	//If the imported MIDI track had no valid lyrics or otherwise was incorrectly formatted
	{
		ReleaseMemory(1);	//Release memory allocated during lyric import
		fclose_err(inf);
		return 0;	  //Return no EOF lyric structure
	}

	PostProcessLyrics();	//Perform validation of pointers, counters, etc.

	if(Lyrics.pitch_tracking)
	{	//Only perform input pitch validation and remapping if the import lyrics had pitch information
		RemapPitches();		//Ensure pitches are within the correct range (except for pitchless lyrics)
	}

	//Delete any existing lyrics and lines
	for(i = 0; i < tp->lyrics; i++)
	{
		free(tp->lyric[i]);
	}
	tp->lyrics = 0;
	tp->lines = 0;
	fclose_err(inf);	//Ensure this file gets closed
	inf=NULL;

	if(EOF_TRANSFER_FROM_LC(tp,&Lyrics) != 0)	//Pass the Lyrics global variable by reference
	{
		ReleaseMemory(1);	//Release memory allocated during lyric import
		return 0;		//Return error (failed to import into EOF lyric structure)
	}

	ReleaseMemory(1);	//Release memory allocated during lyric import
	return 1;	 		//Return finished EOF lyric structure
}
Exemplo n.º 5
0
/**
 * Prepare the map (after loading scenario or savegame). Does some basic
 *  sanity-check and corrects stuff all over the place.
 */
void Game_Prepare(void)
{
	PoolFindStruct find;
	uint16 oldSelectionType;
	Tile *t;
	int i;

	g_validateStrictIfZero++;

	oldSelectionType = g_selectionType;
	g_selectionType = SELECTIONTYPE_MENTAT;

	Structure_Recount();
	Unit_Recount();
	Team_Recount();

	t = &g_map[0];
	for (i = 0; i < 64 * 64; i++, t++) {
		Structure *s;
		Unit *u;

		u = Unit_Get_ByPackedTile(i);
		s = Structure_Get_ByPackedTile(i);

		if (u == NULL || !u->o.flags.s.used) t->hasUnit = false;
		if (s == NULL || !s->o.flags.s.used) t->hasStructure = false;
		if (t->isUnveiled) Map_UnveilTile(i, g_playerHouseID);
	}

	find.houseID = HOUSE_INVALID;
	find.index   = 0xFFFF;
	find.type    = 0xFFFF;

	while (true) {
		Unit *u;

		u = Unit_Find(&find);
		if (u == NULL) break;

		if (u->o.flags.s.isNotOnMap) continue;

		Unit_RemoveFog(u);
		Unit_UpdateMap(1, u);
	}

	find.houseID = HOUSE_INVALID;
	find.index   = 0xFFFF;
	find.type    = 0xFFFF;

	while (true) {
		Structure *s;

		s = Structure_Find(&find);
		if (s == NULL) break;
		if (s->o.type == STRUCTURE_SLAB_1x1 || s->o.type == STRUCTURE_SLAB_2x2 || s->o.type == STRUCTURE_WALL) continue;

		if (s->o.flags.s.isNotOnMap) continue;

		Structure_RemoveFog(s);

		if (s->o.type == STRUCTURE_STARPORT && s->o.linkedID != 0xFF) {
			Unit *u = Unit_Get_ByIndex(s->o.linkedID);

			if (!u->o.flags.s.used || !u->o.flags.s.isNotOnMap) {
				s->o.linkedID = 0xFF;
				s->countDown = 0;
			} else {
				Structure_SetState(s, STRUCTURE_STATE_READY);
			}
		}

		Script_Load(&s->o.script, s->o.type);

		if (s->o.type == STRUCTURE_PALACE) {
			House_Get_ByIndex(s->o.houseID)->palacePosition = s->o.position;
		}

		if ((House_Get_ByIndex(s->o.houseID)->palacePosition.x != 0) || (House_Get_ByIndex(s->o.houseID)->palacePosition.y != 0)) continue;
		House_Get_ByIndex(s->o.houseID)->palacePosition = s->o.position;
	}

	find.houseID = HOUSE_INVALID;
	find.index   = 0xFFFF;
	find.type    = 0xFFFF;

	while (true) {
		House *h;

		h = House_Find(&find);
		if (h == NULL) break;

		h->structuresBuilt = Structure_GetStructuresBuilt(h);
		House_UpdateCreditsStorage((uint8)h->index);
		House_CalculatePowerAndCredit(h);
	}

	GUI_Palette_CreateRemap(g_playerHouseID);

	Map_SetSelection(g_selectionPosition);

	if (g_structureActiveType != 0xFFFF) {
		Map_SetSelectionSize(g_table_structureInfo[g_structureActiveType].layout);
	} else {
		Structure *s = Structure_Get_ByPackedTile(g_selectionPosition);

		if (s != NULL) Map_SetSelectionSize(g_table_structureInfo[s->o.type].layout);
	}

	Voice_LoadVoices(g_playerHouseID);

	g_tickHousePowerMaintenance = max(g_timerGame + 70, g_tickHousePowerMaintenance);
	g_viewport_forceRedraw = true;
	g_playerCredits = 0xFFFF;

	g_selectionType = oldSelectionType;
	g_validateStrictIfZero--;
}
Exemplo n.º 6
0
/*performs common initialization of routes ISed fields and protos once everything is loaded*/
void proto_instanciate(ProtoInstance *proto_node)
{
	SFNode *node, *orig;
	Route *route, *r2;
	u32 i;
	PrototypeNode *proto = proto_node->proto_interface;
	PrototypeNode *owner = proto;

	if (!proto) return;

	if (owner->ExternProto.count) {
		LPSCENEGRAPH extern_lib;
		if (!owner->parent_graph->GetExternProtoLib) return;
		extern_lib = owner->parent_graph->GetExternProtoLib(proto->parent_graph->SceneCallback, &owner->ExternProto);
		if (!extern_lib) return;

		/*this is an hardcoded proto - all routes, node modifications and co are handled internally*/
		if (extern_lib == SG_INTERNAL_PROTO) {
			owner->parent_graph->UserNodeInit(owner->parent_graph->NodeInitCallback, (SFNode *) proto_node);
			return;
		}
		/*not loaded yet*/
		if (!ChainGetCount(extern_lib->protos)) return;

		/*overwrite this proto by external one*/
		proto = NULL;
		/*start with proto v2 addressing*/
		if (owner->ExternProto.vals[0].url) {
			u32 ID = -1;
			char *szName = strrchr(owner->ExternProto.vals[0].url, '#');
			if (szName) {
				szName++;
				if (sscanf(szName, "%d", &ID)) ID = -1;
			}
			proto = SG_FindProto(extern_lib, ID, szName);
		}
		if (!proto) proto = SG_FindProto(extern_lib, owner->ID, NULL);
		if (!proto) proto = SG_FindProtoByInterface(extern_lib, owner);
		/*couldn't find proto in the given lib, consider the proto as loaded (give up)*/
		if (!proto) {
			proto_node->is_loaded = 1;
			return;
		}

		/*unregister from prev and reg with real proto*/
		ChainDeleteItem(owner->instances, proto_node);
		ChainAddEntry(proto->instances, proto_node);
	}

	/*OVERRIDE the proto instance (eg don't instanciate an empty externproto...)*/
	proto_node->proto_interface = proto;

	/*clone all nodes*/
	for (i=0; i<ChainGetCount(proto->node_code); i++) {
		orig = ChainGetEntry(proto->node_code, i);
		/*node is cloned in the new scenegraph and its parent is NULL */
		node = SG_CloneNode(proto_node->sgprivate->scenegraph, orig, NULL);
		assert(node);

		/*assign first rendering node*/
		if (!i) proto_node->RenderingNode = node;
		ChainAddEntry(proto_node->node_code, node);
	}

	/*instantiate routes (not ISed ones)*/
	for (i=0; i<ChainGetCount(proto->sub_graph->Routes); i++) {
		route = ChainGetEntry(proto->sub_graph->Routes, i);
		if (route->IS_route) continue;

		r2 = SG_NewRoute(proto_node->sgprivate->scenegraph, 
				SG_FindNode(proto_node->sgprivate->scenegraph, route->FromNode->sgprivate->NodeID), 
				route->FromFieldIndex, 
				SG_FindNode(proto_node->sgprivate->scenegraph, route->ToNode->sgprivate->NodeID), 
				route->ToFieldIndex);

		if (route->ID) SG_SetRouteID(r2, route->ID);
		if (route->name) SG_SetRouteName(r2, route->name);
	}
	/*activate all ISed fields so that inits on events is properly done*/
	for (i=0; i<ChainGetCount(proto_node->sgprivate->scenegraph->Routes); i++) {
		route = ChainGetEntry(proto_node->sgprivate->scenegraph->Routes, i);
		if (route->IS_route) ActivateRoute(route);
	}
	/*and load all scripts (this must be done once all fields are routed for the "initialize" method)*/
	while (ChainGetCount(proto_node->scripts_to_load)) {
		node = ChainGetEntry(proto_node->scripts_to_load, 0);
		ChainDeleteEntry(proto_node->scripts_to_load, 0);
		Script_Load(node);
	}
	/*re-activate all ISed fields pointing to scripts once scripts are loaded (eventIns)*/
	for (i=0; i<ChainGetCount(proto_node->sgprivate->scenegraph->Routes); i++) {
		route = ChainGetEntry(proto_node->sgprivate->scenegraph->Routes, i);
		if (!route->IS_route || !route->ToNode) continue;
/*		assert(route->is_setup);
		if ((route->FromField.eventType == ET_EventOut) || (route->FromField.eventType == ET_EventIn) ) continue;
*/		if ((route->ToNode->sgprivate->tag==TAG_MPEG4_Script) || (route->ToNode->sgprivate->tag==TAG_X3D_Script) )
			ActivateRoute(route);
	}

	proto_node->is_loaded = 1;
}