Feature fixes & enhancements.

*Adds LOG_FEATURE (--debug feature) so we can keep track of features.

*Disallow VTOLs from being able to poach features.

*Changes feature spawning from instant to a variable time period.

*When feature can't be placed, break out of routine instead of sending invalid data.

*Actually remove features, and notify others that the feature was removed. (AKA, actually sync between machines.)

ASSERT() when numNaybors is invalid.
Fix a spamming debug line mistakenly changed in r6677


git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@6737 4a71c877-e1ca-e34f-864e-861f7616d084
master
Buginator 2009-02-28 03:36:26 +00:00
parent df0ada9a50
commit fc8bbc5bd9
7 changed files with 70 additions and 19 deletions

View File

@ -74,6 +74,7 @@ static const char *code_part_names[] = {
"gateway", "gateway",
"message", "message",
"terrain", "terrain",
"feature",
"last" "last"
}; };

View File

@ -139,6 +139,7 @@ typedef enum {
LOG_GATEWAY, LOG_GATEWAY,
LOG_MSG, LOG_MSG,
LOG_TERRAIN, LOG_TERRAIN,
LOG_FEATURE,
LOG_LAST /**< _must_ be last! */ LOG_LAST /**< _must_ be last! */
} code_part; } code_part;

View File

@ -254,6 +254,7 @@ FEATURE * buildFeature(FEATURE_STATS *psStats, UDWORD x, UDWORD y,BOOL FromSave)
FEATURE* psFeature = createFeature(); FEATURE* psFeature = createFeature();
if (psFeature == NULL) if (psFeature == NULL)
{ {
debug(LOG_WARNING, "Feature couldn't be built.");
return NULL; return NULL;
} }
// features are not in the cluster system // features are not in the cluster system

View File

@ -2912,7 +2912,11 @@ static void checkLocalFeatures(DROID *psDroid)
{ {
SDWORD i; SDWORD i;
BASE_OBJECT *psObj; BASE_OBJECT *psObj;
static int oilTimer = 0;
static bool GenerateDrum = false;
static uint8_t drumCount = 0;
// NOTE: Why not do this for AI units also?
// only do for players droids. // only do for players droids.
if(psDroid->player != selectedPlayer) if(psDroid->player != selectedPlayer)
{ {
@ -2920,7 +2924,7 @@ static void checkLocalFeatures(DROID *psDroid)
} }
droidGetNaybors(psDroid);// update naybor list. droidGetNaybors(psDroid);// update naybor list.
ASSERT( numNaybors <= MAX_NAYBORS, "numNaybors is %d, out of range of %d!", numNaybors, MAX_NAYBORS);
// scan the neighbours // scan the neighbours
for(i=0; i<(SDWORD)numNaybors; i++) for(i=0; i<(SDWORD)numNaybors; i++)
{ {
@ -2928,26 +2932,43 @@ static void checkLocalFeatures(DROID *psDroid)
psObj = asDroidNaybors[i].psObj; psObj = asDroidNaybors[i].psObj;
if ( psObj->type != OBJ_FEATURE if ( psObj->type != OBJ_FEATURE
|| ((FEATURE *)psObj)->psStats->subType != FEAT_OIL_DRUM || ((FEATURE *)psObj)->psStats->subType != FEAT_OIL_DRUM
|| asDroidNaybors[i].distSqr >= DROIDDIST ) || asDroidNaybors[i].distSqr >= DROIDDIST
|| isVtolDroid(psDroid)) // VTOLs can't pick up features!
{ {
// object too far away to worry about // object too far away to worry about
continue; continue;
} }
if(bMultiPlayer && (psObj->player == ANYPLAYER)) if(bMultiPlayer && (psObj->player == ANYPLAYER))
{ {
giftPower(ANYPLAYER,selectedPlayer,true); // give power and tell everyone. giftPower(ANYPLAYER,selectedPlayer,true); // give power and tell everyone.
addOilDrum(1); // when player finds oil, we init the timer, and flag that we need a drum
if (!oilTimer)
{
oilTimer = gameTime2;
GenerateDrum = true;
}
// if player finds more than one drum (before timer expires), then we tack on ~50 sec to timer.
if(drumCount++)
{
oilTimer += GAME_TICKS_PER_SEC * 50;
}
} }
else else
{ {
addPower(selectedPlayer,OILDRUM_POWER); addPower(selectedPlayer,OILDRUM_POWER);
CONPRINTF(ConsoleString,(ConsoleString,_("You found %u power in an oil drum"),OILDRUM_POWER)); CONPRINTF(ConsoleString,(ConsoleString,_("You found %u power in an oil drum."),OILDRUM_POWER));
} }
removeFeature((FEATURE*)psObj); // remove artifact+ send multiplay info. removeFeature((FEATURE*)psObj); // remove artifact+ send multiplay info.
}
// once they found a oil drum, we then wait ~600 secs before we pop up new one(s).
if( ((oilTimer + GAME_TICKS_PER_SEC * 600) < gameTime2 ) && GenerateDrum )
{
addOilDrum(drumCount);
oilTimer = 0;
drumCount = 0;
GenerateDrum = false;
} }
} }

View File

@ -311,6 +311,7 @@ void giftPower(uint8_t from, uint8_t to, BOOL send)
if (from == ANYPLAYER) if (from == ANYPLAYER)
{ {
gifval = OILDRUM_POWER; gifval = OILDRUM_POWER;
CONPRINTF(ConsoleString,(ConsoleString,_("Player %u found %u power in an oil drum"), to, gifval));
} }
else else
{ {
@ -321,10 +322,6 @@ void giftPower(uint8_t from, uint8_t to, BOOL send)
addPower(to, gifval); addPower(to, gifval);
if (from == ANYPLAYER && to == selectedPlayer)
{
CONPRINTF(ConsoleString,(ConsoleString,_("You found %u power in an oil drum"),gifval));
}
if (send) if (send)
{ {
uint8_t giftType = POWER_GIFT; uint8_t giftType = POWER_GIFT;
@ -604,6 +601,23 @@ void recvMultiPlayerFeature()
} }
} }
} }
// must match _feature_type in featuredef.h
static const char *feature_names[] =
{
"FEAT_BUILD_WRECK",
"FEAT_HOVER",
"FEAT_TANK",
"FEAT_GEN_ARTE",
"FEAT_OIL_RESOURCE",
"FEAT_BOULDER",
"FEAT_VEHICLE",
"FEAT_BUILDING",
"FEAT_DROID",
"FEAT_LOS_OBJ",
"FEAT_OIL_DRUM",
"FEAT_TREE",
"FEAT_SKYSCRAPER",
};
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// splatter artifact gifts randomly about. // splatter artifact gifts randomly about.
void addMultiPlayerRandomArtifacts(uint8_t quantity, FEATURE_TYPE type) void addMultiPlayerRandomArtifacts(uint8_t quantity, FEATURE_TYPE type)
@ -613,6 +627,7 @@ void addMultiPlayerRandomArtifacts(uint8_t quantity, FEATURE_TYPE type)
uint32_t x, y; uint32_t x, y;
uint8_t player = ANYPLAYER; uint8_t player = ANYPLAYER;
debug(LOG_FEATURE, "Sending %u artifact(s) type: (%s)", quantity, feature_names[type]);
NETbeginEncode(NET_ARTIFACTS, NET_ALL_PLAYERS); NETbeginEncode(NET_ARTIFACTS, NET_ALL_PLAYERS);
NETuint8_t(&quantity); NETuint8_t(&quantity);
NETenum(&type); NETenum(&type);
@ -630,7 +645,8 @@ void addMultiPlayerRandomArtifacts(uint8_t quantity, FEATURE_TYPE type)
if (!pickATileGen(&x, &y, LOOK_FOR_EMPTY_TILE, zonedPAT)) if (!pickATileGen(&x, &y, LOOK_FOR_EMPTY_TILE, zonedPAT))
{ {
ASSERT(false, "addMultiPlayerRandomArtifacts: Unable to find a free location"); ASSERT(false, "Unable to find a free location");
break;
} }
pF = buildFeature(asFeatureStats + i, world_coord(x), world_coord(y), false); pF = buildFeature(asFeatureStats + i, world_coord(x), world_coord(y), false);
@ -671,6 +687,7 @@ void recvMultiPlayerRandomArtifacts()
NETuint8_t(&quantity); NETuint8_t(&quantity);
NETenum(&type); NETenum(&type);
debug(LOG_FEATURE, "receiving %u artifact(s) type: (%s)", quantity, feature_names[type]);
for (i = 0; i < numFeatureStats && asFeatureStats[i].subType != type; i++); for (i = 0; i < numFeatureStats && asFeatureStats[i].subType != type; i++);
for (count = 0; count < quantity; count++) for (count = 0; count < quantity; count++)
@ -684,13 +701,13 @@ void recvMultiPlayerRandomArtifacts()
if (!tileOnMap(tx, ty)) if (!tileOnMap(tx, ty))
{ {
debug(LOG_ERROR, "recvMultiPlayerRandomArtifacts: Bad tile coordinates (%u,%u)", tx, ty); debug(LOG_ERROR, "Bad tile coordinates (%u,%u)", tx, ty);
continue; continue;
} }
psTile = mapTile(tx, ty); psTile = mapTile(tx, ty);
if (!psTile || psTile->psObject != NULL) if (!psTile || psTile->psObject != NULL)
{ {
debug(LOG_ERROR, "recvMultiPlayerRandomArtifacts: Already something at (%u,%u)!", tx, ty); debug(LOG_ERROR, "Already something at (%u,%u)!", tx, ty);
continue; continue;
} }
@ -700,6 +717,10 @@ void recvMultiPlayerRandomArtifacts()
pF->id = ref; pF->id = ref;
pF->player = player; pF->player = player;
} }
else
{
debug(LOG_ERROR, "Couldn't build feature %u for player %u ?", ref, player);
}
} }
NETend(); NETend();
} }

View File

@ -849,6 +849,7 @@ static BOOL campInit(void)
// add free research gifts.. // add free research gifts..
if(NetPlay.bHost) if(NetPlay.bHost)
{ {
// NOTE: you can set this safely to 50 for testing.
addOilDrum( NetPlay.playercount*2); // add some free power. addOilDrum( NetPlay.playercount*2); // add some free power.
} }

View File

@ -123,8 +123,8 @@ BOOL turnOffMultiMsg(BOOL bDoit)
{ {
if(bTemp == true) if(bTemp == true)
{ {
// Surely, this should be a Assert? // This is spammed multiple times.
debug(LOG_ERROR, "multiple calls to turn off"); debug(LOG_NEVER, "multiple calls to turn off");
} }
if(bMultiPlayer) if(bMultiPlayer)
{ {
@ -1479,10 +1479,13 @@ static BOOL recvDestroyTemplate()
// send a destruct feature message. // send a destruct feature message.
BOOL SendDestroyFeature(FEATURE *pF) BOOL SendDestroyFeature(FEATURE *pF)
{ {
// Only send if it is our responsibility // Since ANYPLAYER is supposed to be controlled by host only, that creates a issue when
if (myResponsibility(pF->player)) // a MP player gets a feature, and it is 'ANYPLAYER' it would never send the destroy msg.
if (!myResponsibility(pF->player) || !(pF->player == ANYPLAYER))
{
return true; return true;
}
debug(LOG_FEATURE, "p%d feature id %d destroyed (%s)", pF->player, pF->id, pF->psStats->pName);
NETbeginEncode(NET_FEATUREDEST, NET_ALL_PLAYERS); NETbeginEncode(NET_FEATUREDEST, NET_ALL_PLAYERS);
NETuint32_t(&pF->id); NETuint32_t(&pF->id);
return NETend(); return NETend();
@ -1502,9 +1505,11 @@ BOOL recvDestroyFeature()
if (pF == NULL) if (pF == NULL)
{ {
debug(LOG_WARNING, "feature id %d not found? (sync error?)", id);
return false; return false;
} }
debug(LOG_FEATURE, "p%d feature id %d destroyed (%s)", pF->player, pF->id, pF->psStats->pName);
// Remove the feature locally // Remove the feature locally
turnOffMultiMsg(true); turnOffMultiMsg(true);
removeFeature(pF); removeFeature(pF);