#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; // 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; // Move back entities. for (i = pos; i < world->entitiesCount - 1; ++i) world->entities[i] = world->entities[i + 1]; // Update lookup. for (i = id + 1; i < world->lookUpSize; ++i) if (world->lookUp[i] != ENTITY_ID_NONE) --world->lookUp[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; } 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; 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) { kills[killCount] = entity->id; ++killCount; } } // "bring out your dead!" for (i = 0; i < killCount; ++i) { if (kills[i] == 0) // Hack to keep player alive while debugging. continue; removeEntityFromWorld(world, kills[i]); } } 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; } 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; }