Files
source/Strategic/Strategic Event Handler.cpp
T
Overhaul 7a27e7105d New attack busy system
Added missing #includes

Added LUA scripting and console

Changed the way tracers are visualized, so they work more like real tracers instead of a light fountain

Fixed signedness of many grid variables used in GetMouseMapPos calls

Fixed enemy weapon choosing:  Sometimes a mortar is chosen but later rejected, but the grenade class was not reset.  Caused assertion failure

Added checks so enemies don't try to chuck RPG grenades with their hands

Now possible to shoot a someone in the head if he's in water

Fixed InitSightArrays to also clear soldier interrupt duel points.  This was causing an assertion failure elsewhere in the code because the interrupt list still had soldiers on it sometimes when this function was called.

Soldiers are much less willing to forfeit their turn over an attempt to use more APs than they have

Removed early setting of muzzle flash.  This would allow enemies to get an interrupt before you even fired.

Fixed item dropping by AI.  If AI tried to drop something while standing it would cause deadlock

Change to greatly speed up closing the sector inventory window in an unloaded sector

Added conditional compile flag to always give robot weapon ready advantage, even for 360 degree sighting


Check builddefines.h for the conditional flags.  Of greatest interest might be LUA_CONSOLE.  This will cause the game to bring up a command console when run.  However this console is severely lacking in many areas.  If anybody knows of an open-source terminal/console that could be used instead, it would be appreciated.  The existing console does bad things when you try to close it, and since it counts as a separate app, it pauses the game while it has focus.

LUA scripting is very limited, basically just proof of concept.  There is one global variable, the Soldiers array.  An array index gives you the soldier in that slot in the currently loaded sector.  The soldier has a few things that can be accessed:  name (short name); fullname (long name); grid (current grid #, can be changed); walkto(grid) (function to walk to another grid); runto(grid) (function to run to another grid)


git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@924 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2007-06-09 09:01:04 +00:00

1195 lines
36 KiB
C++

#ifdef PRECOMPILEDHEADERS
#include "Strategic All.h"
#else
#include "Strategic Event Handler.h"
#include "MemMan.h"
#include "message.h"
#include "Item Types.h"
#include "Items.h"
#include "Handle Items.h"
#include "LaptopSave.h"
#include "Tactical Save.h"
#include "StrategicMap.h"
#include "Quests.h"
#include "Soldier Profile.h"
#include "Game Event Hook.h"
#include "Game Clock.h"
#include "Interface Dialogue.h"
#include "Random.h"
#include "Overhead.h"
#include "Strategic Town Loyalty.h"
#include "Soldier Init List.h"
#include "SaveLoadMap.h"
#include "Worldman.h"
#include "Soldier Create.h"
#include "Soldier Add.h"
#include "Opplist.h"
#include "Renderworld.h"
#include "Soldier Profile.h"
#include "email.h"
#include "strategic.h"
#include "structure wrap.h"
#include "GameSettings.h"
#include "history.h"
#endif
#include "BobbyRMailOrder.h"
#define MEDUNA_ITEM_DROP_OFF_GRIDNO 10959
#define MEDUNA_ITEM_DROP_OFF_SECTOR_X 3
#define MEDUNA_ITEM_DROP_OFF_SECTOR_Y 14
#define MEDUNA_ITEM_DROP_OFF_SECTOR_Z 0
extern INT16 gsRobotGridNo;
UINT32 guiPabloExtraDaysBribed = 0;
UINT8 gubCambriaMedicalObjects;
void DropOffItemsInMeduna( UINT8 ubOrderNum );
void BobbyRayPurchaseEventCallback( UINT8 ubOrderID )
{
UINT8 i,j;
UINT16 usItem;
OBJECTTYPE Object;
UINT16 usMapPos, usStandardMapPos;
UINT16 usNumberOfItems;
BOOLEAN fSectorLoaded = FALSE;
UINT16 usTotalNumberOfItemTypes;
UINT32 uiCount = 0,uiStolenCount = 0;
static UINT8 ubShipmentsSinceNoBribes = 0;
UINT32 uiChanceOfTheft;
BOOLEAN fPablosStoleSomething = FALSE;
BOOLEAN fPablosStoleLastItem = FALSE;
OBJECTTYPE *pObject=NULL;
OBJECTTYPE *pStolenObject=NULL;
BOOLEAN fThisShipmentIsFromJohnKulba = FALSE; //if it is, dont add an email
UINT8 ubItemsDelivered;
UINT8 ubTempNumItems;
UINT8 ubItemsPurchased;
usStandardMapPos = BOBBYR_SHIPPING_DEST_GRIDNO;
// if the delivery is for meduna, drop the items off there instead
if( gpNewBobbyrShipments[ ubOrderID ].fActive && gpNewBobbyrShipments[ ubOrderID ].ubDeliveryLoc == BR_MEDUNA )
{
DropOffItemsInMeduna( ubOrderID );
return;
}
if (CheckFact( FACT_NEXT_PACKAGE_CAN_BE_LOST, 0 ))
{
SetFactFalse( FACT_NEXT_PACKAGE_CAN_BE_LOST );
if (Random( 100 ) < 50)
{
// lose the whole shipment!
gpNewBobbyrShipments[ ubOrderID ].fActive = FALSE;
SetFactTrue( FACT_LAST_SHIPMENT_CRASHED );
return;
}
}
else if (CheckFact( FACT_NEXT_PACKAGE_CAN_BE_DELAYED, 0 ))
{
// shipment went to wrong airport... reroute all items to a temporary
// gridno to represent the other airport (and damage them)
SetFactTrue( FACT_LAST_SHIPMENT_WENT_TO_WRONG_AIRPORT );
usStandardMapPos = LOST_SHIPMENT_GRIDNO;
SetFactFalse( FACT_NEXT_PACKAGE_CAN_BE_DELAYED );
}
else if ( (gTownLoyalty[ DRASSEN ].ubRating < 20) || StrategicMap[ CALCULATE_STRATEGIC_INDEX( 13, MAP_ROW_B ) ].fEnemyControlled )
{
// loss of the whole shipment
gpNewBobbyrShipments[ ubOrderID ].fActive = FALSE;
SetFactTrue( FACT_AGENTS_PREVENTED_SHIPMENT );
return;
}
//Get the number of item types
usTotalNumberOfItemTypes = gpNewBobbyrShipments[ ubOrderID ].ubNumberPurchases;
//Must get the total number of items ( all item types plus how many of each item type ordered )
usNumberOfItems = 0;
for(i=0; i<gpNewBobbyrShipments[ ubOrderID ].ubNumberPurchases; i++)
{
// Count how many items were purchased
usNumberOfItems += gpNewBobbyrShipments[ ubOrderID ].BobbyRayPurchase[i].ubNumberPurchased;
//if any items are AutoMags
if( gpNewBobbyrShipments[ ubOrderID ].BobbyRayPurchase[i].usItemIndex == AUTOMAG_III )
{
//This shipment is from John Kulba, dont add an email from bobby ray
fThisShipmentIsFromJohnKulba = TRUE;
}
}
// determine if the sector is loaded
if( ( gWorldSectorX == BOBBYR_SHIPPING_DEST_SECTOR_X ) && ( gWorldSectorY == BOBBYR_SHIPPING_DEST_SECTOR_Y ) && ( gbWorldSectorZ == BOBBYR_SHIPPING_DEST_SECTOR_Z ) )
fSectorLoaded = TRUE;
else
fSectorLoaded = FALSE;
// set crate to closed!
if ( fSectorLoaded )
{
SetOpenableStructureToClosed( BOBBYR_SHIPPING_DEST_GRIDNO, 0 );
}
else
{
ChangeStatusOfOpenableStructInUnloadedSector( BOBBYR_SHIPPING_DEST_SECTOR_X, BOBBYR_SHIPPING_DEST_SECTOR_Y, BOBBYR_SHIPPING_DEST_SECTOR_Z, BOBBYR_SHIPPING_DEST_GRIDNO, FALSE );
}
//if we are NOT currently in the right sector
if( !fSectorLoaded )
{
//build an array of objects to be added
pObject = (OBJECTTYPE *) MemAlloc( sizeof( OBJECTTYPE ) * usNumberOfItems );
pStolenObject = (OBJECTTYPE *) MemAlloc( sizeof( OBJECTTYPE ) * usNumberOfItems );
if( pObject == NULL || pStolenObject == NULL)
return;
memset( pObject, 0, sizeof( OBJECTTYPE ) * usNumberOfItems );
memset( pStolenObject, 0, sizeof( OBJECTTYPE ) * usNumberOfItems );
}
// WDS - Option to turn off stealing
// check for potential theft
if (gGameExternalOptions.fStealingDisabled ||
CheckFact( FACT_PABLO_WONT_STEAL, 0 ))
{
uiChanceOfTheft = 0;
}
else if (CheckFact( FACT_PABLOS_BRIBED, 0 ))
{
// Since Pacos has some money, reduce record of # of shipments since last bribed...
ubShipmentsSinceNoBribes /= 2;
uiChanceOfTheft = 0;
}
else
{
ubShipmentsSinceNoBribes++;
// this chance might seem high but it's only applied at most to every second item
uiChanceOfTheft = 12 + Random( 4 * ubShipmentsSinceNoBribes );
}
uiCount=0;
for ( i=0; i<gpNewBobbyrShipments[ ubOrderID ].ubNumberPurchases; i++ )
{
//Get the item
usItem = gpNewBobbyrShipments[ ubOrderID ].BobbyRayPurchase[i].usItemIndex;
//Create the item
CreateItem( usItem, gpNewBobbyrShipments[ ubOrderID ].BobbyRayPurchase[i].bItemQuality, &Object );
// if it's a gun
if (Item [ usItem ].usItemClass == IC_GUN )
{
// Empty out the bullets put in by CreateItem(). We now sell all guns empty of bullets. This is done for BobbyR
// simply to be consistent with the dealers in Arulco, who must sell guns empty to prevent ammo cheats by players.
Object.ubGunShotsLeft = 0;
}
ubItemsDelivered = 0;
//add all the items that were purchased
ubItemsPurchased = gpNewBobbyrShipments[ ubOrderID ].BobbyRayPurchase[i].ubNumberPurchased;
for( j=0; j < ubItemsPurchased; j++)
{
// Pablos might steal stuff but only:
// - if it's one of a group of items
// - if he didn't steal the previous item in the group (so he never steals > 50%)
// - if he has been bribed, he only sneaks out stuff which is cheap
if( fSectorLoaded )
{
// add ubItemsPurchased to the chance of theft so the chance increases when there are more items of a kind being ordered
if ( !fPablosStoleLastItem && uiChanceOfTheft > 0 && Random( 100 ) < (uiChanceOfTheft + ubItemsPurchased) )
{
uiStolenCount++;
usMapPos = PABLOS_STOLEN_DEST_GRIDNO; // off screen!
fPablosStoleSomething = TRUE;
fPablosStoleLastItem = TRUE;
}
else
{
usMapPos = usStandardMapPos;
fPablosStoleLastItem = FALSE;
if (usStandardMapPos == LOST_SHIPMENT_GRIDNO)
{
// damage the item a random amount!
Object.bStatus[0] = (INT8) ( ( (70 + Random( 11 )) * (INT32) Object.bStatus[0] ) / 100 );
// make damn sure it can't hit 0
if (Object.bStatus[0] == 0)
{
Object.bStatus[0] = 1;
}
AddItemToPool( usMapPos, &Object, -1, 0, 0, 0 );
}
else
{
// record # delivered for later addition...
ubItemsDelivered++;
}
}
}
else
{
if ( j > 1 && !fPablosStoleLastItem && uiChanceOfTheft > 0 && Random( 100 ) < (uiChanceOfTheft + j) )
{
memcpy( &pStolenObject[ uiStolenCount ], &Object, sizeof( OBJECTTYPE ) );
uiStolenCount++;
fPablosStoleSomething = TRUE;
fPablosStoleLastItem = TRUE;
}
else
{
fPablosStoleLastItem = FALSE;
//else we are not currently in the sector, so we build an array of items to add in one lump
//add the item to the item array
if (usStandardMapPos == LOST_SHIPMENT_GRIDNO)
{
// damage the item a random amount!
Object.bStatus[0] = (INT8) ( ( (70 + Random( 11 )) * (INT32) Object.bStatus[0] ) / 100 );
// make damn sure it can't hit 0
if (Object.bStatus[0] == 0)
{
Object.bStatus[0] = 1;
}
memcpy( &pObject[ uiCount ], &Object, sizeof( OBJECTTYPE ) );
uiCount++;
}
else
{
ubItemsDelivered++;
}
}
}
}
if ( gpNewBobbyrShipments[ ubOrderID ].BobbyRayPurchase[i].ubNumberPurchased == 1 && ubItemsDelivered == 1 )
{
// the item in Object will be the item to deliver
if( fSectorLoaded )
{
AddItemToPool( usStandardMapPos, &Object, -1, 0, 0, 0 );
}
else
{
memcpy( &pObject[ uiCount ], &Object, sizeof( OBJECTTYPE ) );
uiCount++;
}
}
else
{
while ( ubItemsDelivered )
{
// treat 0s as 1s :-)
ubTempNumItems = __min( ubItemsDelivered, __max( 1, Item[ usItem ].ubPerPocket ) );
CreateItems( usItem, gpNewBobbyrShipments[ ubOrderID ].BobbyRayPurchase[i].bItemQuality, ubTempNumItems, &Object );
// stack as many as possible
if( fSectorLoaded )
{
AddItemToPool( usStandardMapPos, &Object, -1, 0, 0, 0 );
}
else
{
memcpy( &pObject[ uiCount ], &Object, sizeof( OBJECTTYPE ) );
uiCount++;
}
ubItemsDelivered -= ubTempNumItems;
}
}
}
//if we are NOT currently in the sector
if( !fSectorLoaded )
{
//add all the items from the array that was built above
usMapPos = PABLOS_STOLEN_DEST_GRIDNO;
//The item are to be added to the Top part of Drassen, grid loc's 10112, 9950
if( !AddItemsToUnLoadedSector( BOBBYR_SHIPPING_DEST_SECTOR_X, BOBBYR_SHIPPING_DEST_SECTOR_Y, BOBBYR_SHIPPING_DEST_SECTOR_Z, usStandardMapPos, uiCount, pObject, 0, 0, 0, -1, FALSE ) )
{
//Error adding the items
//return;
}
if (uiStolenCount > 0)
{
if( !AddItemsToUnLoadedSector( BOBBYR_SHIPPING_DEST_SECTOR_X, BOBBYR_SHIPPING_DEST_SECTOR_Y, BOBBYR_SHIPPING_DEST_SECTOR_Z, PABLOS_STOLEN_DEST_GRIDNO, uiStolenCount, pStolenObject, 0, 0, 0, -1, FALSE ) )
{
//Error adding the items
//return;
}
}
MemFree( pObject );
MemFree( pStolenObject );
pObject = NULL;
pStolenObject = NULL;
}
if (fPablosStoleSomething)
{
SetFactTrue( FACT_PABLOS_STOLE_FROM_LATEST_SHIPMENT );
}
else
{
SetFactFalse( FACT_PABLOS_STOLE_FROM_LATEST_SHIPMENT );
}
SetFactFalse( FACT_LARGE_SIZED_OLD_SHIPMENT_WAITING );
if ( CheckFact( FACT_NEXT_PACKAGE_CAN_BE_DELAYED, 0 ) )
{
SetFactFalse( FACT_MEDIUM_SIZED_SHIPMENT_WAITING );
SetFactFalse( FACT_LARGE_SIZED_SHIPMENT_WAITING );
SetFactFalse( FACT_REALLY_NEW_BOBBYRAY_SHIPMENT_WAITING );
}
else
{
if (usNumberOfItems - uiStolenCount <= 5)
{
SetFactFalse( FACT_MEDIUM_SIZED_SHIPMENT_WAITING );
SetFactFalse( FACT_LARGE_SIZED_SHIPMENT_WAITING );
}
else if (usNumberOfItems - uiStolenCount <= 15)
{
SetFactTrue( FACT_MEDIUM_SIZED_SHIPMENT_WAITING );
SetFactFalse( FACT_LARGE_SIZED_SHIPMENT_WAITING );
}
else
{
SetFactFalse( FACT_MEDIUM_SIZED_SHIPMENT_WAITING );
SetFactTrue( FACT_LARGE_SIZED_SHIPMENT_WAITING );
}
// this shipment isn't old yet...
SetFactTrue( FACT_REALLY_NEW_BOBBYRAY_SHIPMENT_WAITING );
// set up even to make shipment "old"
AddSameDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, GetWorldMinutesInDay() + 120, FACT_REALLY_NEW_BOBBYRAY_SHIPMENT_WAITING );
}
//We have received the shipment so fActice becomes fALSE
gpNewBobbyrShipments[ ubOrderID ].fActive = FALSE;
//Stop time compression the game
StopTimeCompression( );
//if the shipment is NOT from John Kulba, send an email
if( !fThisShipmentIsFromJohnKulba )
{
//Add an email from Bobby r telling the user the shipment 'Should' be there
AddEmail( BOBBYR_SHIPMENT_ARRIVED, BOBBYR_SHIPMENT_ARRIVED_LENGTH, BOBBY_R, GetWorldTotalMin(), -1 );
}
else
{
//if the shipment is from John Kulba
//Add an email from kulba telling the user the shipment is there
AddEmail( JOHN_KULBA_GIFT_IN_DRASSEN, JOHN_KULBA_GIFT_IN_DRASSEN_LENGTH, JOHN_KULBA, GetWorldTotalMin(), -1 );
}
}
void HandleDelayedItemsArrival( UINT32 uiReason )
{
// This function moves all the items that Pablos has stolen
// (or items that were delayed) to the arrival location for new shipments,
INT16 sStartGridNo;
UINT32 uiNumWorldItems, uiLoop;
BOOLEAN fOk;
WORLDITEM * pTemp;
UINT8 ubLoop;
OBJECTTYPE Object;
if (uiReason == NPC_SYSTEM_EVENT_ACTION_PARAM_BONUS + NPC_ACTION_RETURN_STOLEN_SHIPMENT_ITEMS )
{
if ( gMercProfiles[ PABLO ].bMercStatus == MERC_IS_DEAD )
{
// nothing arrives then!
return;
}
// update some facts...
SetFactTrue( FACT_PABLO_RETURNED_GOODS );
SetFactFalse( FACT_PABLO_PUNISHED_BY_PLAYER );
sStartGridNo = PABLOS_STOLEN_DEST_GRIDNO;
// add random items
for (ubLoop = 0; ubLoop < 2; ubLoop++)
{
switch( Random( 10 ) )
{
case 0:
// 1 in 10 chance of a badly damaged gas mask
CreateItem( GASMASK, (INT8) (20 + Random( 10 )), &Object );
break;
case 1:
case 2:
// 2 in 10 chance of a battered Desert Eagle
CreateItem( DESERTEAGLE, (INT8) (40 + Random( 10 )), &Object );
break;
case 3:
case 4:
case 5:
// 3 in 10 chance of a stun grenade
CreateItem( STUN_GRENADE, (INT8) (70 + Random( 10 )), &Object );
break;
case 6:
case 7:
case 8:
case 9:
// 4 in 10 chance of two 38s!
CreateItems( SW38, (INT8) (90 + Random( 10 )), 2, &Object );
break;
}
if ( ( gWorldSectorX == BOBBYR_SHIPPING_DEST_SECTOR_X ) && ( gWorldSectorY == BOBBYR_SHIPPING_DEST_SECTOR_Y ) && ( gbWorldSectorZ == BOBBYR_SHIPPING_DEST_SECTOR_Z ) )
{
AddItemToPool( BOBBYR_SHIPPING_DEST_GRIDNO, &Object, -1, 0, 0, 0 );
}
else
{
AddItemsToUnLoadedSector( BOBBYR_SHIPPING_DEST_SECTOR_X, BOBBYR_SHIPPING_DEST_SECTOR_Y, BOBBYR_SHIPPING_DEST_SECTOR_Z, BOBBYR_SHIPPING_DEST_GRIDNO, 1, &Object, 0, 0, 0, -1, FALSE );
}
}
}
else if (uiReason == FACT_PACKAGE_DAMAGED)
{
sStartGridNo = LOST_SHIPMENT_GRIDNO;
}
else
{
return;
}
// If the Drassen airport sector is already loaded, move the item pools...
if ( ( gWorldSectorX == BOBBYR_SHIPPING_DEST_SECTOR_X ) && ( gWorldSectorY == BOBBYR_SHIPPING_DEST_SECTOR_Y ) && ( gbWorldSectorZ == BOBBYR_SHIPPING_DEST_SECTOR_Z ) )
{
// sector is loaded!
// just move the hidden item pool
MoveItemPools( sStartGridNo, BOBBYR_SHIPPING_DEST_GRIDNO );
}
else
{
// otherwise load the saved items from the item file and change the records of their locations
fOk = GetNumberOfWorldItemsFromTempItemFile( BOBBYR_SHIPPING_DEST_SECTOR_X, BOBBYR_SHIPPING_DEST_SECTOR_Y, BOBBYR_SHIPPING_DEST_SECTOR_Z, &uiNumWorldItems, FALSE );
if (!fOk)
{
return;
}
pTemp = (WORLDITEM *) MemAlloc( sizeof( WORLDITEM ) * uiNumWorldItems);
if (!pTemp)
{
return;
}
fOk = LoadWorldItemsFromTempItemFile( BOBBYR_SHIPPING_DEST_SECTOR_X, BOBBYR_SHIPPING_DEST_SECTOR_Y, BOBBYR_SHIPPING_DEST_SECTOR_Z, pTemp );
if (fOk)
{
for (uiLoop = 0; uiLoop < uiNumWorldItems; uiLoop++)
{
if (pTemp[uiLoop].sGridNo == PABLOS_STOLEN_DEST_GRIDNO)
{
pTemp[uiLoop].sGridNo = BOBBYR_SHIPPING_DEST_GRIDNO;
}
}
AddWorldItemsToUnLoadedSector( BOBBYR_SHIPPING_DEST_SECTOR_X, BOBBYR_SHIPPING_DEST_SECTOR_Y, BOBBYR_SHIPPING_DEST_SECTOR_Z, 0, uiNumWorldItems, pTemp, TRUE );
}
}
}
void AddSecondAirportAttendant( void )
{
// add the second airport attendant to the Drassen airport...
gMercProfiles[99].sSectorX = BOBBYR_SHIPPING_DEST_SECTOR_X;
gMercProfiles[99].sSectorY = BOBBYR_SHIPPING_DEST_SECTOR_Y;
gMercProfiles[99].bSectorZ = BOBBYR_SHIPPING_DEST_SECTOR_Z;
}
void SetPabloToUnbribed( void )
{
if (guiPabloExtraDaysBribed > 0)
{
// set new event for later on, because the player gave Pablo more money!
AddFutureDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, GetWorldMinutesInDay(), FACT_PABLOS_BRIBED, guiPabloExtraDaysBribed );
guiPabloExtraDaysBribed = 0;
}
else
{
SetFactFalse( FACT_PABLOS_BRIBED );
}
}
void HandlePossiblyDamagedPackage( void )
{
if (Random( 100 ) < 70)
{
SetFactTrue( FACT_PACKAGE_DAMAGED );
HandleDelayedItemsArrival( FACT_PACKAGE_DAMAGED );
}
else
{
// shipment lost forever!
SetFactTrue( FACT_PACKAGE_LOST_PERMANENTLY );
}
// whatever happened, the shipment is no longer delayed
SetFactFalse( FACT_SHIPMENT_DELAYED_24_HOURS );
}
void CheckForKingpinsMoneyMissing( BOOLEAN fFirstCheck )
{
UINT32 uiLoop;
UINT32 uiTotalCash = 0;
BOOLEAN fKingpinWillDiscover = FALSE, fKingpinDiscovers = FALSE;
// money in D5b1 must be less than 30k
for ( uiLoop = 0; uiLoop < guiNumWorldItems; uiLoop++ )
{
// loop through all items, look for ownership
if ( gWorldItems[ uiLoop ].fExists && gWorldItems[ uiLoop ].o.usItem == MONEY )
{
uiTotalCash += gWorldItems[uiLoop].o.uiMoneyAmount;
}
}
// This function should be called every time sector D5/B1 is unloaded!
if ( fFirstCheck )
{
if ( CheckFact( FACT_KINGPIN_WILL_LEARN_OF_MONEY_GONE, 0 ) == TRUE )
{
// unnecessary
return;
}
if ( uiTotalCash < 30000 )
{
// add history log here
AddHistoryToPlayersLog( HISTORY_FOUND_MONEY, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY );
SetFactTrue( FACT_KINGPIN_WILL_LEARN_OF_MONEY_GONE );
}
}
if ( CheckFact( FACT_KINGPIN_DEAD, 0 ) == TRUE )
{
return;
}
if ( uiTotalCash < 30000 )
{
if ( fFirstCheck )
{
// add event to make Kingpin aware, two days from now
fKingpinWillDiscover = TRUE;
}
else
{
fKingpinDiscovers = TRUE;
}
}
if ( fKingpinWillDiscover )
{
// set event for next day to check for real
AddFutureDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, Random( 120 ), FACT_KINGPIN_KNOWS_MONEY_GONE, 1 );
// the sector is unloaded NOW so set Kingpin's balance and remove the cash
gMercProfiles[ KINGPIN ].iBalance = - (30000 - (INT32) uiTotalCash);
// remove all money from map
for ( uiLoop = 0; uiLoop < guiNumWorldItems; uiLoop++ )
{
// loop through all items, look for ownership
if ( gWorldItems[ uiLoop ].fExists && gWorldItems[ uiLoop ].o.usItem == MONEY )
{
// remove!
gWorldItems[ uiLoop ].fExists = FALSE;
}
}
}
else if ( fKingpinDiscovers )
{
// ok start things up here!
SetFactTrue( FACT_KINGPIN_KNOWS_MONEY_GONE );
// set event 2 days from now that if the player has not given Kingpin his money back,
// he sends email to the player
AddFutureDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, Random( 120 ), FACT_KINGPIN_KNOWS_MONEY_GONE, 2 );
}
}
void HandleNPCSystemEvent( UINT32 uiEvent )
{
if (uiEvent < NPC_SYSTEM_EVENT_ACTION_PARAM_BONUS)
{
switch( uiEvent )
{
case FACT_PABLOS_BRIBED:
// set Pacos to unbribed
SetPabloToUnbribed();
break;
case FACT_REALLY_NEW_BOBBYRAY_SHIPMENT_WAITING:
// the shipment is no longer really new
SetFactFalse( FACT_REALLY_NEW_BOBBYRAY_SHIPMENT_WAITING );
if (CheckFact( FACT_LARGE_SIZED_SHIPMENT_WAITING, 0 ))
{
// set "really heavy old shipment" fact
SetFactTrue( FACT_LARGE_SIZED_OLD_SHIPMENT_WAITING );
}
break;
case FACT_SHIPMENT_DELAYED_24_HOURS:
case FACT_24_HOURS_SINCE_DOCTOR_TALKED_TO:
case FACT_24_HOURS_SINCE_JOEY_RESCUED:
SetFactTrue( (UINT16) uiEvent );
break;
case FACT_KINGPIN_KNOWS_MONEY_GONE:
// more generally events for kingpin quest
if ( CheckFact( FACT_KINGPIN_KNOWS_MONEY_GONE, 0 ) == FALSE )
{
// check for real whether to start quest
CheckForKingpinsMoneyMissing( FALSE );
}
else if ( CheckFact( FACT_KINGPIN_DEAD, 0 ) == FALSE )
{
if ( gubQuest[ QUEST_KINGPIN_MONEY ] == QUESTNOTSTARTED )
{
// KP knows money is gone, hasn't told player, if this event is called then the 2
// days are up... send email
AddEmail( KING_PIN_LETTER, KING_PIN_LETTER_LENGTH, KING_PIN, GetWorldTotalMin(), -1 );
StartQuest( QUEST_KINGPIN_MONEY, 5, MAP_ROW_D );
// add event to send terrorists two days from now
AddFutureDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, Random( 120 ), FACT_KINGPIN_KNOWS_MONEY_GONE, 2 );
}
else if ( gubQuest[ QUEST_KINGPIN_MONEY ] == QUESTINPROGRESS )
{
// knows money gone, quest is still in progress
// event indicates Kingpin can start to send terrorists
SetFactTrue( FACT_KINGPIN_CAN_SEND_ASSASSINS );
gMercProfiles[ SPIKE ].sSectorX = 5;
gMercProfiles[ SPIKE ].sSectorY = MAP_ROW_C;
gTacticalStatus.fCivGroupHostile[ KINGPIN_CIV_GROUP ] = CIV_GROUP_WILL_BECOME_HOSTILE;
}
}
break;
}
}
else
{
switch( uiEvent - NPC_SYSTEM_EVENT_ACTION_PARAM_BONUS )
{
case NPC_ACTION_RETURN_STOLEN_SHIPMENT_ITEMS:
HandleDelayedItemsArrival( uiEvent );
break;
case NPC_ACTION_SET_RANDOM_PACKAGE_DAMAGE_TIMER:
HandlePossiblyDamagedPackage();
break;
case NPC_ACTION_ENABLE_CAMBRIA_DOCTOR_BONUS:
SetFactTrue( FACT_WILLIS_HEARD_ABOUT_JOEY_RESCUE );
break;
case NPC_ACTION_TRIGGER_END_OF_FOOD_QUEST:
if ( gMercProfiles[ FATHER ].bMercStatus != MERC_IS_DEAD )
{
EndQuest( QUEST_FOOD_ROUTE, 10, MAP_ROW_A );
SetFactTrue( FACT_FOOD_QUEST_OVER );
}
break;
case NPC_ACTION_DELAYED_MAKE_BRENDA_LEAVE:
//IC:
//TriggerNPCRecord( 85, 9 );
SetFactTrue( FACT_BRENDA_PATIENCE_TIMER_EXPIRED );
break;
case NPC_ACTION_SET_DELAY_TILL_GIRLS_AVAILABLE:
HandleNPCDoAction( 107, NPC_ACTION_SET_GIRLS_AVAILABLE, 0 );
break;
case NPC_ACTION_READY_ROBOT:
{
if ( CheckFact( FACT_FIRST_ROBOT_DESTROYED, 0 ) )
{
// second robot ready
SetFactTrue( FACT_ROBOT_READY_SECOND_TIME );
// resurrect robot
gMercProfiles[ ROBOT ].bLife = gMercProfiles[ ROBOT ].bLifeMax;
gMercProfiles[ ROBOT ].bMercStatus = MERC_OK;
}
else
{
// first robot ready
SetFactTrue( FACT_ROBOT_READY );
}
gMercProfiles[ ROBOT ].sSectorX = gMercProfiles[ MADLAB ].sSectorX;
gMercProfiles[ ROBOT ].sSectorY = gMercProfiles[ MADLAB ].sSectorY;
gMercProfiles[ ROBOT ].bSectorZ = gMercProfiles[ MADLAB ].bSectorZ;
}
break;
case NPC_ACTION_ADD_JOEY_TO_WORLD:
// If Joey is not dead, escorted, or already delivered
if ( gMercProfiles[ JOEY ].bMercStatus != MERC_IS_DEAD && !CheckFact( FACT_JOEY_ESCORTED, 0 ) &&
gMercProfiles[ JOEY ].sSectorX == 4 &&
gMercProfiles[ JOEY ].sSectorY == MAP_ROW_D &&
gMercProfiles[ JOEY ].bSectorZ == 1 )
{
SOLDIERTYPE * pJoey;
pJoey = FindSoldierByProfileID( JOEY, FALSE );
if (pJoey )
{
// he's in the currently loaded sector...delay this an hour!
AddSameDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, GetWorldMinutesInDay() + 60, NPC_SYSTEM_EVENT_ACTION_PARAM_BONUS + NPC_ACTION_ADD_JOEY_TO_WORLD );
}
else
{
// move Joey from caves to San Mona
gMercProfiles[ JOEY ].sSectorX = 5;
gMercProfiles[ JOEY ].sSectorY = MAP_ROW_C;
gMercProfiles[ JOEY ].bSectorZ = 0;
}
}
break;
case NPC_ACTION_SEND_ENRICO_MIGUEL_EMAIL:
AddEmail( ENRICO_MIGUEL, ENRICO_MIGUEL_LENGTH, MAIL_ENRICO, GetWorldTotalMin(), -1 );
break;
case NPC_ACTION_TIMER_FOR_VEHICLE:
SetFactTrue( FACT_OK_USE_HUMMER );
break;
case NPC_ACTION_FREE_KIDS:
SetFactTrue( FACT_KIDS_ARE_FREE );
break;
default:
break;
}
}
}
void HandleEarlyMorningEvents( void )
{
UINT32 cnt;
UINT32 uiAmount;
// loop through all *NPCs* and reset "default response used recently" flags
for (cnt = FIRST_RPC; cnt < GASTON; cnt++)
{
gMercProfiles[cnt].bFriendlyOrDirectDefaultResponseUsedRecently = FALSE;
gMercProfiles[cnt].bRecruitDefaultResponseUsedRecently = FALSE;
gMercProfiles[cnt].bThreatenDefaultResponseUsedRecently = FALSE;
gMercProfiles[cnt].ubMiscFlags2 &= (~PROFILE_MISC_FLAG2_BANDAGED_TODAY);
}
// reset Father Walker's drunkenness level!
gMercProfiles[ FATHER ].bNPCData = (INT8) Random( 4 );
// set Walker's location
if ( Random( 2 ) )
{
// move the father to the other sector, provided neither are loaded
if ( ! ( ( gWorldSectorX == 13) && ( ( gWorldSectorY == MAP_ROW_C) || gWorldSectorY == MAP_ROW_D ) && ( gbWorldSectorZ == 0 ) ) )
{
gMercProfiles[ FATHER ].sSectorX = 13;
// swap his location
if (gMercProfiles[ FATHER ].sSectorY == MAP_ROW_C)
{
gMercProfiles[ FATHER ].sSectorY = MAP_ROW_D;
}
else
{
gMercProfiles[ FATHER ].sSectorY = MAP_ROW_C;
}
}
}
if( gMercProfiles[ TONY ].ubLastDateSpokenTo > 0 && !( gWorldSectorX == 5 && gWorldSectorY == MAP_ROW_C && gbWorldSectorZ == 0 ) )
{
// San Mona C5 is not loaded so make Tony possibly not available
if (Random( 4 ))
{
// Tony IS available
SetFactFalse( FACT_TONY_NOT_AVAILABLE );
gMercProfiles[ TONY ].sSectorX = 5;
gMercProfiles[ TONY ].sSectorY = MAP_ROW_C;
}
else
{
// Tony is NOT available
SetFactTrue( FACT_TONY_NOT_AVAILABLE );
gMercProfiles[ TONY ].sSectorX = 0;
gMercProfiles[ TONY ].sSectorY = 0;
}
}
if ( gMercProfiles[ DEVIN ].ubLastDateSpokenTo == 0 )
{
// Does Devin move?
gMercProfiles[ DEVIN ].bNPCData++;
if ( gMercProfiles[ DEVIN ].bNPCData > 3 )
{
if ( ! ( (gWorldSectorX == gMercProfiles[ DEVIN ].sSectorX) && (gWorldSectorY == gMercProfiles[DEVIN].sSectorY) && (gbWorldSectorZ == 0) ) )
{
// ok, Devin's sector not loaded, so time to move!
// might be same sector as before, if so, oh well!
switch( Random( 5 ) )
{
case 0:
gMercProfiles[ DEVIN ].sSectorX = 9;
gMercProfiles[ DEVIN ].sSectorY = MAP_ROW_G;
break;
case 1:
gMercProfiles[ DEVIN ].sSectorX = 13;
gMercProfiles[ DEVIN ].sSectorY = MAP_ROW_D;
break;
case 2:
gMercProfiles[ DEVIN ].sSectorX = 5;
gMercProfiles[ DEVIN ].sSectorY = MAP_ROW_C;
break;
case 3:
gMercProfiles[ DEVIN ].sSectorX = 2;
gMercProfiles[ DEVIN ].sSectorY = MAP_ROW_H;
break;
case 4:
gMercProfiles[ DEVIN ].sSectorX = 6;
gMercProfiles[ DEVIN ].sSectorY = MAP_ROW_C;
break;
}
}
}
}
// Does Hamous move?
// stop moving the truck if Hamous is dead!!
// stop moving them if the player has the truck or Hamous is hired!
if ( gMercProfiles[ HAMOUS ].bLife > 0 && FindSoldierByProfileID( HAMOUS, TRUE ) == NULL && FindSoldierByProfileID( PROF_ICECREAM, TRUE ) == NULL && (! ( (gWorldSectorX == gMercProfiles[ HAMOUS ].sSectorX) && (gWorldSectorY == gMercProfiles[HAMOUS].sSectorY) && (gbWorldSectorZ == 0) )) )
{
// ok, HAMOUS's sector not loaded, so time to move!
// might be same sector as before, if so, oh well!
switch( Random( 5 ) )
{
case 0:
gMercProfiles[ HAMOUS ].sSectorX = 6;
gMercProfiles[ HAMOUS ].sSectorY = MAP_ROW_G;
gMercProfiles[ PROF_ICECREAM ].sSectorX = 6;
gMercProfiles[ PROF_ICECREAM ].sSectorY = MAP_ROW_G;
break;
case 1:
gMercProfiles[ HAMOUS ].sSectorX = 12;
gMercProfiles[ HAMOUS ].sSectorY = MAP_ROW_F;
gMercProfiles[ PROF_ICECREAM ].sSectorX = 12;
gMercProfiles[ PROF_ICECREAM ].sSectorY = MAP_ROW_F;
break;
case 2:
gMercProfiles[ HAMOUS ].sSectorX = 7;
gMercProfiles[ HAMOUS ].sSectorY = MAP_ROW_D;
gMercProfiles[ PROF_ICECREAM ].sSectorX = 7;
gMercProfiles[ PROF_ICECREAM ].sSectorY = MAP_ROW_D;
break;
case 3:
gMercProfiles[ HAMOUS ].sSectorX = 3;
gMercProfiles[ HAMOUS ].sSectorY = MAP_ROW_D;
gMercProfiles[ PROF_ICECREAM ].sSectorX = 3;
gMercProfiles[ PROF_ICECREAM ].sSectorY = MAP_ROW_D;
break;
case 4:
gMercProfiles[ HAMOUS ].sSectorX = 9;
gMercProfiles[ HAMOUS ].sSectorY = MAP_ROW_D;
gMercProfiles[ PROF_ICECREAM ].sSectorX = 9;
gMercProfiles[ PROF_ICECREAM ].sSectorY = MAP_ROW_D;
break;
}
}
// Does Rat take off?
if ( gMercProfiles[ RAT ].bNPCData != 0 )
{
gMercProfiles[ RAT ].sSectorX = 0;
gMercProfiles[ RAT ].sSectorY = 0;
gMercProfiles[ RAT ].bSectorZ = 0;
}
// Empty money from pockets of Vince 69, Willis 80, and Jenny 132
SetMoneyInSoldierProfile( VINCE, 0 );
SetMoneyInSoldierProfile( STEVE, 0 ); // Steven Willis
SetMoneyInSoldierProfile( JENNY, 0 );
// Vince is no longer expecting money
SetFactFalse( FACT_VINCE_EXPECTING_MONEY );
// Reset Darren's balance and money
gMercProfiles[ DARREN ].iBalance = 0;
SetMoneyInSoldierProfile( DARREN, 15000 );
// set Carmen to be placed on the map in case he moved and is waiting off screen
if (gMercProfiles[ CARMEN ].ubMiscFlags2 & PROFILE_MISC_FLAG2_DONT_ADD_TO_SECTOR)
{
gMercProfiles[ CARMEN ].ubMiscFlags2 &= ~(PROFILE_MISC_FLAG2_DONT_ADD_TO_SECTOR);
// move Carmen to C13
gMercProfiles[ CARMEN ].sSectorX = 13;
gMercProfiles[ CARMEN ].sSectorY = MAP_ROW_C;
gMercProfiles[ CARMEN ].bSectorZ = 0;
// we should also reset # of terrorist heads and give him cash
if (gMercProfiles[ CARMEN ].bNPCData2 > 0)
{
if (gMercProfiles[ CARMEN ].uiMoney < 10000)
{
uiAmount = 0;
}
else
{
uiAmount = gMercProfiles[ CARMEN ].uiMoney;
}
uiAmount += 10000 * gMercProfiles[ CARMEN ].bNPCData2;
SetMoneyInSoldierProfile( CARMEN, uiAmount );
gMercProfiles[ CARMEN ].bNPCData2 = 0;
for ( cnt = HEAD_1; cnt <= HEAD_7; cnt++ )
{
RemoveObjectFromSoldierProfile( CARMEN, (UINT8) cnt );
}
}
}
else
{
// randomize where he'll be today... so long as his sector's not loaded
if ( gMercProfiles[ CARMEN ].sSectorX != gWorldSectorX || gMercProfiles[ CARMEN ].sSectorY != gWorldSectorY )
{
switch( Random( 3 ) )
{
case 0:
gMercProfiles[ CARMEN ].sSectorX = 5;
gMercProfiles[ CARMEN ].sSectorY = MAP_ROW_C;
break;
case 1:
gMercProfiles[ CARMEN ].sSectorX = 13;
gMercProfiles[ CARMEN ].sSectorY = MAP_ROW_C;
break;
case 2:
gMercProfiles[ CARMEN ].sSectorX = 9;
gMercProfiles[ CARMEN ].sSectorY = MAP_ROW_G;
break;
}
// he should have $5000... unless the player forgot to meet him
if (gMercProfiles[ CARMEN ].uiMoney < 5000)
{
SetMoneyInSoldierProfile( CARMEN, 5000 );
}
}
}
if ( PreRandom( 3 ) == 0 )
{
SetFactTrue( FACT_DAVE_HAS_GAS );
}
else
{
SetFactFalse( FACT_DAVE_HAS_GAS );
}
if ( gWorldSectorX == HOSPITAL_SECTOR_X && gWorldSectorY == HOSPITAL_SECTOR_Y && gbWorldSectorZ == HOSPITAL_SECTOR_Z )
{
CheckForMissingHospitalSupplies();
}
}
void MakeCivGroupHostileOnNextSectorEntrance( UINT8 ubCivGroup )
{
// if it's the rebels that will become hostile, reduce town loyalties NOW, not later
if ( ubCivGroup == REBEL_CIV_GROUP && gTacticalStatus.fCivGroupHostile[ ubCivGroup ] == CIV_GROUP_NEUTRAL )
{
ReduceLoyaltyForRebelsBetrayed();
}
gTacticalStatus.fCivGroupHostile[ ubCivGroup ] = CIV_GROUP_WILL_BECOME_HOSTILE;
}
void RemoveAssassin( UINT8 ubProfile )
{
gMercProfiles[ ubProfile ].sSectorX = 0;
gMercProfiles[ ubProfile ].sSectorY = 0;
gMercProfiles[ ubProfile ].bLife = gMercProfiles[ ubProfile ].bLifeMax;
}
void CheckForMissingHospitalSupplies( void )
{
UINT32 uiLoop;
ITEM_POOL * pItemPool;
OBJECTTYPE * pObj;
UINT8 ubMedicalObjects = 0;
for ( uiLoop = 0; uiLoop < guiNumWorldItems; uiLoop++ )
{
// loop through all items, look for ownership
if ( gWorldItems[ uiLoop ].fExists && gWorldItems[ uiLoop ].o.usItem == OWNERSHIP && gWorldItems[ uiLoop ].o.ubOwnerCivGroup == DOCTORS_CIV_GROUP )
{
GetItemPool( gWorldItems[ uiLoop ].sGridNo, &pItemPool, 0 ) ;
while( pItemPool )
{
pObj = &( gWorldItems[ pItemPool->iItemIndex ].o );
if ( pObj->bStatus[ 0 ] > 60 )
{
if ( Item[pObj->usItem].firstaidkit || Item[pObj->usItem].medicalkit || pObj->usItem == REGEN_BOOSTER || pObj->usItem == ADRENALINE_BOOSTER )
{
ubMedicalObjects++;
}
}
pItemPool = pItemPool->pNext;
}
}
}
if ( CheckFact( FACT_PLAYER_STOLE_MEDICAL_SUPPLIES_AGAIN, 0 ) == TRUE )
{
// player returning stuff! if back to full then can operate
if ( ubMedicalObjects >= gubCambriaMedicalObjects )
{
SetFactFalse( FACT_PLAYER_STOLE_MEDICAL_SUPPLIES_AGAIN );
SetFactFalse( FACT_PLAYER_STOLE_MEDICAL_SUPPLIES );
return;
}
}
if ( ubMedicalObjects < gubCambriaMedicalObjects )
{
// player's stolen something!
if ( CheckFact( FACT_PLAYER_STOLE_MEDICAL_SUPPLIES, 0 ) == FALSE )
{
SetFactTrue( FACT_PLAYER_STOLE_MEDICAL_SUPPLIES );
}
// if only 1/5 or less left, give up the ghost
if ( ubMedicalObjects * 5 <= gubCambriaMedicalObjects )
{
// run out!
SetFactTrue( FACT_PLAYER_STOLE_MEDICAL_SUPPLIES_AGAIN );
}
}
}
void DropOffItemsInMeduna( UINT8 ubOrderNum )
{
BOOLEAN fSectorLoaded = FALSE;
OBJECTTYPE Object;
UINT32 uiCount = 0;
OBJECTTYPE *pObject=NULL;
UINT16 usNumberOfItems=0, usItem;
UINT8 ubItemsDelivered, ubTempNumItems;
UINT32 i;
//if the player doesnt "own" the sector,
if( StrategicMap[ CALCULATE_STRATEGIC_INDEX( MEDUNA_ITEM_DROP_OFF_SECTOR_X, MEDUNA_ITEM_DROP_OFF_SECTOR_Y ) ].fEnemyControlled )
{
//the items disappear
gpNewBobbyrShipments[ ubOrderNum ].fActive = FALSE;
return;
}
// determine if the sector is loaded
if( ( gWorldSectorX == MEDUNA_ITEM_DROP_OFF_SECTOR_X ) && ( gWorldSectorY == MEDUNA_ITEM_DROP_OFF_SECTOR_Y ) && ( gbWorldSectorZ == MEDUNA_ITEM_DROP_OFF_SECTOR_Z ) )
fSectorLoaded = TRUE;
else
fSectorLoaded = FALSE;
// set crate to closed!
if ( fSectorLoaded )
{
SetOpenableStructureToClosed( MEDUNA_ITEM_DROP_OFF_GRIDNO, 0 );
}
else
{
ChangeStatusOfOpenableStructInUnloadedSector( MEDUNA_ITEM_DROP_OFF_SECTOR_X, MEDUNA_ITEM_DROP_OFF_SECTOR_Y, MEDUNA_ITEM_DROP_OFF_SECTOR_Z, MEDUNA_ITEM_DROP_OFF_GRIDNO, FALSE );
}
for(i=0; i<gpNewBobbyrShipments[ ubOrderNum ].ubNumberPurchases; i++)
{
// Count how many items were purchased
usNumberOfItems += gpNewBobbyrShipments[ ubOrderNum ].BobbyRayPurchase[i].ubNumberPurchased;
}
//if we are NOT currently in the right sector
if( !fSectorLoaded )
{
//build an array of objects to be added
pObject = (OBJECTTYPE *) MemAlloc( sizeof( OBJECTTYPE ) * usNumberOfItems );
if( pObject == NULL )
return;
memset( pObject, 0, sizeof( OBJECTTYPE ) * usNumberOfItems );
}
uiCount = 0;
//loop through the number of purchases
for( i=0; i< gpNewBobbyrShipments->ubNumberPurchases; i++)
{
ubItemsDelivered = gpNewBobbyrShipments[ ubOrderNum ].BobbyRayPurchase[i].ubNumberPurchased;
usItem = gpNewBobbyrShipments[ ubOrderNum ].BobbyRayPurchase[i].usItemIndex;
while ( ubItemsDelivered )
{
// treat 0s as 1s :-)
ubTempNumItems = __min( ubItemsDelivered, __max( 1, Item[ usItem ].ubPerPocket ) );
CreateItems( usItem, gpNewBobbyrShipments[ ubOrderNum ].BobbyRayPurchase[i].bItemQuality, ubTempNumItems, &Object );
// stack as many as possible
if( fSectorLoaded )
{
AddItemToPool( MEDUNA_ITEM_DROP_OFF_GRIDNO, &Object, -1, 0, 0, 0 );
}
else
{
memcpy( &pObject[ uiCount ], &Object, sizeof( OBJECTTYPE ) );
uiCount++;
}
ubItemsDelivered -= ubTempNumItems;
}
}
//if the sector WASNT loaded
if( !fSectorLoaded )
{
//add all the items from the array that was built above
//The item are to be added to the Top part of Drassen, grid loc's 10112, 9950
if( !AddItemsToUnLoadedSector( MEDUNA_ITEM_DROP_OFF_SECTOR_X, MEDUNA_ITEM_DROP_OFF_SECTOR_Y, MEDUNA_ITEM_DROP_OFF_SECTOR_Z, MEDUNA_ITEM_DROP_OFF_GRIDNO, uiCount, pObject, 0, 0, 0, -1, FALSE ) )
{
//error
Assert( 0 );
}
MemFree( pObject );
pObject = NULL;
}
//mark that the shipment has arrived
gpNewBobbyrShipments[ ubOrderNum ].fActive = FALSE;
//Add an email from kulba telling the user the shipment is there
AddEmail( BOBBY_R_MEDUNA_SHIPMENT, BOBBY_R_MEDUNA_SHIPMENT_LENGTH, BOBBY_R, GetWorldTotalMin(), -1 );
}