From e3752a00fc4900b388eead0f96f08227f80374b5 Mon Sep 17 00:00:00 2001 From: Wanne Date: Wed, 1 Jan 2014 12:41:16 +0000 Subject: [PATCH] Creatures Externalizations (by Buggler) - externalized creatures placement and composition to CreaturePlacements.xml git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@6724 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- Init.cpp | 6 + Strategic/Creature Spreading.cpp | 456 ++++++++++++--- Strategic/Creature Spreading.h | 43 ++ Strategic/Strategic_VS2005.vcproj | 4 + Strategic/Strategic_VS2008.vcproj | 4 + Strategic/Strategic_VS2010.vcxproj | 1 + Strategic/Strategic_VS2010.vcxproj.filters | 3 + Strategic/Strategic_VS2013.vcxproj | 1 + Strategic/Strategic_VS2013.vcxproj.filters | 3 + Strategic/XML_Creatures.cpp | 649 +++++++++++++++++++++ Tactical/XML.h | 4 + 11 files changed, 1081 insertions(+), 93 deletions(-) create mode 100644 Strategic/XML_Creatures.cpp diff --git a/Init.cpp b/Init.cpp index 14bf2716..82b605f6 100644 --- a/Init.cpp +++ b/Init.cpp @@ -908,6 +908,12 @@ BOOLEAN LoadExternalGameplayData(STR directoryName) DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); SGP_THROW_IFFALSE(ReadInBloodcatPlacements(fileName), BLOODCATPLACEMENTSFILENAME); + // Buggler: Read in customized Creature Placements + strcpy(fileName, directoryName); + strcat(fileName, CREATUREPLACEMENTSFILENAME); + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + SGP_THROW_IFFALSE(ReadInCreaturePlacements(fileName), CREATUREPLACEMENTSFILENAME); + // HEADROCK HAM 3.6: Read in customized Uniform Colors strcpy(fileName, directoryName); strcat(fileName, UNIFORMCOLORSFILENAME); diff --git a/Strategic/Creature Spreading.cpp b/Strategic/Creature Spreading.cpp index 4fa922fc..4a42e8ca 100644 --- a/Strategic/Creature Spreading.cpp +++ b/Strategic/Creature Spreading.cpp @@ -109,6 +109,8 @@ //inside the function PrepareCreaturesForBattle() in this module. //BOOLEAN gfUseCreatureMusic = FALSE; // moved to music control.cpp BOOLEAN gfCreatureMeanwhileScenePlayed = FALSE; + +// externalize to xml data enum { QUEEN_LAIR, //where the queen lives. Highly protected @@ -151,6 +153,7 @@ void DeleteCreatureDirectives(); //extern MINE_STATUS_TYPE gMineStatus[ MAX_NUMBER_OF_MINES ]; + CREATURE_DIRECTIVE* NewDirective( UINT8 ubSectorID, UINT8 ubSectorZ, UINT8 ubCreatureHabitat ) { CREATURE_DIRECTIVE *curr; @@ -173,6 +176,7 @@ CREATURE_DIRECTIVE* NewDirective( UINT8 ubSectorID, UINT8 ubSectorZ, UINT8 ubCre return curr; } +/* // externalize to xml data void InitLairDrassen() { CREATURE_DIRECTIVE *curr; @@ -197,11 +201,33 @@ void InitLairDrassen() curr->next = NewDirective( SEC_D13, 1, MINE_EXIT ); } -void InitLairCambria() +void InitLairAlma() { CREATURE_DIRECTIVE *curr; giLairID = 2; //initialize the linked list of lairs + lair = NewDirective( SEC_K13, 3, QUEEN_LAIR ); + curr = lair; + if( !curr->pLevel->ubNumCreatures ) + { + curr->pLevel->ubNumCreatures = 1; //for the queen. + } + curr->next = NewDirective( SEC_J13, 3, LAIR ); + curr = curr->next; + curr->next = NewDirective( SEC_J13, 2, LAIR_ENTRANCE ); + curr = curr->next; + curr->next = NewDirective( SEC_J14, 2, INNER_MINE ); + curr = curr->next; + curr->next = NewDirective( SEC_J14, 1, OUTER_MINE ); + curr = curr->next; + curr->next = NewDirective( SEC_I14, 1, MINE_EXIT ); +} + +void InitLairCambria() +{ + CREATURE_DIRECTIVE *curr; + giLairID = 3; + //initialize the linked list of lairs lair = NewDirective( SEC_J8, 3, QUEEN_LAIR ); curr = lair; if( !curr->pLevel->ubNumCreatures ) @@ -221,28 +247,6 @@ void InitLairCambria() curr->next = NewDirective( SEC_H8, 1, MINE_EXIT ); } -void InitLairAlma() -{ - CREATURE_DIRECTIVE *curr; - giLairID = 3; - //initialize the linked list of lairs - lair = NewDirective( SEC_K13, 3, QUEEN_LAIR ); - curr = lair; - if( !curr->pLevel->ubNumCreatures ) - { - curr->pLevel->ubNumCreatures = 1; //for the queen. - } - curr->next = NewDirective( SEC_J13, 3, LAIR ); - curr = curr->next; - curr->next = NewDirective( SEC_J13, 2, LAIR_ENTRANCE ); - curr = curr->next; - curr->next = NewDirective( SEC_J14, 2, INNER_MINE ); - curr = curr->next; - curr->next = NewDirective( SEC_J14, 1, OUTER_MINE ); - curr = curr->next; - curr->next = NewDirective( SEC_I14, 1, MINE_EXIT ); -} - void InitLairGrumm() { CREATURE_DIRECTIVE *curr; @@ -266,6 +270,36 @@ void InitLairGrumm() curr = curr->next; curr->next = NewDirective( SEC_H3, 1, MINE_EXIT ); } +*/ + +void InitLair(INT32 iChosenMine) +{ + CREATURE_DIRECTIVE *curr; + giLairID = iChosenMine; + + // initialize the linked list of lairs + + // initialize the queen sector + lair = NewDirective( SECTOR( gCreaturePlacements[ giLairID ].sQueenX, gCreaturePlacements[ giLairID ].sQueenY ), + gCreaturePlacements[ giLairID ].ubQueenZ, QUEEN_LAIR ); + curr = lair; + + if( !curr->pLevel->ubNumCreatures ) + { + curr->pLevel->ubNumCreatures = 1; //for the queen. + } + + // initialize valid linked creature sectors + for (UINT8 i = 0; i < MAX_NUMBER_OF_CREATURE_SECTORS; i++) + { + if( gCreaturePlacements[ giLairID ].Habitat[ i ].fValid ) + { + curr->next = NewDirective( SECTOR( gCreaturePlacements[ giLairID ].Habitat[ i ].sX , gCreaturePlacements[ giLairID ].Habitat[ i ].sY ), + gCreaturePlacements[ giLairID ].Habitat[ i ].ubZ, gCreaturePlacements[ giLairID ].Habitat[ i ].ubComposition ); + curr = curr->next; + } + } +} #ifdef JA2BETAVERSION extern BOOLEAN gfExitViewer; @@ -276,13 +310,15 @@ void InitCreatureQuest() UNDERGROUND_SECTORINFO *curr; BOOLEAN fPlayMeanwhile = FALSE; INT32 i=-1; + INT32 x=0; INT32 iChosenMine; INT32 iRandom; - INT32 iNumMinesInfectible; + INT32 iNumMinesInfectible=0; + INT32 iNumMinesInfectibleLUA=0; #ifdef JA2BETAVERSION INT32 iOrigRandom; #endif - BOOLEAN fMineInfectible[4]; + BOOLEAN fMineInfectible[MAX_NUMBER_OF_INFECTIBLE_SITES]; if( giLairID ) { @@ -298,7 +334,7 @@ void InitCreatureQuest() fPlayMeanwhile = TRUE; #endif -#ifdef JA2UB +#ifdef JA2UB //Ja25 No meanwhiles && no creatures #else if( fPlayMeanwhile && !gfCreatureMeanwhileScenePlayed && gModSettings.CreatureMeanwhileCutscene == TRUE ) @@ -325,13 +361,14 @@ void InitCreatureQuest() break; } - //Determine which of the four maps are infectible by creatures. Infectible mines + //Determine which of the maps are infectible by creatures. Infectible mines //are those that are player controlled and unlimited. We don't want the creatures to //infect the mine that runs out. //Default them all to infectible - memset( fMineInfectible, 1, sizeof( BOOLEAN ) * 4 ); - + memset( fMineInfectible, 1, sizeof( BOOLEAN ) * MAX_NUMBER_OF_INFECTIBLE_SITES ); + + /* // externalize to xml data if( gMineStatus[ MINE_DRASSEN ].fAttackedHeadMiner || //gMineStatus[ MINE_DRASSEN ].uiOreRunningOutPoint || !gMineStatus[ MINE_DRASSEN ].fInfectible || @@ -365,15 +402,39 @@ void InitCreatureQuest() { //If head miner was attacked, ore will/has run out, or enemy controlled fMineInfectible[ 3 ] = FALSE; } + */ + + // determine mine infectible status + for (x = 0; x < MAX_NUMBER_OF_MINES; x++) + { + if( gMineStatus[ x ].fInfectible ) + { + if( gMineStatus[ x ].fAttackedHeadMiner || + //gMineStatus[ x ].uiOreRunningOutPoint || + !gMineStatus[ x ].fInfectible || + StrategicMap[ gMineStatus[ x ].StrategicIndex() ].fEnemyControlled ) + { //If head miner was attacked, ore will/has run out, or enemy controlled + fMineInfectible[ iNumMinesInfectibleLUA ] = FALSE; + } + iNumMinesInfectibleLUA++; + } + } #ifdef JA2BETAVERSION if( guiCurrentScreen == AIVIEWER_SCREEN ) { //If in the AIViewer, allow any mine to get infected - memset( fMineInfectible, 1, sizeof( BOOLEAN ) * 4 ); + memset( fMineInfectible, 1, sizeof( BOOLEAN ) * NUMBER_OF_INFECTIBLE_SITES ); } #endif - - iNumMinesInfectible = fMineInfectible[0] + fMineInfectible[1] + fMineInfectible[2] + fMineInfectible[3]; + + //// externalize to xml data + //iNumMinesInfectible = fMineInfectible[0] + fMineInfectible[1] + fMineInfectible[2] + fMineInfectible[3]; + + //count min of infectible sites defined in xml and initmines.lua script + for (x = 0; x < min( NUMBER_OF_INFECTIBLE_SITES, iNumMinesInfectibleLUA ); x++) + { + iNumMinesInfectible += fMineInfectible[x]; + } if( !iNumMinesInfectible ) { @@ -389,18 +450,19 @@ void InitCreatureQuest() iChosenMine = 0; - for( i = 0; i < 4; i++ ) + for( x = 0; x < min( NUMBER_OF_INFECTIBLE_SITES, iNumMinesInfectibleLUA ); x++ ) { if( iRandom ) { iChosenMine++; - if( fMineInfectible[i] ) + if( fMineInfectible[x] ) { iRandom--; } } } + /* // externalize to xml data //Now, choose a start location for the queen. switch( iChosenMine ) { @@ -409,16 +471,16 @@ void InitCreatureQuest() curr = FindUnderGroundSector( 13, 5, 1 ); curr->uiFlags |= SF_PENDING_ALTERNATE_MAP; break; - case 2: //Cambria - InitLairCambria(); - curr = FindUnderGroundSector( 9, 8, 1 ); - curr->uiFlags |= SF_PENDING_ALTERNATE_MAP; //entrance - break; - case 3: //Alma's mine + case 2: //Alma's mine InitLairAlma(); curr = FindUnderGroundSector( 14, 10, 1 ); curr->uiFlags |= SF_PENDING_ALTERNATE_MAP; break; + case 3: //Cambria + InitLairCambria(); + curr = FindUnderGroundSector( 9, 8, 1 ); + curr->uiFlags |= SF_PENDING_ALTERNATE_MAP; //entrance + break; case 4: //Grumm's mine InitLairGrumm(); curr = FindUnderGroundSector( 4, 8, 2 ); @@ -435,6 +497,15 @@ void InitCreatureQuest() #endif return; } + */ + + //Now, choose a start location for the queen. + InitLair( iChosenMine ); + + //load alternate map for creature changes + curr = FindUnderGroundSector( gCreaturePlacements[ giLairID ].sAltMapX, gCreaturePlacements[ giLairID ].sAltMapY, + gCreaturePlacements[ giLairID ].ubAltMapZ ); + curr->uiFlags |= SF_PENDING_ALTERNATE_MAP; //Now determine how often we will spread the creatures. switch( gGameOptions.ubDifficultyLevel ) @@ -520,6 +591,8 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"CreatureSpreading1"); INT32 iAbsoluteMaxPopulation; INT32 iMaxPopulation=-1; INT32 iChanceToPopulate; + + /* // externalize to xml data switch( node->pLevel->ubCreatureHabitat ) { case QUEEN_LAIR: //Defend the queen bonus @@ -547,6 +620,9 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"CreatureSpreading1"); Assert( 0 ); return FALSE; } + */ + + iAbsoluteMaxPopulation = gCreatureComposition[ node->pLevel->ubCreatureHabitat ].iMaxPopulation; switch( gGameOptions.ubDifficultyLevel ) { @@ -738,11 +814,15 @@ void AddCreaturesToBattle( UINT8 ubNumYoungMales, UINT8 ubNumYoungFemales, UINT8 void ChooseTownSectorToAttack( UINT8 ubSectorID, BOOLEAN fOverrideTest ) { - INT32 iRandom; + INT32 iRandom, i; UINT8 ubSectorX, ubSectorY; + INT8 bTownId, bTownSize; + UINT8 ubAttackSectorID; + ubSectorX = (UINT8)((ubSectorID % 16) + 1); ubSectorY = (UINT8)((ubSectorID / 16) + 1); + /* // externalize to xml data if( !fOverrideTest ) { iRandom = PreRandom( 100 ); @@ -750,52 +830,55 @@ void ChooseTownSectorToAttack( UINT8 ubSectorID, BOOLEAN fOverrideTest ) { case SEC_D13: //DRASSEN if( iRandom < 45 ) - ubSectorID = SEC_D13; + ubAttackSectorID = SEC_D13; else if( iRandom < 70 ) - ubSectorID = SEC_C13; + ubAttackSectorID = SEC_C13; else - ubSectorID = SEC_B13; + ubAttackSectorID = SEC_B13; break; case SEC_H3: //GRUMM if( iRandom < 35 ) - ubSectorID = SEC_H3; + ubAttackSectorID = SEC_H3; else if( iRandom < 55 ) - ubSectorID = SEC_H2; + ubAttackSectorID = SEC_H2; else if( iRandom < 70 ) - ubSectorID = SEC_G2; + ubAttackSectorID = SEC_G2; else if( iRandom < 85 ) - ubSectorID = SEC_H1; + ubAttackSectorID = SEC_H1; else - ubSectorID = SEC_G1; + ubAttackSectorID = SEC_G1; break; case SEC_H8: //CAMBRIA if( iRandom < 35 ) - ubSectorID = SEC_H8; + ubAttackSectorID = SEC_H8; else if( iRandom < 55 ) - ubSectorID = SEC_G8; + ubAttackSectorID = SEC_G8; else if( iRandom < 70 ) - ubSectorID = SEC_F8; + ubAttackSectorID = SEC_F8; else if( iRandom < 85 ) - ubSectorID = SEC_G9; + ubAttackSectorID = SEC_G9; else - ubSectorID = SEC_F9; + ubAttackSectorID = SEC_F9; break; case SEC_I14: //ALMA if( iRandom < 45 ) - ubSectorID = SEC_I14; + ubAttackSectorID = SEC_I14; else if( iRandom < 65 ) - ubSectorID = SEC_I13; + ubAttackSectorID = SEC_I13; else if( iRandom < 85 ) - ubSectorID = SEC_H14; + ubAttackSectorID = SEC_H14; else - ubSectorID = SEC_H13; + ubAttackSectorID = SEC_H13; break; default: Assert( 0 ); return; } } - switch( ubSectorID ) + else + ubAttackSectorID = ubSectorID; + + switch( ubAttackSectorID ) { case SEC_D13: //DRASSEN gsCreatureInsertionCode = INSERTION_CODE_GRIDNO; @@ -855,7 +938,59 @@ void ChooseTownSectorToAttack( UINT8 ubSectorID, BOOLEAN fOverrideTest ) default: return; } - gubSectorIDOfCreatureAttack = ubSectorID; + */ + + // determine the sector to attack + if( !fOverrideTest ) + { + bTownId = StrategicMap[ SECTOR_INFO_TO_STRATEGIC_INDEX ( ubSectorID )].bNameId; + bTownSize = GetTownSectorSize( bTownId ); + iRandom = PreRandom( bTownSize + 1 ) + 1; + + // originating sector has double the chance + if( iRandom == bTownSize + 1 ) + ubAttackSectorID = ubSectorID; + else + { + INT32 j=0; + for( i = 0; i < MAP_WORLD_X * MAP_WORLD_Y + 1; i++ ) + { + if( StrategicMap[ i ].bNameId == bTownId ) + { + j++; + if( iRandom == j ) + ubAttackSectorID = STRATEGIC_INDEX_TO_SECTOR_INFO( i ); + } + } + } + } + else + ubAttackSectorID = ubSectorID; + + // determine the attack sector insertion code + if( ubAttackSectorID == ubSectorID ) + { + gsCreatureInsertionCode = INSERTION_CODE_GRIDNO; + gsCreatureInsertionGridNo = gCreaturePlacements[ giLairID ].iAttackSourceGridNo; + } + else if ( ubAttackSectorID - ubSectorID < -15 ) + { + gsCreatureInsertionCode = INSERTION_CODE_SOUTH; + } + else if ( ubAttackSectorID - ubSectorID < 0 ) + { + gsCreatureInsertionCode = INSERTION_CODE_EAST; + } + else if ( ubAttackSectorID - ubSectorID < 16 ) + { + gsCreatureInsertionCode = INSERTION_CODE_WEST; + } + else + { + gsCreatureInsertionCode = INSERTION_CODE_NORTH; + } + + gubSectorIDOfCreatureAttack = ubAttackSectorID; } void CreatureAttackTown( UINT8 ubSectorID, BOOLEAN fOverrideTest ) @@ -1046,7 +1181,7 @@ void EndCreatureQuest() } //Remove the creatures that are trapped underneath Tixa - pSector = FindUnderGroundSector( 9, 10, 2 ); + pSector = FindUnderGroundSector( gModSettings.ubTixaPrisonSectorX, gModSettings.ubTixaPrisonSectorY, 2 ); if( pSector ) { pSector->ubNumCreatures = 0; @@ -1054,7 +1189,7 @@ void EndCreatureQuest() //Also find and nuke all creatures on any surface levels!!! //KM: Sept 3, 1999 patch - for( i = 0; i < 255; i++ ) + for( i = 0; i < SEC_P16 + 1; i++ ) { SectorInfo[ i ].ubNumCreatures = 0; SectorInfo[ i ].ubCreaturesInBattle = 0; @@ -1079,6 +1214,7 @@ BOOLEAN MineClearOfMonsters( UINT8 ubMineIndex ) if( !gMineStatus[ ubMineIndex ].fPrevInvadedByMonsters ) { + /* // externalize to xml data switch( ubMineIndex ) { case MINE_GRUMM: @@ -1122,6 +1258,19 @@ BOOLEAN MineClearOfMonsters( UINT8 ubMineIndex ) #endif break; } + */ + + // Buggler: use the defined underground mine sectors in lua script instead of the hardcoded ones + UINT32 i; + + for( i = 0; i < associatedMineSectors.size(); i++ ) + { + if( associatedMineSectors[ i ].mineID == ubMineIndex ) + { + if( CreaturesInUndergroundSector( SECTOR( associatedMineSectors[ i ].x, associatedMineSectors[ i ].y ), associatedMineSectors[ i ].z ) ) + return FALSE; + } + } } else { //mine was previously invaded by creatures. Don't allow mine production until queen is dead. @@ -1133,9 +1282,8 @@ BOOLEAN MineClearOfMonsters( UINT8 ubMineIndex ) return TRUE; } -void DetermineCreatureTownComposition( UINT8 ubNumCreatures, - UINT8 *pubNumYoungMales, UINT8 *pubNumYoungFemales, - UINT8 *pubNumAdultMales, UINT8 *pubNumAdultFemales ) +void DetermineCreatureTownComposition( UINT8 ubNumCreatures, UINT8 *pubNumYoungMales, UINT8 *pubNumYoungFemales, + UINT8 *pubNumAdultMales, UINT8 *pubNumAdultFemales ) { INT32 i, iRandom; UINT8 ubYoungMalePercentage = 10; @@ -1167,9 +1315,8 @@ void DetermineCreatureTownComposition( UINT8 ubNumCreatures, } } -void DetermineCreatureTownCompositionBasedOnTacticalInformation( UINT8 *pubNumCreatures, - UINT8 *pubNumYoungMales, UINT8 *pubNumYoungFemales, - UINT8 *pubNumAdultMales, UINT8 *pubNumAdultFemales ) +void DetermineCreatureTownCompositionBasedOnTacticalInformation( UINT8 *pubNumCreatures, UINT8 *pubNumYoungMales, UINT8 *pubNumYoungFemales, + UINT8 *pubNumAdultMales, UINT8 *pubNumAdultFemales ) { SECTORINFO *pSector; INT32 i; @@ -1292,10 +1439,28 @@ BOOLEAN PrepareCreaturesForBattle() #endif SetMusicMode( MUSIC_TACTICAL_NOTHING ); - ubCreatureHabitat = MINE_EXIT; + // externalize to xml data + //ubCreatureHabitat = MINE_EXIT; + + //assign the B1 underground habitat composition to the attacking creatures + for (UINT8 i = 0; i < MAX_NUMBER_OF_CREATURE_SECTORS; i++) + { + INT16 sX = gCreaturePlacements[ giLairID ].sAttackSourceX; + INT16 sY = gCreaturePlacements[ giLairID ].sAttackSourceX; + UINT8 ubZ = 1; + + if( sX == gCreaturePlacements[ giLairID ].Habitat[ i ].sX && + sY == gCreaturePlacements[ giLairID ].Habitat[ i ].sY && + ubZ == gCreaturePlacements[ giLairID ].Habitat[ i ].ubZ ) + { + ubCreatureHabitat = gCreaturePlacements[ giLairID ].Habitat[ i ].ubComposition; + break; + } + } ubNumCreatures = gubNumCreaturesAttackingTown; } + /* // externalize to xml data switch( ubCreatureHabitat ) { case QUEEN_LAIR: @@ -1335,6 +1500,7 @@ BOOLEAN PrepareCreaturesForBattle() ubAdultFemalePercentage = 30; break; case OUTER_MINE: + case FEEDING_GROUNDS: case MINE_EXIT: fQueen = FALSE; ubLarvaePercentage = 0; @@ -1350,6 +1516,26 @@ BOOLEAN PrepareCreaturesForBattle() #endif return FALSE; } + */ + + //out-of-range habitat + if( ubCreatureHabitat >= NUMBER_OF_CREATURE_COMPOSITIONS ) + { + AssertMsg( 0, String( "Invalid creature habitat ID of %d for PrepareCreaturesForBattle.", ubCreatureHabitat ) ); + } + + //queen sector + if( !ubCreatureHabitat ) + fQueen = TRUE; + else + fQueen = FALSE; + + ubLarvaePercentage = gCreatureComposition[ ubCreatureHabitat ].ubLarvaePercent; + ubInfantPercentage = gCreatureComposition[ ubCreatureHabitat ].ubInfantPercent; + ubYoungMalePercentage = gCreatureComposition[ ubCreatureHabitat ].ubYoungMalePercent; + ubYoungFemalePercentage = gCreatureComposition[ ubCreatureHabitat ].ubYoungFemalePercent; + ubAdultMalePercentage = gCreatureComposition[ ubCreatureHabitat ].ubAdultMalePercent; + ubAdultFemalePercentage = gCreatureComposition[ ubCreatureHabitat ].ubAdultFemalePercent; //First step is to convert the percentages into the numbers we will use. if( fQueen ) @@ -1423,6 +1609,8 @@ void CreatureNightPlanning() { //Check the populations of the mine exits, and factor a chance for them to attack at night. UINT8 ubNumCreatures; + + /* // externalize to xml data ubNumCreatures = CreaturesInUndergroundSector( SEC_H3, 1 ); if( ubNumCreatures > 1 && ubNumCreatures * 10 > (INT32)PreRandom( 100 ) ) { //10% chance for each creature to decide it's time to attack. @@ -1443,6 +1631,17 @@ void CreatureNightPlanning() { //10% chance for each creature to decide it's time to attack. AddStrategicEvent( EVENT_CREATURE_ATTACK, GetWorldTotalMin() + 1 +PreRandom( 429 ), SEC_H8 ); } + */ + + UINT8 ubSectorID = SECTOR( gCreaturePlacements[ giLairID ].sAttackSourceX, gCreaturePlacements[ giLairID ].sAttackSourceY ); + + // Attacksource B1 underground sector must be a valid creature habitat! + ubNumCreatures = CreaturesInUndergroundSector( ubSectorID , 1 ); + + if( ubNumCreatures > 1 && ubNumCreatures * 10 > (INT32)PreRandom( 100 ) ) + { //10% chance for each creature to decide it's time to attack. + AddStrategicEvent( EVENT_CREATURE_ATTACK, GetWorldTotalMin() + 1 +PreRandom( 429 ), ubSectorID ); + } } @@ -1568,7 +1767,7 @@ BOOLEAN LoadCreatureDirectives( HWFILE hFile, UINT32 uiSavedGameVersion ) if( gfClearCreatureQuest && giLairID != -1 ) { giLairID = 0; -#ifdef JA2UB +#ifdef JA2UB // no UB #else gfCreatureMeanwhileScenePlayed = FALSE; @@ -1578,20 +1777,57 @@ BOOLEAN LoadCreatureDirectives( HWFILE hFile, UINT32 uiSavedGameVersion ) gfClearCreatureQuest = FALSE; #endif + /* // externalize to xml data switch( giLairID ) { - case -1: break; //creature quest finished -- it's okay - case 0: break; //lair doesn't exist yet -- it's okay - case 1: InitLairDrassen(); break; - case 2: InitLairCambria(); break; - case 3: InitLairAlma(); break; - case 4: InitLairGrumm(); break; + case -1: + break; //creature quest finished -- it's okay + case 0: + break; //lair doesn't exist yet -- it's okay + case 1: + InitLairDrassen(); + break; + case 2: + InitLairAlma(); + break; + case 3: + InitLairCambria(); + break; + case 4: + InitLairGrumm(); + break; default: #ifdef JA2BETAVERSION ScreenMsg( FONT_RED, MSG_ERROR, L"Invalid restoration of creature lair ID of %d. Save game potentially hosed.", giLairID ); #endif break; } + */ + + //count infectible sites defined initmines.lua script + INT32 iNumMinesInfectibleLUA=0; + + for (INT32 x = 0; x < MAX_NUMBER_OF_MINES; x++) + { + if( gMineStatus[ x ].fInfectible ) + iNumMinesInfectibleLUA++; + } + + if( giLairID <= 0 ) + { + //quest finished/lair doesn't exist yet -- it's okay + } + else if( giLairID <= min( NUMBER_OF_INFECTIBLE_SITES, iNumMinesInfectibleLUA ) ) + { + InitLair( giLairID ); + } + else + { + #ifdef JA2BETAVERSION + ScreenMsg( FONT_RED, MSG_ERROR, L"Invalid restoration of creature lair ID of %d. Save game potentially hosed.", giLairID ); + #endif + } + return( TRUE ); } @@ -1666,9 +1902,10 @@ BOOLEAN GetWarpOutOfMineCodes( INT16 *psSectorX, INT16 *psSectorY, INT8 *pbSecto if( !iSwitchValue ) { - return FALSE; + return( FALSE ); } - + + /* // externalize to xml data //Now make sure the mercs are in the previously infested mine switch( iSwitchValue ) { @@ -1688,21 +1925,6 @@ BOOLEAN GetWarpOutOfMineCodes( INT16 *psSectorX, INT16 *psSectorY, INT8 *pbSecto return TRUE; } break; - case 3: //Cambria - if( gWorldSectorX == 8 && gWorldSectorY == 9 && gbWorldSectorZ == 3 || - gWorldSectorX == 8 && gWorldSectorY == 8 && gbWorldSectorZ == 3 || - gWorldSectorX == 8 && gWorldSectorY == 8 && gbWorldSectorZ == 2 || - gWorldSectorX == 9 && gWorldSectorY == 8 && gbWorldSectorZ == 2 || - gWorldSectorX == 9 && gWorldSectorY == 8 && gbWorldSectorZ == 1 || - gWorldSectorX == 8 && gWorldSectorY == 8 && gbWorldSectorZ == 1 ) - { - *psSectorX = 8; - *psSectorY = 8; - *pbSectorZ = 0; - *psInsertionGridNo = 13002;//dnl!!! - return TRUE; - } - break; case 2: //Alma if( gWorldSectorX == 13 && gWorldSectorY == 11 && gbWorldSectorZ == 3 || gWorldSectorX == 13 && gWorldSectorY == 10 && gbWorldSectorZ == 3 || @@ -1718,6 +1940,21 @@ BOOLEAN GetWarpOutOfMineCodes( INT16 *psSectorX, INT16 *psSectorY, INT8 *pbSecto return TRUE; } break; + case 3: //Cambria + if( gWorldSectorX == 8 && gWorldSectorY == 9 && gbWorldSectorZ == 3 || + gWorldSectorX == 8 && gWorldSectorY == 8 && gbWorldSectorZ == 3 || + gWorldSectorX == 8 && gWorldSectorY == 8 && gbWorldSectorZ == 2 || + gWorldSectorX == 9 && gWorldSectorY == 8 && gbWorldSectorZ == 2 || + gWorldSectorX == 9 && gWorldSectorY == 8 && gbWorldSectorZ == 1 || + gWorldSectorX == 8 && gWorldSectorY == 8 && gbWorldSectorZ == 1 ) + { + *psSectorX = 8; + *psSectorY = 8; + *pbSectorZ = 0; + *psInsertionGridNo = 13002;//dnl!!! + return TRUE; + } + break; case 4: //Grumm if( gWorldSectorX == 4 && gWorldSectorY == 7 && gbWorldSectorZ == 3 || gWorldSectorX == 4 && gWorldSectorY == 8 && gbWorldSectorZ == 3 || @@ -1735,5 +1972,38 @@ BOOLEAN GetWarpOutOfMineCodes( INT16 *psSectorX, INT16 *psSectorY, INT8 *pbSecto } break; } + */ + + //Now make sure the mercs are in the previously infested mine + else + { + // queen sector + if( gWorldSectorX == gCreaturePlacements[ iSwitchValue ].sQueenX + && gWorldSectorY == gCreaturePlacements[ iSwitchValue ].sQueenY + && gbWorldSectorZ == gCreaturePlacements[ iSwitchValue ].ubQueenZ ) + { + *psSectorX = gCreaturePlacements[ iSwitchValue ].sWarpToX; + *psSectorY = gCreaturePlacements[ iSwitchValue ].sWarpToY; + *pbSectorZ = gCreaturePlacements[ iSwitchValue ].ubWarpToZ; + *psInsertionGridNo = gCreaturePlacements[ iSwitchValue ].iWarpToGridNo; + return( TRUE ); + } + + // other creature habitat sector + for (UINT8 i = 0; i < MAX_NUMBER_OF_CREATURE_SECTORS; i++) + { + if( gWorldSectorX == gCreaturePlacements[ iSwitchValue ].Habitat[ i ].sX + && gWorldSectorY == gCreaturePlacements[ iSwitchValue ].Habitat[ i ].sY + && gbWorldSectorZ == gCreaturePlacements[ iSwitchValue ].Habitat[ i ].ubZ ) + { + *psSectorX = gCreaturePlacements[ iSwitchValue ].sWarpToX; + *psSectorY = gCreaturePlacements[ iSwitchValue ].sWarpToY; + *pbSectorZ = gCreaturePlacements[ iSwitchValue ].ubWarpToZ; + *psInsertionGridNo = gCreaturePlacements[ iSwitchValue ].iWarpToGridNo; + return( TRUE ); + } + } + } + return( FALSE ); } diff --git a/Strategic/Creature Spreading.h b/Strategic/Creature Spreading.h index 6aae1b5b..0fdae122 100644 --- a/Strategic/Creature Spreading.h +++ b/Strategic/Creature Spreading.h @@ -57,4 +57,47 @@ BOOLEAN PlayerGroupIsInACreatureInfestedMine(); extern INT32 giLairID; +// Buggler: creature XML definitions +// actual infectible sites defined in XML +extern UINT8 NUMBER_OF_INFECTIBLE_SITES; +extern UINT8 NUMBER_OF_CREATURE_COMPOSITIONS; + +#define MAX_NUMBER_OF_INFECTIBLE_SITES 10 +#define MAX_NUMBER_OF_CREATURE_SECTORS 50 +#define MAX_NUMBER_OF_CREATURE_COMPOSITIONS 30 + +typedef struct CREATUREHABITAT +{ + INT16 sX, sY; + UINT8 ubZ; + UINT8 ubComposition; + BOOLEAN fValid; +} CREATUREHABITAT; + +typedef struct CREATUREPLACEMENT +{ + INT16 sAttackSourceX, sAttackSourceY; + INT32 iAttackSourceGridNo; + INT16 sAltMapX, sAltMapY; + UINT8 ubAltMapZ; + INT16 sWarpToX, sWarpToY; + UINT8 ubWarpToZ; + INT32 iWarpToGridNo; + INT16 sQueenX, sQueenY; + UINT8 ubQueenZ; + CREATUREHABITAT Habitat[ MAX_NUMBER_OF_CREATURE_SECTORS ]; +}CREATUREPLACEMENT; + +typedef struct CREATURECOMPOSITION +{ + UINT8 ubLarvaePercent, ubInfantPercent; + UINT8 ubYoungMalePercent, ubYoungFemalePercent; + UINT8 ubAdultMalePercent, ubAdultFemalePercent; + INT32 iMaxPopulation; +}CREATURECOMPOSITION; + +// This array stores all XML-read creature placement data, valid giLairID starts at 1 +extern CREATUREPLACEMENT gCreaturePlacements[ MAX_NUMBER_OF_INFECTIBLE_SITES + 1 ]; +extern CREATURECOMPOSITION gCreatureComposition[ MAX_NUMBER_OF_CREATURE_COMPOSITIONS ]; + #endif \ No newline at end of file diff --git a/Strategic/Strategic_VS2005.vcproj b/Strategic/Strategic_VS2005.vcproj index 7b2a269a..48cdd04f 100644 --- a/Strategic/Strategic_VS2005.vcproj +++ b/Strategic/Strategic_VS2005.vcproj @@ -752,6 +752,10 @@ RelativePath=".\XML_CoolnessBySector.cpp" > + + diff --git a/Strategic/Strategic_VS2008.vcproj b/Strategic/Strategic_VS2008.vcproj index 8d575cb0..0c8182db 100644 --- a/Strategic/Strategic_VS2008.vcproj +++ b/Strategic/Strategic_VS2008.vcproj @@ -750,6 +750,10 @@ RelativePath=".\XML_CoolnessBySector.cpp" > + + diff --git a/Strategic/Strategic_VS2010.vcxproj b/Strategic/Strategic_VS2010.vcxproj index 904cf0e7..58dec1a8 100644 --- a/Strategic/Strategic_VS2010.vcxproj +++ b/Strategic/Strategic_VS2010.vcxproj @@ -127,6 +127,7 @@ + diff --git a/Strategic/Strategic_VS2010.vcxproj.filters b/Strategic/Strategic_VS2010.vcxproj.filters index eacdd124..b39bbf5d 100644 --- a/Strategic/Strategic_VS2010.vcxproj.filters +++ b/Strategic/Strategic_VS2010.vcxproj.filters @@ -344,5 +344,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/Strategic/Strategic_VS2013.vcxproj b/Strategic/Strategic_VS2013.vcxproj index 4adfaff9..eab489af 100644 --- a/Strategic/Strategic_VS2013.vcxproj +++ b/Strategic/Strategic_VS2013.vcxproj @@ -127,6 +127,7 @@ + diff --git a/Strategic/Strategic_VS2013.vcxproj.filters b/Strategic/Strategic_VS2013.vcxproj.filters index eacdd124..b39bbf5d 100644 --- a/Strategic/Strategic_VS2013.vcxproj.filters +++ b/Strategic/Strategic_VS2013.vcxproj.filters @@ -344,5 +344,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/Strategic/XML_Creatures.cpp b/Strategic/XML_Creatures.cpp new file mode 100644 index 00000000..d51b4103 --- /dev/null +++ b/Strategic/XML_Creatures.cpp @@ -0,0 +1,649 @@ +#ifdef PRECOMPILEDHEADERS + #include "Strategic All.h" + +#else + #include "expat.h" + #include "string.h" + #include "Campaign Types.h" + #include "FileMan.h" + #include "MemMan.h" + #include "Debug Control.h" + #include "Creature Spreading.h" +#endif + +// Buggler: creature XML externalization stuff +#define MAX_CHAR_DATA_LENGTH 500 +#define INVALID_CREATURESITE_INDEX -1 +#define INVALID_COMPOSITION_INDEX -1 + +// This array stores all XML-read creature placement data, valid giLairID starts at 1 +CREATUREPLACEMENT gCreaturePlacements[ MAX_NUMBER_OF_INFECTIBLE_SITES + 1]; +CREATURECOMPOSITION gCreatureComposition[ MAX_NUMBER_OF_CREATURE_COMPOSITIONS ]; + + +// actual infectible sites defined in XML +UINT8 NUMBER_OF_INFECTIBLE_SITES; +UINT8 NUMBER_OF_CREATURE_COMPOSITIONS; + +typedef enum +{ + CREATURE_ELEMENT_NONE = 0, + CREATURE_ELEMENT_CREATUREINFO, + CREATURE_ELEMENT_COMPOSITIONLIST, + CREATURE_ELEMENT_COMPOSITION, + CREATURE_ELEMENT_COMPINDEX, + CREATURE_ELEMENT_LARVAEPERCENT, + CREATURE_ELEMENT_INFANTPERCENT, + CREATURE_ELEMENT_YMALEPERCENT, + CREATURE_ELEMENT_YFEMALEPERCENT, + CREATURE_ELEMENT_AMALEPERCENT, + CREATURE_ELEMENT_AFEMALEPERCENT, + CREATURE_ELEMENT_MAXPOPULATION, + CREATURE_ELEMENT_PLACEMENTLIST, + CREATURE_ELEMENT_PLACEMENT, + CREATURE_ELEMENT_INDEX, + CREATURE_ELEMENT_ATTACKSOURCE, + CREATURE_ELEMENT_ATTACKSOURCE_SECTOR, + CREATURE_ELEMENT_ATTACKSOURCE_GRIDNO, + CREATURE_ELEMENT_ALTERNATEMAP, + CREATURE_ELEMENT_ALTERNATEMAP_SECTOR, + CREATURE_ELEMENT_ALTERNATEMAP_Z, + CREATURE_ELEMENT_WARPTO, + CREATURE_ELEMENT_WARPTO_SECTOR, + CREATURE_ELEMENT_WARPTO_Z, + CREATURE_ELEMENT_WARPTO_GRIDNO, + CREATURE_ELEMENT_CREATURESECTOR, + CREATURE_ELEMENT_QUEEN, + CREATURE_ELEMENT_QUEEN_SECTOR, + CREATURE_ELEMENT_QUEEN_Z, + CREATURE_ELEMENT_HABITAT, + CREATURE_ELEMENT_HABITAT_SECTOR, + CREATURE_ELEMENT_HABITAT_Z, + CREATURE_ELEMENT_HABITAT_COMPOSITION, + CREATURE_ELEMENT_HABITAT_VALID, +} CREATURE_PARSE_STAGE; + +typedef struct +{ + CREATURE_PARSE_STAGE curElement; + CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1]; + + CREATUREPLACEMENT curPlacementInfo; + CREATURECOMPOSITION curCompositionInfo; + UINT32 curIndex; + UINT32 uiHighestIndex; + UINT32 uiCompHighestIndex; + UINT32 curHabitat; + + UINT32 currentDepth; + UINT32 maxReadDepth; +} CreatureParseData; + +static void XMLCALL +creatureplacementStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts) +{ + CreatureParseData * pData = (CreatureParseData *) userData; + + if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element? + { + + if(strcmp(name, "CREATURE_INFO") == 0 && pData->curElement == CREATURE_ELEMENT_NONE) + { + pData->curElement = CREATURE_ELEMENT_CREATUREINFO; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "COMPOSITION_LIST") == 0 && pData->curElement == CREATURE_ELEMENT_CREATUREINFO) + { + pData->curElement = CREATURE_ELEMENT_COMPOSITIONLIST; + pData->maxReadDepth++; //we are not skipping this element + + // Initiate Array by setting all values to 0 + for (UINT16 x = 0; x < MAX_NUMBER_OF_CREATURE_COMPOSITIONS; x++) + { + gCreatureComposition[x].ubLarvaePercent = 0; + gCreatureComposition[x].ubInfantPercent = 0; + gCreatureComposition[x].ubYoungMalePercent = 0; + gCreatureComposition[x].ubYoungFemalePercent = 0; + gCreatureComposition[x].ubAdultMalePercent = 0; + gCreatureComposition[x].ubAdultFemalePercent = 0; + gCreatureComposition[x].iMaxPopulation = 0; + } + } + else if(strcmp(name, "COMPOSITION") == 0 && pData->curElement == CREATURE_ELEMENT_COMPOSITIONLIST) + { + pData->curElement = CREATURE_ELEMENT_COMPOSITION; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "CompIndex") == 0 && pData->curElement == CREATURE_ELEMENT_COMPOSITION) + { + pData->curElement = CREATURE_ELEMENT_COMPINDEX; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "LarvaePercent") == 0 && pData->curElement == CREATURE_ELEMENT_COMPOSITION) + { + pData->curElement = CREATURE_ELEMENT_LARVAEPERCENT; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "InfantPercent") == 0 && pData->curElement == CREATURE_ELEMENT_COMPOSITION) + { + pData->curElement = CREATURE_ELEMENT_INFANTPERCENT; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "YoungMalePercent") == 0 && pData->curElement == CREATURE_ELEMENT_COMPOSITION) + { + pData->curElement = CREATURE_ELEMENT_YMALEPERCENT; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "YoungFemalePercent") == 0 && pData->curElement == CREATURE_ELEMENT_COMPOSITION) + { + pData->curElement = CREATURE_ELEMENT_YFEMALEPERCENT; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "AdultMalePercent") == 0 && pData->curElement == CREATURE_ELEMENT_COMPOSITION) + { + pData->curElement = CREATURE_ELEMENT_AMALEPERCENT; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "AdultFemalePercent") == 0 && pData->curElement == CREATURE_ELEMENT_COMPOSITION) + { + pData->curElement = CREATURE_ELEMENT_AFEMALEPERCENT; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "MaxPopulation") == 0 && pData->curElement == CREATURE_ELEMENT_COMPOSITION) + { + pData->curElement = CREATURE_ELEMENT_MAXPOPULATION; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "PLACEMENT_LIST") == 0 && pData->curElement == CREATURE_ELEMENT_CREATUREINFO) + { + pData->curElement = CREATURE_ELEMENT_PLACEMENTLIST; + pData->maxReadDepth++; //we are not skipping this element + + // Initiate Array by setting all values to 0 + for (UINT16 x = 0; x < MAX_NUMBER_OF_INFECTIBLE_SITES + 1; x++) + { + gCreaturePlacements[x].sAltMapX = 0; + gCreaturePlacements[x].sAltMapY = 0; + gCreaturePlacements[x].ubAltMapZ = 0; + gCreaturePlacements[x].sQueenX = 0; + gCreaturePlacements[x].sQueenY = 0; + gCreaturePlacements[x].ubQueenZ = 0; + gCreaturePlacements[x].sAttackSourceX = 0; + gCreaturePlacements[x].sAttackSourceY = 0; + gCreaturePlacements[x].iAttackSourceGridNo = 0; + gCreaturePlacements[x].sWarpToX = 0; + gCreaturePlacements[x].sWarpToY = 0; + gCreaturePlacements[x].ubWarpToZ = 0; + gCreaturePlacements[x].iWarpToGridNo = 0; + for (UINT16 y = 0; y < MAX_NUMBER_OF_CREATURE_SECTORS; y++) + { + gCreaturePlacements[x].Habitat[y].sX = 0; + gCreaturePlacements[x].Habitat[y].sY = 0; + gCreaturePlacements[x].Habitat[y].ubZ = 0; + gCreaturePlacements[x].Habitat[y].ubComposition = 0; + gCreaturePlacements[x].Habitat[y].fValid = 0; + } + } + } + else if(strcmp(name, "PLACEMENT") == 0 && pData->curElement == CREATURE_ELEMENT_PLACEMENTLIST) + { + pData->curElement = CREATURE_ELEMENT_PLACEMENT; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "Index") == 0 && pData->curElement == CREATURE_ELEMENT_PLACEMENT) + { + pData->curElement = CREATURE_ELEMENT_INDEX; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "ATTACKSOURCE") == 0 && pData->curElement == CREATURE_ELEMENT_PLACEMENT) + { + pData->curElement = CREATURE_ELEMENT_ATTACKSOURCE; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "SectorGrid") == 0 && pData->curElement == CREATURE_ELEMENT_ATTACKSOURCE) + { + pData->curElement = CREATURE_ELEMENT_ATTACKSOURCE_SECTOR; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "GridNo") == 0 && pData->curElement == CREATURE_ELEMENT_ATTACKSOURCE) + { + pData->curElement = CREATURE_ELEMENT_ATTACKSOURCE_GRIDNO; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "ALTERNATEMAP") == 0 && pData->curElement == CREATURE_ELEMENT_PLACEMENT) + { + pData->curElement = CREATURE_ELEMENT_ALTERNATEMAP; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "SectorGrid") == 0 && pData->curElement == CREATURE_ELEMENT_ALTERNATEMAP) + { + pData->curElement = CREATURE_ELEMENT_ALTERNATEMAP_SECTOR; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "SectorZ") == 0 && pData->curElement == CREATURE_ELEMENT_ALTERNATEMAP) + { + pData->curElement = CREATURE_ELEMENT_ALTERNATEMAP_Z; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "WARPTOSECTOR") == 0 && pData->curElement == CREATURE_ELEMENT_PLACEMENT) + { + pData->curElement = CREATURE_ELEMENT_WARPTO; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "SectorGrid") == 0 && pData->curElement == CREATURE_ELEMENT_WARPTO) + { + pData->curElement = CREATURE_ELEMENT_WARPTO_SECTOR; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "SectorZ") == 0 && pData->curElement == CREATURE_ELEMENT_WARPTO) + { + pData->curElement = CREATURE_ELEMENT_WARPTO_Z; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "GridNo") == 0 && pData->curElement == CREATURE_ELEMENT_WARPTO) + { + pData->curElement = CREATURE_ELEMENT_WARPTO_GRIDNO; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "CREATURESECTOR") == 0 && pData->curElement == CREATURE_ELEMENT_PLACEMENT) + { + pData->curElement = CREATURE_ELEMENT_CREATURESECTOR; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "QUEENSECTOR") == 0 && pData->curElement == CREATURE_ELEMENT_CREATURESECTOR) + { + pData->curElement = CREATURE_ELEMENT_QUEEN; + pData->curHabitat = 0; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "SectorGrid") == 0 && pData->curElement == CREATURE_ELEMENT_QUEEN) + { + pData->curElement = CREATURE_ELEMENT_QUEEN_SECTOR; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "SectorZ") == 0 && pData->curElement == CREATURE_ELEMENT_QUEEN) + { + pData->curElement = CREATURE_ELEMENT_QUEEN_Z; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "HABITATSECTOR") == 0 && pData->curElement == CREATURE_ELEMENT_CREATURESECTOR) + { + pData->curElement = CREATURE_ELEMENT_HABITAT; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "SectorGrid") == 0 && pData->curElement == CREATURE_ELEMENT_HABITAT) + { + pData->curElement = CREATURE_ELEMENT_HABITAT_SECTOR; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "SectorZ") == 0 && pData->curElement == CREATURE_ELEMENT_HABITAT) + { + pData->curElement = CREATURE_ELEMENT_HABITAT_Z; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "Composition") == 0 && pData->curElement == CREATURE_ELEMENT_HABITAT) + { + pData->curElement = CREATURE_ELEMENT_HABITAT_COMPOSITION; + pData->maxReadDepth++; //we are not skipping this element + } + pData->szCharData[0] = '\0'; + } + + pData->currentDepth++; + +} + +static void XMLCALL +creatureplacementCharacterDataHandle(void *userData, const XML_Char *str, int len) +{ + CreatureParseData * pData = (CreatureParseData *) userData; + + if(pData->currentDepth <= pData->maxReadDepth && strlen(pData->szCharData) < MAX_CHAR_DATA_LENGTH) + strncat(pData->szCharData,str,__min((unsigned int)len,MAX_CHAR_DATA_LENGTH-strlen(pData->szCharData))); +} + +static void XMLCALL +creatureplacementEndElementHandle(void *userData, const XML_Char *name) +{ + CreatureParseData * pData = (CreatureParseData *) userData; + + if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading + { + if(strcmp(name, "CREATURE_INFO") == 0 && pData->curElement == CREATURE_ELEMENT_CREATUREINFO) + { + pData->curElement = CREATURE_ELEMENT_NONE; + } + else if(strcmp(name, "COMPOSITION_LIST") == 0 && pData->curElement == CREATURE_ELEMENT_COMPOSITIONLIST) + { + pData->curElement = CREATURE_ELEMENT_CREATUREINFO; + + // CompIndex starts at 0 + NUMBER_OF_CREATURE_COMPOSITIONS = pData->uiCompHighestIndex + 1; + } + else if(strcmp(name, "COMPOSITION") == 0 && pData->curElement == CREATURE_ELEMENT_COMPOSITION) + { + pData->curElement = CREATURE_ELEMENT_COMPOSITIONLIST; + + if ( pData->curIndex != INVALID_CREATURESITE_INDEX ) + { + // valid creature composition index starts at 0 + gCreatureComposition[pData->curIndex].ubLarvaePercent = pData->curCompositionInfo.ubLarvaePercent; + gCreatureComposition[pData->curIndex].ubInfantPercent = pData->curCompositionInfo.ubInfantPercent; + gCreatureComposition[pData->curIndex].ubYoungMalePercent = pData->curCompositionInfo.ubYoungMalePercent; + gCreatureComposition[pData->curIndex].ubYoungFemalePercent = pData->curCompositionInfo.ubYoungFemalePercent; + gCreatureComposition[pData->curIndex].ubAdultMalePercent = pData->curCompositionInfo.ubAdultMalePercent; + gCreatureComposition[pData->curIndex].ubAdultFemalePercent = pData->curCompositionInfo.ubAdultFemalePercent; + gCreatureComposition[pData->curIndex].iMaxPopulation = pData->curCompositionInfo.iMaxPopulation; + } + } + else if(strcmp(name, "CompIndex") == 0 && pData->curElement == CREATURE_ELEMENT_COMPINDEX) + { + pData->curElement = CREATURE_ELEMENT_COMPOSITION; + + pData->curIndex = atol(pData->szCharData); + // CompIndex starts at 0 + if ( pData->curIndex < 0 || pData->curIndex > MAX_NUMBER_OF_CREATURE_COMPOSITIONS ) + { + pData->curIndex = INVALID_COMPOSITION_INDEX; + } + else if ( pData->curIndex > pData->uiCompHighestIndex ) + { + pData->uiCompHighestIndex = pData->curIndex; + } + } + else if(strcmp(name, "LarvaePercent") == 0 && pData->curElement == CREATURE_ELEMENT_LARVAEPERCENT) + { + pData->curElement = CREATURE_ELEMENT_COMPOSITION; + + pData->curCompositionInfo.ubLarvaePercent = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "InfantPercent") == 0 && pData->curElement == CREATURE_ELEMENT_INFANTPERCENT) + { + pData->curElement = CREATURE_ELEMENT_COMPOSITION; + + pData->curCompositionInfo.ubInfantPercent = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "YoungMalePercent") == 0 && pData->curElement == CREATURE_ELEMENT_YMALEPERCENT) + { + pData->curElement = CREATURE_ELEMENT_COMPOSITION; + + pData->curCompositionInfo.ubYoungMalePercent = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "YoungFemalePercent") == 0 && pData->curElement == CREATURE_ELEMENT_YFEMALEPERCENT) + { + pData->curElement = CREATURE_ELEMENT_COMPOSITION; + + pData->curCompositionInfo.ubYoungFemalePercent = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "AdultMalePercent") == 0 && pData->curElement == CREATURE_ELEMENT_AMALEPERCENT) + { + pData->curElement = CREATURE_ELEMENT_COMPOSITION; + + pData->curCompositionInfo.ubAdultMalePercent = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "AdultFemalePercent") == 0 && pData->curElement == CREATURE_ELEMENT_AFEMALEPERCENT) + { + pData->curElement = CREATURE_ELEMENT_COMPOSITION; + + pData->curCompositionInfo.ubAdultFemalePercent = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "MaxPopulation") == 0 && pData->curElement == CREATURE_ELEMENT_MAXPOPULATION) + { + pData->curElement = CREATURE_ELEMENT_COMPOSITION; + + pData->curCompositionInfo.iMaxPopulation = (INT32) atol(pData->szCharData); + } + else if(strcmp(name, "PLACEMENT_LIST") == 0 && pData->curElement == CREATURE_ELEMENT_PLACEMENTLIST) + { + pData->curElement = CREATURE_ELEMENT_CREATUREINFO; + + NUMBER_OF_INFECTIBLE_SITES = pData->uiHighestIndex; + } + else if(strcmp(name, "PLACEMENT") == 0 && pData->curElement == CREATURE_ELEMENT_PLACEMENT) + { + pData->curElement = CREATURE_ELEMENT_PLACEMENTLIST; + + if ( pData->curIndex != INVALID_CREATURESITE_INDEX ) + { + // valid giLairID starts at 1 + gCreaturePlacements[pData->curIndex].sAltMapX = pData->curPlacementInfo.sAltMapX; + gCreaturePlacements[pData->curIndex].sAltMapY = pData->curPlacementInfo.sAltMapY; + gCreaturePlacements[pData->curIndex].ubAltMapZ = pData->curPlacementInfo.ubAltMapZ; + gCreaturePlacements[pData->curIndex].sQueenX = pData->curPlacementInfo.sQueenX; + gCreaturePlacements[pData->curIndex].sQueenY = pData->curPlacementInfo.sQueenY; + gCreaturePlacements[pData->curIndex].ubQueenZ = pData->curPlacementInfo.ubQueenZ; + gCreaturePlacements[pData->curIndex].sAttackSourceX = pData->curPlacementInfo.sAttackSourceX; + gCreaturePlacements[pData->curIndex].sAttackSourceY = pData->curPlacementInfo.sAttackSourceY; + gCreaturePlacements[pData->curIndex].iAttackSourceGridNo = pData->curPlacementInfo.iAttackSourceGridNo; + gCreaturePlacements[pData->curIndex].sWarpToX = pData->curPlacementInfo.sWarpToX; + gCreaturePlacements[pData->curIndex].sWarpToY = pData->curPlacementInfo.sWarpToY; + gCreaturePlacements[pData->curIndex].ubWarpToZ = pData->curPlacementInfo.ubWarpToZ; + gCreaturePlacements[pData->curIndex].iWarpToGridNo = pData->curPlacementInfo.iWarpToGridNo; + + for (UINT8 y = 0; y < MAX_NUMBER_OF_CREATURE_SECTORS; y++) + { + gCreaturePlacements[pData->curIndex].Habitat[y].sX = pData->curPlacementInfo.Habitat[y].sX; + gCreaturePlacements[pData->curIndex].Habitat[y].sY = pData->curPlacementInfo.Habitat[y].sY; + gCreaturePlacements[pData->curIndex].Habitat[y].ubZ = pData->curPlacementInfo.Habitat[y].ubZ; + gCreaturePlacements[pData->curIndex].Habitat[y].ubComposition = pData->curPlacementInfo.Habitat[y].ubComposition; + gCreaturePlacements[pData->curIndex].Habitat[y].fValid = pData->curPlacementInfo.Habitat[y].fValid; + } + } + } + else if(strcmp(name, "Index") == 0 && pData->curElement == CREATURE_ELEMENT_INDEX) + { + pData->curElement = CREATURE_ELEMENT_PLACEMENT; + + pData->curIndex = atol(pData->szCharData); + if ( !pData->curIndex || pData->curIndex > MAX_NUMBER_OF_INFECTIBLE_SITES + 1 ) + { + pData->curIndex = INVALID_CREATURESITE_INDEX; + } + else if ( pData->curIndex > pData->uiHighestIndex ) + { + pData->uiHighestIndex = pData->curIndex; + } + } + else if(strcmp(name, "ATTACKSOURCE") == 0 && pData->curElement == CREATURE_ELEMENT_ATTACKSOURCE) + { + pData->curElement = CREATURE_ELEMENT_PLACEMENT; + } + else if(strcmp(name, "SectorGrid") == 0 && pData->curElement == CREATURE_ELEMENT_ATTACKSOURCE_SECTOR) + { + UINT8 x, y; + pData->curElement = CREATURE_ELEMENT_ATTACKSOURCE; + + y = (UINT8)pData->szCharData[0] & 0x1F; + x = (UINT8)atol(&pData->szCharData[1]); + if ( x > 0 && x <= 16 && y > 0 && y <= 16 ) + { + pData->curPlacementInfo.sAttackSourceX = x; + pData->curPlacementInfo.sAttackSourceY = y; + } + SGP_THROW_IFFALSE( (SECTOR(x,y) >= 0 && SECTOR(x,y) < 256) , L"Illegal sector number in CreaturePlacements.XML" ); + } + else if(strcmp(name, "GridNo") == 0 && pData->curElement == CREATURE_ELEMENT_ATTACKSOURCE_GRIDNO) + { + pData->curElement = CREATURE_ELEMENT_ATTACKSOURCE; + + pData->curPlacementInfo.iAttackSourceGridNo = (INT32) atol(pData->szCharData); + } + else if(strcmp(name, "ALTERNATEMAP") == 0 && pData->curElement == CREATURE_ELEMENT_ALTERNATEMAP) + { + pData->curElement = CREATURE_ELEMENT_PLACEMENT; + } + else if(strcmp(name, "SectorGrid") == 0 && pData->curElement == CREATURE_ELEMENT_ALTERNATEMAP_SECTOR) + { + UINT8 x, y; + pData->curElement = CREATURE_ELEMENT_ALTERNATEMAP; + + y = (UINT8)pData->szCharData[0] & 0x1F; + x = (UINT8)atol(&pData->szCharData[1]); + if ( x > 0 && x <= 16 && y > 0 && y <= 16 ) + { + pData->curPlacementInfo.sAltMapX = x; + pData->curPlacementInfo.sAltMapY = y; + } + SGP_THROW_IFFALSE( (SECTOR(x,y) >= 0 && SECTOR(x,y) < 256) , L"Illegal sector number in CreaturePlacements.XML" ); + } + else if(strcmp(name, "SectorZ") == 0 && pData->curElement == CREATURE_ELEMENT_ALTERNATEMAP_Z) + { + pData->curElement = CREATURE_ELEMENT_ALTERNATEMAP; + + pData->curPlacementInfo.ubAltMapZ = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "WARPTOSECTOR") == 0 && pData->curElement == CREATURE_ELEMENT_WARPTO) + { + pData->curElement = CREATURE_ELEMENT_PLACEMENT; + } + else if(strcmp(name, "SectorGrid") == 0 && pData->curElement == CREATURE_ELEMENT_WARPTO_SECTOR) + { + UINT8 x, y; + pData->curElement = CREATURE_ELEMENT_WARPTO; + + y = (UINT8)pData->szCharData[0] & 0x1F; + x = (UINT8)atol(&pData->szCharData[1]); + if ( x > 0 && x <= 16 && y > 0 && y <= 16 ) + { + pData->curPlacementInfo.sWarpToX = x; + pData->curPlacementInfo.sWarpToY = y; + } + SGP_THROW_IFFALSE( (SECTOR(x,y) >= 0 && SECTOR(x,y) < 256) , L"Illegal sector number in CreaturePlacements.XML" ); + } + else if(strcmp(name, "SectorZ") == 0 && pData->curElement == CREATURE_ELEMENT_WARPTO_Z) + { + pData->curElement = CREATURE_ELEMENT_WARPTO; + + pData->curPlacementInfo.ubWarpToZ = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "GridNo") == 0 && pData->curElement == CREATURE_ELEMENT_WARPTO_GRIDNO) + { + pData->curElement = CREATURE_ELEMENT_WARPTO; + + pData->curPlacementInfo.iWarpToGridNo = (INT32) atol(pData->szCharData); + } + else if(strcmp(name, "CREATURESECTOR") == 0 && pData->curElement == CREATURE_ELEMENT_CREATURESECTOR) + { + pData->curElement = CREATURE_ELEMENT_PLACEMENT; + } + else if(strcmp(name, "QUEENSECTOR") == 0 && pData->curElement == CREATURE_ELEMENT_QUEEN) + { + pData->curElement = CREATURE_ELEMENT_CREATURESECTOR; + } + else if(strcmp(name, "SectorGrid") == 0 && pData->curElement == CREATURE_ELEMENT_QUEEN_SECTOR) + { + UINT8 x, y; + pData->curElement = CREATURE_ELEMENT_QUEEN; + + y = (UINT8)pData->szCharData[0] & 0x1F; + x = (UINT8)atol(&pData->szCharData[1]); + if ( x > 0 && x <= 16 && y > 0 && y <= 16 ) + { + pData->curPlacementInfo.sQueenX = x; + pData->curPlacementInfo.sQueenY = y; + } + SGP_THROW_IFFALSE( (SECTOR(x,y) >= 0 && SECTOR(x,y) < 256) , L"Illegal sector number in CreaturePlacements.XML" ); + } + else if(strcmp(name, "SectorZ") == 0 && pData->curElement == CREATURE_ELEMENT_QUEEN_Z) + { + pData->curElement = CREATURE_ELEMENT_QUEEN; + + pData->curPlacementInfo.ubQueenZ = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "HABITATSECTOR") == 0 && pData->curElement == CREATURE_ELEMENT_HABITAT) + { + pData->curElement = CREATURE_ELEMENT_CREATURESECTOR; + } + else if(strcmp(name, "SectorGrid") == 0 && pData->curElement == CREATURE_ELEMENT_HABITAT_SECTOR) + { + UINT8 x, y; + pData->curElement = CREATURE_ELEMENT_HABITAT; + + y = (UINT8)pData->szCharData[0] & 0x1F; + x = (UINT8)atol(&pData->szCharData[1]); + if ( x > 0 && x <= 16 && y > 0 && y <= 16 ) + { + pData->curPlacementInfo.Habitat[pData->curHabitat].sX = x; + pData->curPlacementInfo.Habitat[pData->curHabitat].sY = y; + } + SGP_THROW_IFFALSE( (SECTOR(x,y) >= 0 && SECTOR(x,y) < 256) , L"Illegal sector number in CreaturePlacements.XML" ); + } + else if(strcmp(name, "SectorZ") == 0 && pData->curElement == CREATURE_ELEMENT_HABITAT_Z) + { + pData->curElement = CREATURE_ELEMENT_HABITAT; + + pData->curPlacementInfo.Habitat[pData->curHabitat].ubZ = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "Composition") == 0 && pData->curElement == CREATURE_ELEMENT_HABITAT_COMPOSITION) + { + pData->curElement = CREATURE_ELEMENT_HABITAT; + + pData->curPlacementInfo.Habitat[pData->curHabitat].ubComposition = (UINT8) atol(pData->szCharData); + + // valid creature habitat if using other than queen habitat + if ( pData->curPlacementInfo.Habitat[pData->curHabitat].ubComposition ) + pData->curPlacementInfo.Habitat[pData->curHabitat].fValid = TRUE; + + pData->curHabitat++; + } + + pData->maxReadDepth--; + } + + pData->currentDepth--; +} + +BOOLEAN ReadInCreaturePlacements(STR fileName) +{ + HWFILE hFile; + UINT32 uiBytesRead; + UINT32 uiFSize; + CHAR8 * lpcBuffer; + XML_Parser parser = XML_ParserCreate(NULL); + + CreatureParseData pData; + + hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE ); + if ( !hFile ) + return( FALSE ); + + uiFSize = FileGetSize(hFile); + lpcBuffer = (CHAR8 *) MemAlloc(uiFSize+1); + + //Read in block + if ( !FileRead( hFile, lpcBuffer, uiFSize, &uiBytesRead ) ) + { + MemFree(lpcBuffer); + return( FALSE ); + } + + lpcBuffer[uiFSize] = 0; //add a null terminator + + FileClose( hFile ); + + + XML_SetElementHandler(parser, creatureplacementStartElementHandle, creatureplacementEndElementHandle); + XML_SetCharacterDataHandler(parser, creatureplacementCharacterDataHandle); + + + memset(&pData,0,sizeof(pData)); + NUMBER_OF_INFECTIBLE_SITES = 0; + NUMBER_OF_CREATURE_COMPOSITIONS = 0; + XML_SetUserData(parser, &pData); + + if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE)) + { + CHAR8 errorBuf[511]; + sprintf(errorBuf, "XML Parser Error in CreaturePlacements.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser)); + LiveMessage(errorBuf); + + MemFree(lpcBuffer); + return FALSE; + } + + MemFree(lpcBuffer); + + XML_ParserFree(parser); + + return TRUE; +} \ No newline at end of file diff --git a/Tactical/XML.h b/Tactical/XML.h index cdbf7aaf..b8e30b43 100644 --- a/Tactical/XML.h +++ b/Tactical/XML.h @@ -172,6 +172,7 @@ typedef PARSE_STAGE; #define SECTORNAMESFILENAME "Map\\SectorNames.xml" #define COOLNESSBYSECTORFILENAME "Map\\CoolnessBySector.xml" #define BLOODCATPLACEMENTSFILENAME "Map\\BloodcatPlacements.xml" +#define CREATUREPLACEMENTSFILENAME "Map\\CreaturePlacements.xml" #define SECTORLEVEL1NAMESFILENAME "Map\\SectorNamesLevel_1.xml" #define SECTORLEVEL2NAMESFILENAME "Map\\SectorNamesLevel_2.xml" #define SECTORLEVEL3NAMESFILENAME "Map\\SectorNamesLevel_3.xml" @@ -453,6 +454,9 @@ extern BOOLEAN ReadInMercOpinions(STR fileName); // HEADROCK HAM 3.6: Customized Bloodcat Placements extern BOOLEAN ReadInBloodcatPlacements(STR fileName); +// Buggler: Customized Creature Placements +extern BOOLEAN ReadInCreaturePlacements(STR fileName); + // HEADROCK HAM 3.6: Customized Uniform Colors extern BOOLEAN ReadInUniforms(STR fileName);