#include #include #include #include #include "data.h" #define MAX_UNITS 100 #define MAX_BUILDINGS 50 typedef struct Node { int x, y; int gCost; // Cost from start node int hCost; // Heuristic cost to target node struct Node* parent; } Node; // Function to calculate the distance between two points using Manhattan distance int calculateDistance(int x1, int y1, int x2, int y2) { return abs(x1 - x2) + abs(y1 - y2); } bool isUnitOrBuildingAtPosition(GameData* data, int x, int y) { for (int i = 0; i < MAX_UNITS; i++) { if (data->units[i].unitID != -1 && data->units[i].x == x && data->units[i].y == y) { // Found a unit at the position return true; } } for (int i = 0; i < MAX_BUILDINGS; i++) { if (data->buildings[i].buildingID != -1 && data->buildings[i].x == x && data->buildings[i].y == y) { // Found a building at the position return true; } } // No unit or building found at the position return false; } // A* algorithm implementation void aStarPathfinding(GameData* map, int startX, int startY, int targetX, int targetY) { // Create start and target nodes Node startNode = {startX, startY, 0, 0, NULL}; Node targetNode = {targetX, targetY, 0, 0, NULL}; // Create open and closed lists Node* openList = malloc(sizeof(Node) * MAP_SIZE * MAP_SIZE); Node* closedList = malloc(sizeof(Node) * MAP_SIZE * MAP_SIZE); int openListCount = 0; int closedListCount = 0; // Add start node to open list openList[openListCount++] = startNode; while (openListCount > 0) { // Find the node with the lowest fCost in the open list int currentIndex = 0; for (int i = 0; i < openListCount; i++) { if (openList[i].gCost + openList[i].hCost < openList[currentIndex].gCost + openList[currentIndex].hCost) { currentIndex = i; } } // Move current node to the closed list Node currentNode = openList[currentIndex]; openList[currentIndex] = openList[--openListCount]; closedList[closedListCount++] = currentNode; // Check if we have reached the target node if (currentNode.x == targetNode.x && currentNode.y == targetNode.y) { // Path found, reconstruct and print the path while (currentNode.parent != NULL) { printf("(%d, %d) -> ", currentNode.x, currentNode.y); currentNode = *currentNode.parent; } printf("(%d, %d)\n", startX, startY); break; } // Generate neighboring nodes for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (i == 0 && j == 0) continue; int neighborX = currentNode.x + i; int neighborY = currentNode.y + j; // Ignore invalid neighbors or obstacles if (neighborX < 0 || neighborX >= MAP_SIZE || neighborY < 0 || neighborY >= MAP_SIZE || map->currentMap.tileData[neighborX][neighborY] == 1 || isUnitOrBuildingAtPosition(map, neighborX, neighborY)) { continue; } // Calculate neighbor costs int gCost = currentNode.gCost + 1; // Assuming uniform movement cost int hCost = calculateDistance(neighborX, neighborY, targetNode.x, targetNode.y); // Check if neighbor is in the closed list bool inClosedList = false; for (int k = 0; k < closedListCount; k++) { if (closedList[k].x == neighborX && closedList[k].y == neighborY) { inClosedList = true; break; } } if (!inClosedList) { // Check if neighbor is in the open list bool inOpenList = false; for (int k = 0; k < openListCount; k++) { if (openList[k].x == neighborX && openList[k].y == neighborY) { inOpenList = true; if (gCost < openList[k].gCost) { openList[k].gCost = gCost; openList[k].parent = ¤tNode; } break; } } if (!inOpenList) { // Add neighbor to open list openList[openListCount++] = (Node){neighborX, neighborY, gCost, hCost, ¤tNode}; } } } } } free(openList); free(closedList); } // goap typedef struct { int targetX, targetY; // The target position for the unit } MoveGoal; typedef struct { int unitID; // The ID of the unit to move int targetX, targetY; // The target position } MoveAction; bool canMove(GameData* gameData, MoveAction* action) { // Find the unit in the game data for (int i = 0; i < MAX_UNITS; i++) { if (gameData->units[i].unitID == action->unitID) { // Check if the unit is within range of the target int distance = abs(gameData->units[i].x - action->targetX) + abs(gameData->units[i].y - action->targetY); return distance <= 5; // Assuming a unit can move up to 5 tiles in one action } } return false; // Unit not found } MoveAction* planMove(GameData* gameData, MoveGoal* goal) { // For simplicity, we'll just select the first unit that can move to the goal for (int i = 0; i < MAX_UNITS; i++) { MoveAction action = {gameData->units[i].unitID, goal->targetX, goal->targetY}; if (canMove(gameData, &action)) { return &action; // Return the action } } return NULL; // No action found } void updateGame(GameData* gameData) { // Update game state... // Example: Plan a move for a unit MoveGoal goal = {10, 20}; // Move to position (10, 20) MoveAction* action = planMove(gameData, &goal); if (action != NULL) { // Execute the action... } } void moveUnit(Unit* unit, int targetX, int targetY) { // Move the unit to the target position unit->x = targetX; unit->y = targetY; printf("Unit %d moved to (%d, %d).\n", unit->unitID, unit->x, unit->y); } // Sample GOAP planning logic for moving a unit to a target position void planActions(GameData* gameData) { // Assuming we want to move Unit 0 to position (10, 10) int targetX = 10; int targetY = 10; // Find the Unit with unitID 0 Unit* unitToMove = NULL; for (int i = 0; i < MAX_UNITS; i++) { if (gameData->units[i].unitID == 0) { unitToMove = &gameData->units[i]; break; } } if (unitToMove != NULL) { // Implement planning logic here to move the unit to the target position printf("Planning to move Unit %d to (%d, %d)...\n", unitToMove->unitID, targetX, targetY); // Execute the action to move the unit moveUnit(unitToMove, targetX, targetY); } else { printf("Unit with ID 0 not found.\n"); } } // behavior tree typedef enum { NODE_SELECTOR, NODE_SEQUENCE, NODE_ACTION, NODE_CONDITION } NodeType; typedef struct Node { NodeType type; int (*execute)(struct Node*); } Node; int executeAction(Node* node) { // Placeholder for action execution return 1; // Assume action is successful } int executeCondition(Node* node) { // Placeholder for condition checking return 1; // Assume condition is true } int executeSelector(Node* node) { // Selector node executes its children until one succeeds for (int i = 0; i < node->numChildren; i++) { if (node->children[i]->execute(node->children[i])) { return 1; } } return 0; } int executeSequence(Node* node) { // Sequence node executes its children in order until one fails for (int i = 0; i < node->numChildren; i++) { if (!node->children[i]->execute(node->children[i])) { return 0; } } return 1; } Node* createMoveToTargetBehavior() { Node* moveToTarget = malloc(sizeof(Node)); moveToTarget->type = NODE_ACTION; moveToTarget->execute = executeAction; // Additional setup for the move action... return moveToTarget; } Node* createAttackEnemyBehavior() { Node* attackEnemy = malloc(sizeof(Node)); attackEnemy->type = NODE_ACTION; attackEnemy->execute = executeAction; // Additional setup for the attack action... return attackEnemy; } Node* createPatrolAreaBehavior() { Node* patrolArea = malloc(sizeof(Node)); patrolArea->type = NODE_ACTION; patrolArea->execute = executeAction; // Additional setup for the patrol action... return patrolArea; } Node* createBehaviorTree() { Node* root = malloc(sizeof(Node)); root->type = NODE_SELECTOR; root->execute = executeSelector; root->numChildren = 3; root->children = malloc(sizeof(Node*) * 3); root->children[0] = createMoveToTargetBehavior(); root->children[1] = createAttackEnemyBehavior(); root->children[2] = createPatrolAreaBehavior(); return root; } void updateUnitBehavior(Node* behaviorTree) { behaviorTree->execute(behaviorTree); } // Define the possible return status of a behavior node typedef enum { SUCCESS, FAILURE, RUNNING } Status; // Define a function pointer type for the behavior node typedef Status (*NodeFunction)(); // Behavior Tree nodes (functions) Status sequence(); Status selector(); Status action1(); Status action2(); // Sample action nodes Status action1() { printf("Executing Action 1\n"); return SUCCESS; } Status action2() { printf("Executing Action 2\n"); return SUCCESS; } // Function to save behavior tree to a file void saveBehaviorTreeToFile(const char* filename, NodeFunction root) { FILE* file = fopen(filename, "wb"); if (file == NULL) { printf("Error opening file for writing\n"); return; } // Write the address of the root function to the file fwrite(&root, sizeof(NodeFunction), 1, file); fclose(file); } // Function to load behavior tree from a file NodeFunction loadBehaviorTreeFromFile(const char* filename) { FILE* file = fopen(filename, "rb"); if (file == NULL) { printf("Error opening file for reading\n"); return NULL; } NodeFunction root; fread(&root, sizeof(NodeFunction), 1, file); fclose(file); return root; }