#include "world.h" #include "game.h" #include "entity.h" #include "entitiesInclude.h" void initWorld(World * world) { world->entities = NULL; world->entitiesCount = 0; world->lookUp = NULL; world->lookUpSize = 0; world->vacantIds = NULL; world->vacantIdsCount = 0; world->entitiesToAdd = NULL; world->entitiesToAddCount = 0; // Set current fingerprint. SetRandomSeed(time(NULL)); world->currentFingerprint = GetRandomValue( FINGERPRINT_START_RANGE_MIN, FINGERPRINT_START_RANGE_MAX ); } void freeWorld(World * world) { int i; if (world->entities == NULL) return; // Close entities. for (i = 0; i < world->entitiesCount; ++i) closeEntity(&world->entities[i]); KF_FREE(world->entities); KF_FREE(world->lookUp); if (world->vacantIds != NULL) KF_FREE(world->vacantIds); } // Not for direct use. KfError pushVacantId(World * world, EntityId id) { ++world->vacantIdsCount; // Allocate. if (world->vacantIds == NULL) world->vacantIds = (EntityId*)KF_CALLOC(1, sizeof(EntityId)); else world->vacantIds = (EntityId*)KF_REALLOCARRAY( world->vacantIds, world->vacantIdsCount, sizeof(EntityId) ); if (world->vacantIds == NULL) { ALLOCATION_ERROR; return KFERROR; } world->vacantIds[world->vacantIdsCount - 1] = id; return KFSUCCESS; } // Not for direct use. EntityId popVacantId(World * world) { EntityId id; // Already empty. if (world->vacantIds == NULL) return ENTITY_NONE; id = world->vacantIds[world->vacantIdsCount - 1]; // Decrease count. --world->vacantIdsCount; // Free or recallocate. if (world->vacantIdsCount == 0) { KF_FREE(world->vacantIds); world->vacantIds = NULL; } else { world->vacantIds = (EntityId*)KF_REALLOCARRAY( world->vacantIds, world->vacantIdsCount, sizeof(EntityId) ); } return id; } Entity * getEntityFromWorld(World world, EntityId id) { if (world.entities == NULL || id < 0 || id >= world.lookUpSize) return NULL; int pos = world.lookUp[id]; if (pos == ENTITY_ID_NONE) return NULL; return &world.entities[pos]; } EntityId addEntityToWorld(World * world, Entity entity) { EntityId id; EntityId poppedId; Entity entityCopy = entity; // Set fingerprint. entityCopy.fingerprint = world->currentFingerprint; ++world->currentFingerprint; // Not allocated. if (world->entities == NULL) { // Allocate. world->entities = (Entity*)KF_CALLOC(1, sizeof(Entity)); world->lookUp = (EntityId*)KF_CALLOC(1, sizeof(EntityId)); world->entitiesCount = 1; world->lookUpSize = 1; if (world->entities == NULL || world->lookUp == NULL) { ALLOCATION_ERROR; return ENTITY_NONE; } // Set entity and id. world->entities[0] = entityCopy; world->entities[0].id = 0; world->lookUp[0] = 0; return 0; } ++world->entitiesCount; // Resize. world->entities = (Entity*)KF_REALLOCARRAY( world->entities, world->entitiesCount, sizeof(Entity) ); if (world->entities == NULL) { ALLOCATION_ERROR; return ENTITY_NONE; } // Set entity. world->entities[world->entitiesCount - 1] = entityCopy; // Set look up. poppedId = popVacantId(world); // Got popped id. if (poppedId != ENTITY_ID_NONE) { world->lookUp[poppedId] = world->entitiesCount - 1; world->entities[world->entitiesCount - 1].id = poppedId; return poppedId; } ++world->lookUpSize; world->lookUp = (EntityId*)KF_REALLOCARRAY( world->lookUp, world->lookUpSize, sizeof(EntityId) ); if (world->lookUp == NULL) { ALLOCATION_ERROR; return ENTITY_NONE; } // Set id. id = world->lookUpSize - 1; world->entities[world->entitiesCount - 1].id = id; world->lookUp[id] = world->entitiesCount - 1; return id; } KfError removeEntityFromWorld(World * world, EntityId id) { int i; int pos; if (world->entitiesCount == 1) return KFERROR; // Get position in list. pos = world->lookUp[id]; if (pos == ENTITY_ID_NONE) return KFSUCCESS; // Close entity. closeEntity(&world->entities[pos]); // Push id. if (pushVacantId(world, id) != KFSUCCESS) return KFERROR; for (i = pos; i < world->entitiesCount - 1; ++i) { // Move back entities world->entities[i] = world->entities[i + 1]; // Update lookUp. world->lookUp[world->entities[i].id] = i; } world->lookUp[id] = ENTITY_ID_NONE; // Resize entities. --world->entitiesCount; world->entities = (Entity*)KF_REALLOCARRAY( world->entities, world->entitiesCount, sizeof(Entity) ); if (world->entities == NULL) { ALLOCATION_ERROR; return KFERROR; } return KFSUCCESS; } KfError scheduleEntityToAdd(World * world, Entity entity) { ++world->entitiesToAddCount; // Allocate shit. if (world->entitiesToAdd == NULL) world->entitiesToAdd = (Entity*)KF_CALLOC(world->entitiesToAddCount, sizeof(Entity)); else world->entitiesToAdd = (Entity*)KF_REALLOCARRAY( world->entitiesToAdd, world->entitiesToAddCount, sizeof(Entity) ); if (world->entitiesToAdd == NULL) { ALLOCATION_ERROR; return KFERROR; } world->entitiesToAdd[world->entitiesToAddCount - 1] = entity; return KFSUCCESS; } KfError handleScheduledEntities(World * world) { int i; // No entities to add. if (world->entitiesToAdd == NULL) return KFSUCCESS; for (i = 0; i < world->entitiesToAddCount; ++i) { // Add entity indeed. if (addEntityToWorld(world, world->entitiesToAdd[i]) == ENTITY_NONE) return KFERROR; } // Clean up this shit. KF_FREE(world->entitiesToAdd); world->entitiesToAdd = NULL; world->entitiesToAddCount = 0; return KFSUCCESS; } void handleCollisionInWorld(Entity * entity1, Entity * entity2) { //if (entity1->id != 0) // entity1->health = 0.0; //if (entity2->id != 0) // entity2->health = 0.0; if (entity1->type != ENTITY_ANTIFA && entity2->type != ENTITY_ANTIFA) setSoldatoLeader(entity1, entity2); switch (entity1->type) { case ENTITY_ANTIFA: break; case ENTITY_SOLDATO: break; case ENTITY_CAPORALE: break; case ENTITY_SERGENTE: break; case ENTITY_MARESCIALLO: break; case ENTITY_GENERALE: break; case ENTITY_MUSSOLINI: break; case ENTITY_GUIDED_MISSILE: break; default: break; } } void updateWorld(World * world, Game * game) { int i, j; Entity * entity; Entity * entity2; // People are fucking dying. EntityId kills[world->entitiesCount]; size_t killCount = 0; for (i = 0; i < world->entitiesCount; ++i) { entity = &world->entities[i]; // Call update callback. if (entity->updateCb != NULL) entity->updateCb(game, entity); // Check for collision. for (j = 0; j < i; ++j) { entity2 = &world->entities[j]; // Collided. // Only use real collision if player is there. if (entity->id == ENTITY_ANTIFA || entity2->id == ENTITY_ANTIFA) { if (checkEntityCollision(entity, entity2)) handleCollisionInWorld(entity, entity2); } else { if (Vector3Distance(entity->position, entity2->position) <= entity->radius + entity2->radius) handleCollisionInWorld(entity, entity2); } } // It fucking died. if (entity->health <= 0.0 && entity->type != ENTITY_ANTIFA) { kills[killCount] = entity->id; ++killCount; } } // "bring out your dead!" for (i = 0; i < killCount; ++i) removeEntityFromWorld(world, kills[i]); // Handle some shit. handleScheduledEntities(world); } void drawWorld(World * world, Game * game) { int i; Entity * entity; for (i = 0; i < world->entitiesCount; ++i) { entity = &world->entities[i]; // Call draw callback. if (entity->drawCb != NULL) entity->drawCb(game, entity); } } EntityId traceRayToEntityInWorld(World * world, Ray ray, EntityFingerprint from, bool useFrom) { int i, j; RayCollision collision; Entity * currentEntity; Ray transformedRay; // Set direction. transformedRay.direction = ray.direction; // Used for finding closest. float closest = -1.0; // -1.0 means ray haven't hit anything. EntityId closestId = ENTITY_NONE; // Loop through entities. for (i = 0; i < world->entitiesCount; ++i) { currentEntity = &world->entities[i]; if (currentEntity->fingerprint == from && useFrom) continue; else if (currentEntity->model == NULL) // Null model indeed. continue; // Set position relative to entity. transformedRay.position = Vector3Subtract(ray.position, currentEntity->position); // Loop through meshes. for (j = 0; j < currentEntity->model->meshCount; ++j) { collision = GetRayCollisionMesh( transformedRay, currentEntity->model->meshes[j], currentEntity->model->transform ); // Did hit. if (collision.hit) { // Find closest. if (collision.distance < closest || closest == -1.0) { closest = collision.distance; closestId = currentEntity->id; } } } } return closestId; } void debugWorld(World * world) { int i; Entity * entity; for (i = 0; i < world->entitiesCount; ++i) { entity = &world->entities[i]; bool idMatches = world->lookUp[entity->id] == i; printf("index: %d, look up: %d, id: %d fingerprint: %x, matches: %d\n", i, world->lookUp[entity->id], entity->id, entity->fingerprint, idMatches); } // for (i = 0; i < world->lookUpSize; ++i) { // if (world->lookUp[i] != ENTITY_ID_NONE) // printf("%d\n", world->entities[world->lookUp[i]].id == i); // } if (world->vacantIds == NULL) return; for (i = 0; i < world->vacantIdsCount; ++i) printf("v %d\n", world->vacantIds[i]); puts(""); } KfError addEntryToWorld(World * world, Game * game, WorldEntry entry) { // Create entity. Entity entity = createEntity(entry.type, game); entity.position = entry.position; entity.rotation = entry.rotation; // Add to world. if (addEntityToWorld(world, entity) == ENTITY_NONE) return KFERROR; return KFSUCCESS; } KfError addEntriesToWorld(World * world, Game * game, WorldEntry * entries, size_t entriesCount) { int i; for (i = 0; i < entriesCount; ++i) if (addEntryToWorld(world, game, entries[i]) != KFSUCCESS) return KFERROR; return KFSUCCESS; }