btmux-0.6-rc4/doc/
btmux-0.6-rc4/event/
btmux-0.6-rc4/game/
btmux-0.6-rc4/game/maps/
btmux-0.6-rc4/game/mechs/
btmux-0.6-rc4/game/text/help/
btmux-0.6-rc4/game/text/help/cat_faction/
btmux-0.6-rc4/game/text/help/cat_inform/
btmux-0.6-rc4/game/text/help/cat_misc/
btmux-0.6-rc4/game/text/help/cat_mux/
btmux-0.6-rc4/game/text/help/cat_mux/cat_commands/
btmux-0.6-rc4/game/text/help/cat_mux/cat_functions/
btmux-0.6-rc4/game/text/help/cat_templates/
btmux-0.6-rc4/game/text/wizhelp/
btmux-0.6-rc4/include/
btmux-0.6-rc4/misc/
btmux-0.6-rc4/python/
btmux-0.6-rc4/src/hcode/btech/
btmux-0.6-rc4/tree/
/*
 * $Id: mech.c3.c,v 1.1.1.1 2005/01/11 21:18:11 kstevens Exp $
 *
 * Author: Cord Awtry <kipsta@mediaone.net>
 *
 *  Copyright (c) 2001 Cord Awtry
 *       All rights reserved
 */

#include "mech.h"
#include "mech.events.h"
#include "p.mech.c3.h"
#include "p.mech.c3.misc.h"
#include "p.mech.utils.h"
#include "p.mech.los.h"
#include "p.mech.contacts.h"

#define C3_POS_IN_NETWORK -1
#define C3_POS_NO_ROOM		-2

#define C3_MASTER_MECH_SIZE 5
#define C3_MASTER_OTHER_SIZE 1

int getC3MasterSize(MECH * mech)
{
	if(MechType(mech) == CLASS_MECH)
		return C3_MASTER_MECH_SIZE;
	else
		return C3_MASTER_OTHER_SIZE;
}

int isPartOfWorkingC3Master(MECH * mech, int section, int slot)
{
	int x = 0;
	int y, t;
	int wcWorkingSlots = 0;
	int wStartCheck = 0;
	int tDoBump;

	wStartCheck = MAX(0, slot - (getC3MasterSize(mech) - 1));

	while (x < CritsInLoc(mech, section)) {
		tDoBump = 0;

		if((t = GetPartType(mech, section, x))) {
			if(Special2I(t) == C3_MASTER) {
				if(x < wStartCheck) {
					tDoBump = 1;
				} else {
					/* We're within range of our slot, if not already on it */
					for(y = x; y < (x + getC3MasterSize(mech)); y++) {
						if(y != slot) {
							if(!PartIsNonfunctional(mech, section, y))
								wcWorkingSlots++;
						}
					}
				}
			}
		}

		if(tDoBump)
			x += getC3MasterSize(mech);
		else
			x++;
	}

	return (wcWorkingSlots == (getC3MasterSize(mech) - 1));
}

int countWorkingC3MastersOnMech(MECH * mech)
{
	int x, y, t;
	int wcSlots;
	int wcWorkingSlots;
	int wcMasters = 0;

	debugC3(tprintf("Counting working C3 masters for %d", mech->mynum));

	for(x = 0; x < NUM_SECTIONS; x++) {
		wcSlots = 0;
		wcWorkingSlots = 0;

		for(y = 0; y < CritsInLoc(mech, x); y++) {
			if((t = GetPartType(mech, x, y))) {
				if(Special2I(t) == C3_MASTER) {
					debugC3(tprintf
							("...found a C3Master slot at section %d, slot %d on %d.",
							 x, y, mech->mynum));

					wcSlots++;

					if(!PartIsNonfunctional(mech, x, y)) {
						debugC3("......and the slot is functional.");
						wcWorkingSlots++;
					}
				}
			}

			if(wcSlots == getC3MasterSize(mech)) {
				debugC3(tprintf
						("...found enough slots for a C3Master for %d.",
						 mech->mynum));
				wcSlots = 0;

				if(wcWorkingSlots == getC3MasterSize(mech)) {
					debugC3(tprintf
							("...there is even enough working slots to make the computer work on %d.",
							 mech->mynum));
					wcMasters++;
				}
			}
		}
	}

	debugC3(tprintf("Found %d working C3 masters on %d", wcMasters,
					mech->mynum));

	return wcMasters;
}

int countTotalC3MastersOnMech(MECH * mech)
{
	int x, y, t;
	int wcSlots;
	int wcMasters = 0;

	debugC3(tprintf("Counting total C3 masters for %d", mech->mynum));

	for(x = 0; x < NUM_SECTIONS; x++) {
		wcSlots = 0;

		for(y = 0; y < CritsInLoc(mech, x); y++) {
			if((t = GetPartType(mech, x, y))) {
				if(Special2I(t) == C3_MASTER) {
					debugC3(tprintf
							("...found a C3Master slot at section %d, slot %d on %d.",
							 x, y, mech->mynum));

					wcSlots++;
				}
			}

			if(wcSlots == getC3MasterSize(mech)) {
				debugC3(tprintf
						("...found enough slots for a C3Master for %d.",
						 mech->mynum));

				wcSlots = 0;
				wcMasters++;
			}
		}
	}

	debugC3(tprintf("Found %d total C3 masters on %d", wcMasters,
					mech->mynum));

	return wcMasters;
}

int countMaxC3Units(MECH * mech, dbref * myTempNetwork,
					int tempNetworkSize, MECH * targMech)
{
	dbref otherRef;
	MECH *otherMech;
	int i;
	int wcC3Masters = 0;
	int myMasters = 0;
	int maxC3Size;

	debugC3(tprintf("Counting max C3 units in %d's network", mech->mynum));

	if(targMech)
		debugC3(tprintf("...using %d as an additional mech",
						targMech->mynum));

	/* First we iterate over the list and find all the masters */
	for(i = 0; i < tempNetworkSize; i++) {
		otherRef = myTempNetwork[i];
		otherMech = getMech(otherRef);

		if(!otherMech)
			continue;

		wcC3Masters += MechWorkingC3Masters(otherMech);

		debugC3(tprintf("...for %d, we add %d masters", otherMech->mynum,
						MechWorkingC3Masters(otherMech)));
	}

	/* Let's find out the max number of mechs in this network. Make sure we add in any slaves we can control */
	maxC3Size = (wcC3Masters * 4) - wcC3Masters;

	debugC3(tprintf("...we now have a max size of %d", maxC3Size));

	myMasters = MechWorkingC3Masters(mech);

	if(myMasters > 0)
		maxC3Size += (myMasters * 4) - myMasters;

	debugC3(tprintf
			("...and after adding in my masters, we now have a max size of %d",
			 maxC3Size));

	/* Let's see if a 2nd mech has been supplied to us */
	if(targMech) {
		myMasters = MechWorkingC3Masters(targMech);

		if(myMasters > 0)
			maxC3Size += (myMasters * 4) - myMasters;
	}

	maxC3Size = MIN(maxC3Size, 11);

	debugC3(tprintf("...final max size of %d", maxC3Size));

	return maxC3Size;
}

int trimC3Network(MECH * mech, dbref * myTempNetwork, int tempNetworkSize)
{
	dbref otherRef;
	MECH *otherMech;
	int i;
	int newNetworkSize;
	int maxC3Size = 0;			/* This is calc'd based on the number of masters */
	dbref newNetwork[C3_NETWORK_SIZE];

	debugC3(tprintf("C3 TRIM: Trimming %d's C3 network", mech->mynum));

	/* Initialize our data */
	newNetworkSize = tempNetworkSize;

	for(i = 0; i < C3_NETWORK_SIZE; i++)
		newNetwork[i] = -1;

	/* Get our count of max units */
	maxC3Size = countMaxC3Units(mech, myTempNetwork, tempNetworkSize, NULL);

	debugC3(tprintf("C3 TRIM: Max C3 size: %d", maxC3Size));
	debugC3(tprintf("C3 TRIM: Current C3 size: %d", tempNetworkSize));

	/* Now we see if our network is oversized */
	if(maxC3Size < tempNetworkSize) {
		newNetworkSize = 0;

		/* First put our masters in */
		for(i = 0; i < tempNetworkSize; i++) {
			otherRef = myTempNetwork[i];
			otherMech = getMech(otherRef);

			if(!otherMech)
				continue;

			if(MechWorkingC3Masters(otherMech) > 0)
				newNetwork[newNetworkSize++] = otherRef;
		}

		/* Next we put in slaves up to the max amount */
		if(newNetworkSize < maxC3Size) {
			for(i = 0; i < tempNetworkSize; i++) {
				otherRef = myTempNetwork[i];
				otherMech = getMech(otherRef);

				if(!otherMech)
					continue;

				if(MechWorkingC3Masters(otherMech) == 0)
					newNetwork[newNetworkSize++] = otherRef;

				if(newNetworkSize >= maxC3Size)
					break;
			}
		}

		/* Now, refill our other temp network */
		for(i = 0; i < newNetworkSize; i++)
			myTempNetwork[i] = newNetwork[i];
	}

	return newNetworkSize;
}

int getFreeC3NetworkPos(MECH * mech, MECH * mechToAdd)
{
	int i;
	dbref otherRef;

	validateC3Network(mech);

	for(i = 0; i < C3_NETWORK_SIZE; i++) {
		otherRef = MechC3NetworkElem(mech, i);

		if(otherRef > 0) {
			if(otherRef == mechToAdd->mynum)
				return C3_POS_IN_NETWORK;
		} else
			return i;
	}

	return C3_POS_NO_ROOM;
}

void replicateC3Network(MECH * mechSrc, MECH * mechDest)
{
	int i;
	dbref otherRef;

	debugC3(tprintf("C3 REPLICATE: %d's C3 network to %d",
					mechSrc->mynum, mechDest->mynum));

	clearC3Network(mechDest, 0);

	MechC3NetworkElem(mechDest, 0) = mechSrc->mynum;
	MechC3NetworkSize(mechDest) = 1;

	for(i = 0; i < C3_NETWORK_SIZE; i++) {
		otherRef = MechC3NetworkElem(mechSrc, i);

		if(otherRef != mechDest->mynum) {
			MechC3NetworkElem(mechDest, MechC3NetworkSize(mechDest)) =
				otherRef;
			MechC3NetworkSize(mechDest) += 1;
		}
	}

	validateC3Network(mechDest);
}

void addMechToC3Network(MECH * mech, MECH * mechToAdd)
{
	MECH *otherMech;
	MECH *otherNotifyMech;
	dbref otherRef;
	int i;
	int wPos = -1;

	debugC3(tprintf("C3 ADD: %d to the C3 network of %d",
					mechToAdd->mynum, mech->mynum));

	/* Find a position to add the new mech into my network */
	wPos = getFreeC3NetworkPos(mech, mechToAdd);

	/* If we have a number that's less than 0, then we have an invalid position. Either we're already in the network or there's not enough room */
	if(wPos < 0)
		return;

	/* Well, we have a valid position, so let's put this mech in the network */
	debugC3(tprintf("C3 ADD: Position to add to %d's network is %d",
					mech->mynum, wPos));

	MechC3NetworkElem(mech, wPos) = mechToAdd->mynum;
	MechC3NetworkSize(mech) += 1;

	mech_notify(mech, MECHALL,
				tprintf("%s connects to your C3 network.",
						GetMechToMechID(mech, mechToAdd)));

	/* Now let's replicate the new network across the system so that everyone has the same network settings */
	for(i = 0; i < C3_NETWORK_SIZE; i++) {
		otherRef = MechC3NetworkElem(mech, i);

		otherMech = getOtherMechInNetwork(mech, i, 0, 0, 0, 1);

		if(!otherMech)
			continue;

		if(!Good_obj(otherMech->mynum))
			continue;

		if(otherRef != mechToAdd->mynum) {
			otherNotifyMech = getOtherMechInNetwork(mech, i, 1, 1, 1, 1);

			if(otherNotifyMech)
				mech_notify(otherNotifyMech, MECHALL,
							tprintf("%s connects to your C3 network.",
									GetMechToMechID(otherNotifyMech,
													mechToAdd)));
		}

		replicateC3Network(mech, otherMech);
	}

	/* Last, but not least, one final validation of the network */
	validateC3Network(mech);
}

void clearMechFromC3Network(dbref refToClear, MECH * mech)
{
	int i;

	debugC3(tprintf("C3 CLEAR: %d from the C3 network of %d", refToClear,
					mech->mynum));

	if(!MechC3NetworkSize(mech))
		return;

	for(i = 0; i < C3_NETWORK_SIZE; i++) {
		if(MechC3NetworkElem(mech, i) == refToClear)
			MechC3NetworkElem(mech, i) = -1;
	}

	validateC3Network(mech);
}

void clearC3Network(MECH * mech, int tClearFromOthers)
{
	MECH *otherMech;
	int i;

	debugC3(tprintf("C3 CLEAR: %d's C3 network", mech->mynum));

	for(i = 0; i < C3_NETWORK_SIZE; i++) {
		otherMech = getOtherMechInNetwork(mech, i, 0, 0, 0, 1);

		MechC3NetworkElem(mech, i) = -1;

		if(tClearFromOthers) {
			if(!otherMech)
				continue;

			if(!Good_obj(otherMech->mynum))
				continue;

			clearMechFromC3Network(mech->mynum, otherMech);
		}
	}

	MechC3NetworkSize(mech) = 0;
}

void validateC3Network(MECH * mech)
{
	MECH *otherMech;
	dbref myTempNetwork[C3_NETWORK_SIZE];
	int i;
	int networkSize = 0;

	debugC3(tprintf("C3 VALIDATE: %d's C3 network", mech->mynum));

	if(!HasC3(mech) || Destroyed(mech) || C3Destroyed(mech)) {
		clearC3Network(mech, 1);

		return;
	}

	if(MechC3NetworkSize(mech) < 0) {
		clearC3Network(mech, 1);

		return;
	}

	for(i = 0; i < C3_NETWORK_SIZE; i++) {
		otherMech = getOtherMechInNetwork(mech, i, 0, 0, 0, 1);

		if(!otherMech)
			continue;

		if(!Good_obj(otherMech->mynum))
			continue;

		debugC3(tprintf("C3 VALIDATE INFO: %d is now in %d's C3 network",
						otherMech->mynum, mech->mynum));

		myTempNetwork[networkSize] = otherMech->mynum;
		networkSize++;
	}

	clearC3Network(mech, 0);

	for(i = 0; i < networkSize; i++)
		MechC3NetworkElem(mech, i) = myTempNetwork[i];

	MechC3NetworkSize(mech) = networkSize;

	debugC3(tprintf
			("C3 VALIDATE INFO: (PreTrim) %d's C3 network is %d elements",
			 mech->mynum, MechC3NetworkSize(mech)));

	networkSize = trimC3Network(mech, myTempNetwork, networkSize);

	debugC3(tprintf
			("C3 VALIDATE INFO: (PostTrim) %d's C3 network has been trimmed to %d elements",
			 mech->mynum, networkSize));

	if(networkSize != MechC3NetworkSize(mech)) {
		clearC3Network(mech, 0);

		for(i = 0; i < networkSize; i++)
			MechC3NetworkElem(mech, i) = myTempNetwork[i];

		MechC3NetworkSize(mech) = networkSize;
	}

}

void mech_c3_join_leave(dbref player, void *data, char *buffer)
{
	MECH *mech = (MECH *) data, *target;
	MAP *objMap;
	char *args[2];
	dbref refTarget;
	int LOS = 1;
	float range = 0.0;
	int maxC3Size = 0;

	cch(MECH_USUALO);

	DOCHECK(mech_parseattributes(buffer, args, 2) != 1,
			"Invalid number of arguments to function!");

	DOCHECK(!HasC3(mech), "This unit is not equipped with C3!");
	DOCHECK(C3Destroyed(mech), "Your C3 system is destroyed!");
	DOCHECK(AnyECMDisturbed(mech),
			"Your C3 system is not currently operational!");

	validateC3Network(mech);

	/* Clear our C3 Network */
	if(!strcmp(args[0], "-")) {
		if(MechC3NetworkSize(mech) <= 0) {
			mech_notify(mech, MECHALL,
						"You are not connected to a C3 network!");

			return;
		}

		clearC3Network(mech, 1);

		mech_notify(mech, MECHALL, "You disconnect from the C3 network.");

		return;
	}

	/* Well, if we're here then we wanna connect to a network */
	/* Let's check to see if we're already in one... can't be in two at the same time */
	DOCHECK(MechC3NetworkSize(mech) > 0, "You are already in a C3 network!");

	objMap = getMap(mech->mapindex);

	/* Find who we're trying to connect to */
	refTarget = FindTargetDBREFFromMapNumber(mech, args[0]);
	target = getMech(refTarget);

	if(target)
		LOS =
			InLineOfSight(mech, target, MechX(target), MechY(target), range);
	else
		refTarget = 0;

	DOCHECK((refTarget < 1) ||
			!LOS, "That is not a valid targetID. Try again.");
	DOCHECK(MechTeam(mech) != MechTeam(target),
			"You can't use the C3 network of unfriendly units!");
	DOCHECK(mech->mynum == target->mynum, "You can't connect to yourself!");
	DOCHECK(Destroyed(target), "That unit is destroyed!");
	DOCHECK(!Started(target), "That unit is not started!");
	DOCHECK(!HasC3(target),
			"That unit does not appear to be equipped with C3!");

	/* validate the network of our target */
	validateC3Network(target);

	/* Let's see how much can actually fit in this network, based on the number of masters and slaves */
	maxC3Size =
		countMaxC3Units(mech, MechC3Network(target),
						MechC3NetworkSize(target), target);

	DOCHECK(maxC3Size < (MechC3NetworkSize(target) + 1),
			"That unit's C3 network is operating at maximum capacity!");

	/* Connect us up */
	mech_notify(mech, MECHALL, tprintf("You connect to %s's C3 network.",
									   GetMechToMechID(mech, target)));

	addMechToC3Network(target, mech);
}

void mech_c3_message(dbref player, MECH * mech, char *buffer)
{
	cch(MECH_USUALO);

	DOCHECK(!HasC3(mech), "This unit is not equipped with C3!");
	DOCHECK(C3Destroyed(mech), "Your C3 system is destroyed!");
	DOCHECK(AnyECMDisturbed(mech),
			"Your C3 system is not currently operational!");

	validateC3Network(mech);

	DOCHECK(MechC3NetworkSize(mech) <= 0,
			"There are no other units in your C3 network!");

	skipws(buffer);
	DOCHECK(!*buffer, "What do you want to send on the C3 Network?");

	sendNetworkMessage(player, mech, buffer, 1);
}

void mech_c3_targets(dbref player, MECH * mech, char *buffer)
{
	cch(MECH_USUALO);

	DOCHECK(!HasC3(mech), "This unit is not equipped with C3!");
	DOCHECK(C3Destroyed(mech), "Your C3 system is destroyed!");
	DOCHECK(AnyECMDisturbed(mech),
			"Your C3 system is not currently operational!");

	validateC3Network(mech);

	DOCHECK(MechC3NetworkSize(mech) <= 0,
			"There are no other units in your C3 network!");

	showNetworkTargets(player, mech, 1);
}

void mech_c3_network(dbref player, MECH * mech, char *buffer)
{
	cch(MECH_USUALO);

	DOCHECK(!HasC3(mech), "This unit is not equipped with C3!");
	DOCHECK(C3Destroyed(mech), "Your C3 system is destroyed!");
	DOCHECK(AnyECMDisturbed(mech),
			"Your C3 system is not currently operational!");

	validateC3Network(mech);

	DOCHECK(MechC3NetworkSize(mech) <= 0,
			"There are no other units in your C3 network!");

	showNetworkData(player, mech, 1);
}