dawn/notes/
dawn/src/
dawn/src/docs/
/**************************************************************************/
// pload.cpp - dawn player loading/unloading system
/***************************************************************************
 * The Dawn of Time v1.69r (c)1997-2004 Michael Garratt                    *
 * >> A number of people have contributed to the Dawn codebase, with the   *
 *    majority of code written by Michael Garratt - www.dawnoftime.org     *
 * >> To use this source code, you must fully comply with the dawn license *
 *    in licenses.txt... In particular, you may not remove this copyright  *
 *    notice.                                                              *
 **************************************************************************/

#include "include.h"
#include "pload.h"

void extract_char_from_char_list(char_data *ch);
int ploaded_players_in_realm=0;
/**************************************************************************/
char_data *pload_find_player_by_name(char *name)
{
	// the following lines are an optimisation so everytime a player
	// logs in we don't have to search every player in every room
	if(ploaded_players_in_realm<=0){
		return NULL;
	}

	// loop thru all players in all rooms looking for ploaded players
	int i;
	ROOM_INDEX_DATA *pRoomIndex;

	for(i=0; i<MAX_KEY_HASH; i++){
		for ( pRoomIndex  = room_index_hash[i];pRoomIndex;pRoomIndex = pRoomIndex->next ){
			for(char_data *lch=pRoomIndex->people; lch; lch=lch->next_in_room){
				if(lch->pload && !IS_NPC(lch)){
					if(!str_cmp(name, lch->name)){
						return lch;
					}
				}
			}
		}
	}
	// unfound
	return NULL;
}
/**************************************************************************/
// extract a ploaded player, without saving them
void pload_extract(char_data *ch, char_data *victim)
{
	if(!victim){
		ch->println("pload_extract(): bug, victim is NULL!");
		logf("pload_extract(): bug, victim is NULL!");
		return;
	}

	if(!victim->pload){
		ch->println("pload_extract(): victim->pload is NULL!");
		logf("pload_extract(): victim->pload is NULL!");
		return;
	}

	char_from_room(victim);	
	if(victim->pet){
		char_from_room(victim->pet);
	}
	
	if(victim->pload->loaded_by && victim->pload->loaded_by!=ch){
		victim->pload->loaded_by->printlnf("`YPloaded character '%s' has been unloaded by '%s'`x",
			PERS(victim, victim->pload->loaded_by),
			ch?PERS(ch, victim->pload->loaded_by):"player login?!?");
	}

	ch->printlnf("Ploaded character '%s' has been unloaded.", PERS(victim, ch));

	// deallocate the pload relationship recording
	if(victim->pload->loaded_by){
		victim->pload->loaded_by->ploaded=NULL;
		victim->pload->loaded_by=NULL;
		delete victim->pload;
		victim->pload=NULL;
	}
	if(victim->pet){
		if(victim->pet->pload){
			delete victim->pet->pload;
			victim->pet->pload=NULL;
		}
		free_char( victim->pet );
	}
	free_char( victim ); 

	ploaded_players_in_realm--;
}
/**************************************************************************/
void do_goto( char_data *ch, char *argument );
/**************************************************************************/
// Kal - Dec 2001
void do_pload(char_data *ch, char *argument )
{	
	char_data *lch;

	if(IS_NPC(ch) || ch->pload){
		ch->println("live players only sorry.");
		return;
	}

	char arg[MIL];
	char name[MIL];
	argument=one_argument(argument, arg);
	one_argument(argument, name);
	
	if(IS_NULLSTR(arg)){
		ch->titlebar("PLAYER LOAD SYNTAX AND NOTES");
		ch->println("syntax: pload load <playername>   - load a player");
		ch->println("syntax: pload unload <playername> - removes a ploaded player");
		ch->println("syntax: pload save <playername>   - saves a ploaded player pfile");
		ch->println("syntax: pload list <playername>   - lists all currently ploaded players");

		ch->println("");
		ch->println("`xNotes about a ploaded player:");
		ch->println("* Any changes you do to the player will NOT be saved,\r\n"
					"  unless you use the `=Cpload save`x command");
		ch->println("* The 'unload' option does NOT save the ploaded players pfile.");
		ch->println("* Ploaded players can not be seen by mortals");
		ch->println("* Time does NOT pass for the player, so affect durations will be unaffected");
		ch->println("* The player will automatically be unloaded (without saving) when you logout.");
		ch->println("* The player will automatically be unloaded (without saving)\r\n"
					"  if they try to login and get their password correct.");
		ch->println("* Ploaded players are put in limbo by default, if you move them from this\r\n"
					"  room and 'pload save' them, they will appear in the new room next login");
		ch->println("* A players ploaded login is not recorded in laston.");
		ch->println("* A players login time, site and hours played remain what\r\n"
					"  they were with their last normal login.");
		ch->println("* Ploaded players are not transfered nor saved for a hotreboot.");
		ch->println("* Often the ploaded player can only be located while in the same\r\n"
					"  room as it, or using the 'pload list' command.");
		ch->println("* With some functions, ploaded player names must be used in full.");
		ch->titlebar("");
		return;
	}

	// load option
	if(!str_cmp(arg,"load")){
		connection_data d;
		memset(&d, 0, sizeof(d));
		d.make_connected_socket_invalid();
		bool pfile_loaded_okay;

		if(IS_NULLSTR(name)){
			do_pload(ch,""); // show the help - incomplete syntax
			return;
		}

		ROOM_INDEX_DATA *limbo=get_room_index( ROOM_VNUM_LIMBO );
		assertp(limbo); // should be impossible to not have a limbo room

		// imms must be in the limbo room to pload players
		if(ch->in_room!=limbo){
			ch->printlnf("You must be in limbo (room %d) to load players with pload.",
				ROOM_VNUM_LIMBO);
			ch->println("Moving you to limbo for the pload.");
			interpret(ch, FORMATF("goto %d",ROOM_VNUM_LIMBO));
			if(ch->in_room!=limbo){
				ch->printlnf("The command 'goto %d' failed to get you to limbo, manually goto limbo then retry pload.",
					ROOM_VNUM_LIMBO);
				return;
			}
		}

		// can't pload more than one at a time.
		if(ch->ploaded){
			ch->printlnf("You have already ploaded '%s' who is in room %d.",
				ch->ploaded->name, ch->ploaded->in_room->vnum);
			return;
		}

		// confirm no player is in the game with exactly that name
		for( lch = player_list; lch; lch = lch->next_player ){
			if(!str_cmp(lch->name, name)){
				if(can_see_who(ch, lch)){
					ch->printlnf("'%s' is already within the game.", name);
				}else{
					ch->printlnf("'%s' is above your level/trust - you can not pload him/her.", name);
				}
				return;
			}
		}

		// confirm that character isn't ploaded by someone else
		if(pload_find_player_by_name(name)){
			ch->printlnf("'%s' is already ploaded by someone else.", name);
			do_pload(ch,"list");
			return;
		}
		
		// attempt to load the pfile
		pfile_loaded_okay= load_char_obj( &d, name );

		if(!pfile_loaded_okay || !d.character){
			ch->printlnf("Couldn't load pfile '%s'.", name);
			return;
		}

		// pfile loaded, check if they are above the trust/level of the loader
		lch=d.character;
		d.character->desc=NULL;
		if(lch->pet){
			// remove pets from the char_list 
			extract_char_from_char_list(lch->pet);			
		}

		if(get_trust(ch)<=get_trust(lch)){
			// notice that this message should be the same as the one above, if the loader
			// cant see the loaded person when they are already in the game
			ch->printlnf("'%s' is above your level/trust - you can not pload him/her.", name);

			// deallocate the loaded character data
			if(lch->pet){
				free_char( lch->pet );
			}
			free_char( lch );
			return;
		}

		// === By This Stage:
		// * we have loaded the pfile data into lch
		// * lch->in_room is set to the room the player would normally be loaded into
		// * if they have a pet:
		//   - pet is read into lch->pet, 
		//   - lch->pet->in_room is set to the room the pet would normally be loaded into
		
		// Transfer the player into the limbo room, save the was_in_room field first though
		// as this simulates the affect of the player going idle and being transfered to
		// limbo naturally... as a result when the player is saved, they will be saved in their 
		// original room.
		
		lch->was_in_room=lch->in_room;
		char_to_room(lch, limbo);

		ch->printlnf("Character %s ploaded - original room %d.", 
			PERS(lch, ch), lch->was_in_room?lch->was_in_room->vnum:-1);
		logf("Character '%s' ploaded - will save in original room (%d).", 
			PERS(lch, NULL), lch->was_in_room?lch->was_in_room->vnum:-1);

		if(lch->pet){
			lch->pet->was_in_room=lch->pet->in_room;
			char_to_room(lch->pet, limbo);
			ch->printlnf("Pet '%s' belonging to %s ploaded - original room %d.", 
				PERS(lch->pet, ch), PERS(lch, ch), lch->pet->was_in_room?lch->pet->was_in_room->vnum:-1);
			logf("Pet '%s' belonging to %s ploaded - original room vnum %d.", 
				PERS(lch->pet, NULL), PERS(lch, NULL), lch->pet->was_in_room?lch->pet->was_in_room->vnum:-1);
		}

		// record the pload relationship
		ch->ploaded=lch; 
		lch->pload=new pload_data;
		lch->pload->dont_save=true; // we dont want the pfile saved
		lch->pload->loaded_by=ch;
		lch->next=NULL;
		lch->next_player=NULL;
		ploaded_players_in_realm++;
		if(lch->pet){
			lch->pet->pload=new pload_data;
			lch->pet->pload->loaded_by=NULL;
			lch->pet->next=NULL;
			lch->pet->next_player=NULL;
		}
		
		// NOTE: neither pets nor characters are within the player_list or character_list
		//       This is intentional - so they arent affected by char_update() etc
		return;
	}


	// unload option
	if(!str_cmp(arg,"unload")){
		if(IS_NULLSTR(name)){
			do_pload(ch,""); // show the help - incomplete syntax
			return;
		}

		lch=get_char_room(ch, name);

		if(!lch){
			ch->printlnf("There is no ploaded player '%s' to unload from this room.", name);
			return;
		}

		if(IS_NPC(lch)){
			ch->printlnf("'%s' is an NPC, you can't use pload to unload them.", name);
			return;
		}

		if(!lch->pload){
			ch->printlnf("'%s' was not ploaded, so you can't unload him/her.", name);
			return;
		}

		pload_extract(ch, lch);
		return;
	}

	// save option
	if(!str_cmp(arg,"save")){
		if(IS_NULLSTR(name)){
			do_pload(ch,""); // show the help - incomplete syntax
			return;
		}

		lch=get_char_room(ch, name);

		if(!lch){
			ch->wraplnf("There is no ploaded player '%s' to save in this room "
				"(you must be in the same room as a ploaded player to save them).", name);
			do_pload(ch,"list");
			return;
		}

		if(IS_NPC(lch)){
			ch->printlnf("'%s' is an NPC, you can't use pload to save them.", name);
			return;
		}

		if(!lch->pload){
			ch->printlnf("'%s' was not ploaded, so you can't save him/her.", name);
			return;
		}

		lch->pload->dont_save=false; // we dont want the pfile saved
		save_char_obj(lch);
		lch->pload->dont_save=true; // we dont want the pfile saved
		ch->printlnf("saved ploaded player '%s'", lch->name);
		logf("saved ploaded player '%s'", lch->name);
		return;
	}

	// list option
	if(!str_cmp(arg,"list")){
		ROOM_INDEX_DATA *limbo=get_room_index( ROOM_VNUM_LIMBO );
		assertp(limbo); // should be impossible to not have a limbo room
		// loop thru all players in all rooms looking for ploaded players
		int i;
		int count=0;
		int pccount=0;
		ROOM_INDEX_DATA *pRoomIndex;

		for(i=0; i<MAX_KEY_HASH; i++){
			for ( pRoomIndex  = room_index_hash[i];pRoomIndex;pRoomIndex = pRoomIndex->next ){
				for(lch=pRoomIndex->people; lch; lch=lch->next_in_room){
					if(lch->pload){
						ch->printf("[%d] %s in room %d ", 
							++count,
							PERS(lch, ch),
							pRoomIndex->vnum);

						if(lch->in_room==limbo && lch->was_in_room){
							ch->printf("[save room %d] ", lch->was_in_room->vnum);
						}else{
							ch->printf("[save room %d] ", lch->in_room->vnum);
						}

						if(lch->pload->loaded_by){
							ch->printlnf("(loaded by %s)", PERS(lch->pload->loaded_by, ch));
						}else{
							if(IS_NPC(lch) && lch->master && lch->master->pet==lch){
								ch->printlnf("(pet of %s)", PERS(lch->master, ch));
							}else{
								ch->println("(loaded by unknown)");
							}
						}
						if(!IS_NPC(lch)){
							pccount++;
						}
					}
				}
			}
		}
		if(count==0){
			ch->println("There are no ploaded players in the game");
		}
		if(pccount!=ploaded_players_in_realm){
			logf("do_pload(): bug - count!=ploaded_players_in_realm!!!");
			ch->println("do_pload(): bug - count!=ploaded_players_in_realm!!!");
		}
		return;
	}

	ch->printlnf("Unknown pload command '%s'", arg);
	do_pload(ch, "");

}
/**************************************************************************/
// Kal, Aug 02
void do_undeny( char_data *ch, char *argument )
{
	if(IS_NULLSTR(argument)){
		ch->println("syntax: undeny <playername>");
		ch->println("This command is really a macro for:`1"
			" pload load <playername>`1"
			" undeny <playername>`1"
			" pload save <playername>`1"
			" pload unload <playername>");
		return;
	}
	char_data *victim;

	// check the player isn't already around
	victim=get_whovis_player_world(ch, argument);
	if(victim){
		ch->printlnf("player '%s' is already in the game.", argument);
		return;
	}
	victim=pload_find_player_by_name(argument);
	if(victim){
		ch->printlnf("ploaded player by name '%s' already in the game.", argument);
		return;
	}

	// backup the room they are already in
	room_index_data *rm=ch->in_room;
	ROOM_INDEX_DATA *limbo=get_room_index( ROOM_VNUM_LIMBO );
	assertp(limbo); // should be impossible to not have a limbo room

	ch->println("UNDENY BEGINS");
	// imms must be in the limbo room to pload players
	if(rm!=limbo){
		ch->println("Moving you to limbo for the pload.");
		char_from_room(ch);
		char_to_room(ch, limbo);
	}


	
	ch->println("Ploading victim.");
	interpret(ch, FORMATF("pload load %s", argument));

	victim=pload_find_player_by_name(argument);
	if(!victim || IS_NPC(victim)){
		ch->println("Something went wrong with the pload, victim not found");
		ch->println("Punloading victim.");
		interpret(ch, FORMATF("pload unload %s", argument));
		if(ch->in_room!=rm){
			ch->println("Returning you to old room.");
			char_from_room(ch);
			char_to_room(ch, rm);
		}
		ch->println("UNDENY ABORTED");
		return;
	}

	if(!IS_SET(victim->act, PLR_DENY)){
		ch->println("VICTIM IS NOT CURRENTLY DENIED!");
		ch->println("Punloading victim.");
		interpret(ch, FORMATF("pload unload %s", argument));
		if(ch->in_room!=rm){
			ch->println("Returning you to old room.");
			char_from_room(ch);
			char_to_room(ch, rm);
		}
		ch->println("UNDENY ABORTED");
		return;	
	}

	REMOVE_BIT(victim->act, PLR_DENY);
	ch->println("DENY FLAG REMOVED FROM VICTIM.");

	ch->println("Saving victim.");
	interpret(ch, FORMATF("pload save %s", argument));

	ch->println("Punloading victim.");
	interpret(ch, FORMATF("pload unload %s", argument));
	
	if(ch->in_room!=rm){
		ch->println("Returning you to old room.");
		char_from_room(ch);
		char_to_room(ch, rm);
	}
	ch->println("UNDENY FINISHED");
}

/**************************************************************************/
/**************************************************************************/