/* This file is part of Warzone 2100. Copyright (C) 1999-2004 Eidos Interactive Copyright (C) 2005-2007 Warzone Resurrection Project Warzone 2100 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Warzone 2100 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Warzone 2100; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* * Player.c * * Update code for computer player AI * */ #include "lib/framework/frame.h" #include "objects.h" #include "map.h" #include "player.h" #include "game.h" #include "order.h" #include "objectdef.h" #include "multiplay.h" /* The position for the computer players to attack */ #define ATTACKX 39 #define ATTACKY 42 //defined in StructureDef.h - AB 6/1/98 /* Quick hack to choose an assembly point for player droids */ /*struct _pos { UDWORD x,y; } aAssemblyPos[MAX_PLAYERS] = { { 39,39 }, { 34,23 }, { 26,37 }, { 34,23 }, { 34,23 }, { 34,23 }, { 26,37 }, { 34,23 }, };*/ struct _position2 { UDWORD x,y; }; /* location of computer player bases */ struct _position2 aBasePos[MAX_PLAYERS] = { { 0,0 }, { 0,0 }, { 0,0 }, { 0,0 }, { 0,0 }, { 0,0 }, { 20,40 }, { 34,19 }, }; /* distance from base to check for enemy droids */ #define DROID_SCAN 7 /* Quick hack to choose droid templates to build */ //#define MAX_DROIDTYPES 3 /*struct _man_info { UDWORD templIndex; // which template to build UDWORD points; // number of points towards group total } aManInfo[MAX_PLAYERS][MAX_DROIDTYPES] = { { // player 0 { 1, 1 }, { 3, 2 }, { 2, 3 }, }, { // player 1 { 1, 1 }, { 3, 2 }, { 2, 3 }, }, { // player 2 { 1, 1 }, { 3, 2 }, { 2, 3 }, }, { // player 3 { 1, 1 }, { 3, 2 }, { 2, 3 }, }, { // player 4 { 1, 1 }, { 3, 2 }, { 2, 3 }, }, { // player 5 { 1, 1 }, { 3, 2 }, { 2, 3 }, }, { // player 6 { 1, 1 }, { 4, 3 }, { 2, 4 }, }, { // player 7 { 1, 1 }, { 4, 3 }, { 2, 4 }, }, }; UDWORD numManInfo[MAX_PLAYERS] = // Number of the above structs valid for each player { 3, 3, 3, 3, 3, 3, 3, 3, // first 3 was a 0, changed for multiplayer (ajl) };*/ UDWORD attackPoints[MAX_PLAYERS] = // Number of points for the attack group { 7, 7, 7, 7, 7, 7, 9, 9, // first 7 was a 0, changed for multiplayer (ajl) }; typedef struct _player_ai { DROID *psAttackGrp; // The group of droids that have been built to attack the player UDWORD groupPoints; BOOL building; // Whether the player is building an attack group } PLAYER_AI; PLAYER_AI *asPlayerAI; /* Initialise the player AI system */ BOOL playerInitialise(void) { asPlayerAI = (PLAYER_AI *)MALLOC(sizeof(PLAYER_AI) * MAX_PLAYERS); if (!asPlayerAI) { debug( LOG_ERROR, "Out of memory" ); abort(); return FALSE; } memset(asPlayerAI, 0, sizeof(PLAYER_AI) * MAX_PLAYERS); return TRUE; } /* Reset the player AI after a load game */ void playerReset(void) { memset(asPlayerAI, 0, sizeof(PLAYER_AI) * MAX_PLAYERS); } /* Shutdown the player AI system */ void playerShutDown(void) { FREE(asPlayerAI); } /* Check a group list for dead droids */ /*static void playerCheckGroup(DROID **ppsDroid) { DROID *psPrev = NULL, *psCurr;; while (*ppsDroid && (*ppsDroid)->died) { *ppsDroid = (*ppsDroid)->sAI.psGroup; } for(psCurr = *ppsDroid; psCurr; psCurr = psCurr->sAI.psGroup) { if (psCurr->died) { psPrev->sAI.psGroup = psCurr->sAI.psGroup; } else { psPrev = psCurr; } } }*/ /* Update the AI for a player */ void playerUpdate(UDWORD player) { // DROID *psCurr; // STRUCTURE *psStruct; if ((!bMultiPlayer) && (player ==0)) // this'll have to come out to allow p1 AI { // currently stops the whole thing crashing. return; } else if( bMultiPlayer && (isHumanPlayer(player))) { return; } // See if the human player has been seen by this player /* if (!asPlayerAI[player].building) { for(psCurr = apsDroidLists[0]; psCurr; psCurr = psCurr->psNext) { if (psCurr->visible[player]) { // Seen one - start manufacturing droids to attack with playerStartManufacture(player); asPlayerAI[player].building = TRUE; break; } } } else { // Check the factory is still producing for(psStruct = apsStructLists[player]; psStruct; psStruct = psStruct->psNext) { if (psStruct->pStructureType->type == REF_FACTORY) { break; } } if (psStruct && ((FACTORY *)psStruct->pFunctionality)->psSubject == NULL) { // Factory isn't building - restart it playerStartManufacture(player); } } */ // Check none of the droids in the attack group have died // playerCheckGroup(&asPlayerAI[player].psAttackGrp); } /* deal with a new droid being built by a factory */ void playerNewDroid(DROID *psDroid) { // UDWORD player; // UDWORD newManu, templIndex; // SDWORD xdiff, ydiff, radSquared; // DROID_TEMPLATE *psTempl; // STRUCTURE *psStruct; // DROID *psCurr; // BOOL foundDroid; // char droidName[MAX_NAME_SIZE]; /* if (!psDroid) { return; } // Check it isn't the human player player = psDroid->player; #ifndef PSX if( (!bMultiPlayer) && (player == 0)) { return; } else if((bMultiPlayer) && (IsHumanPlayer(player)) ) { return; } #else if (player == 0) { return; } #endif // Add it to the attack group psDroid->sAI.psGroup = asPlayerAI[player].psAttackGrp; asPlayerAI[player].psAttackGrp = psDroid; */ //This now happens in buildDroid - AB 6/1/98 //move droid to assembly point //orderDroidLoc(psDroid, DORDER_MOVE, aAssemblyPos[player].x << TILE_SHIFT, // aAssemblyPos[player].y << TILE_SHIFT); //SCRIPTED NOW /* Move the droid to the assembly point if (asPlayerAI[player].groupPoints < attackPoints[player]) { orderDroidLoc(psDroid, DORDER_MOVE, aAssemblyPos[player].x << TILE_SHIFT, aAssemblyPos[player].y << TILE_SHIFT); } else { // send the droids to attack - first see if there are any droids close to the base foundDroid = FALSE; radSquared = DROID_SCAN*DROID_SCAN; for(psCurr = apsDroidLists[0]; psCurr; psCurr = psCurr->psNext) { xdiff = (psCurr->x >> TILE_SHIFT) - aBasePos[player].x; ydiff = (psCurr->y >> TILE_SHIFT) - aBasePos[player].y; if (xdiff*xdiff + ydiff*ydiff < radSquared) { foundDroid = TRUE; orderGroupObj(psDroid, DORDER_ATTACK, (BASE_OBJECT *)psCurr); } } if (!foundDroid) { orderGroupLoc(psDroid, DORDER_MOVE, ATTACKX << TILE_SHIFT, ATTACKY << TILE_SHIFT); // asPlayerAI[player].psAttackGrp = NULL; asPlayerAI[player].groupPoints = 0; } } */ //THIS IS SCRIPTED NOW... /* Find the factory */ /* for(psStruct = apsStructLists[player]; psStruct; psStruct = psStruct->psNext) { if (psStruct->pStructureType->type == REF_FACTORY) { break; } } // Choose a new droid to build newManu = rand() % numManInfo[player]; templIndex = aManInfo[player][newManu].templIndex; // psTempl = apsDroidTemplates[player]; // for(i=0; i != templIndex && psTempl; i++, psTempl = psTempl->psNext) // ; switch (templIndex) { case 1: strcpy(droidName,"BaBa People"); break; case 2: strcpy(droidName, "Barbarian Buggy"); break; case 4: strcpy(droidName, "Barbarian Trike"); } for (psTempl = apsDroidTemplates[player]; psTempl; psTempl = psTempl->psNext) { if (!strcmp(psTempl->pName, droidName)) { break; } } if (psTempl) { // Start the production of the droid structSetManufacture(psStruct, psTempl, 1); asPlayerAI[player].groupPoints += aManInfo[player][newManu].points; }*/ } /* Get a player to start manufacturing droids */ /*void playerStartManufacture(UDWORD player) { UDWORD newManu, templIndex; STRUCTURE *psStruct; DROID_TEMPLATE *psTempl; char droidName[MAX_NAME_SIZE]; // Find the factory for(psStruct = apsStructLists[player]; psStruct; psStruct = psStruct->psNext) { if (psStruct->pStructureType->type == REF_FACTORY) { break; } } // Choose a new droid to build if (psStruct) { newManu = rand() % numManInfo[player]; templIndex = aManInfo[player][newManu].templIndex; // psTempl = apsDroidTemplates[player]; // for(i=0; i != templIndex && psTempl; i++, psTempl = psTempl->psNext) // ; switch (templIndex) { case 1: strcpy(droidName,"BaBa People"); break; case 2: strcpy(droidName, "Barbarian Buggy"); break; case 4: strcpy(droidName, "Barbarian Trike"); } for (psTempl = apsDroidTemplates[player]; psTempl; psTempl = psTempl->psNext) { if (!strcmp(psTempl->pName, droidName)) { break; } } if (psTempl) { // Start the production of the droid structSetManufacture(psStruct, psTempl, 1); asPlayerAI[player].groupPoints += aManInfo[player][newManu].points; } } } */ //New version in Structure.c - AB 6/1/98 /*sets the point new droids go to - x/y in world coords*/ /*void setAssemblyPoint(UDWORD x, UDWORD y, UDWORD player) { aAssemblyPos[player].x = x >> TILE_SHIFT; aAssemblyPos[player].y = y >> TILE_SHIFT; }*/ /* sends players droids to attack a specified x/y. Checks to see if any enemy droids are near to the home base first*/ void attackLocation(UDWORD x, UDWORD y, UDWORD player) { /* BOOL foundDroid; DROID *psDroid, *psCurr; SDWORD xdiff, ydiff, radSquared; #ifndef PSX if( (!bMultiPlayer) && (player == 0)) { return; } else if((bMultiPlayer) && (IsHumanPlayer(player)) ) { return; } #else if (player == 0) { return; } #endif // send the droids to attack psDroid = asPlayerAI[player].psAttackGrp; foundDroid = FALSE; radSquared = DROID_SCAN*DROID_SCAN; //first see if there are any droids close to the base for(psCurr = apsDroidLists[0]; psCurr; psCurr = psCurr->psNext) { xdiff = (psCurr->x >> TILE_SHIFT) - aBasePos[player].x; ydiff = (psCurr->y >> TILE_SHIFT) - aBasePos[player].y; if (xdiff*xdiff + ydiff*ydiff < radSquared) { foundDroid = TRUE; orderGroupObj(psDroid, DORDER_ATTACK, (BASE_OBJECT *)psCurr); } } //send them to location if none near if (!foundDroid) { orderGroupLoc(psDroid, DORDER_MOVE, x, y); // asPlayerAI[player].groupPoints = 0; }*/ }