/** * @brief Searches a free spawning point for a given actor size and turns it into an actor * @param[in] player The player to get the free spawn points for * @param[in] actorSize The actor size to get a spawning point for * @return An actor edict or @c NULL if no free spawning point was found */ edict_t* G_ClientGetFreeSpawnPointForActorSize (const player_t *player, const actorSizeEnum_t actorSize) { edict_t *ent; if (actorSize == ACTOR_SIZE_NORMAL) { /* Find valid actor spawn fields for this player. */ ent = G_ClientGetFreeSpawnPoint(player, ET_ACTORSPAWN); if (ent) { edict_t *copy = G_EdictDuplicate(ent); if (copy != NULL) copy->type = ET_ACTOR; ent = copy; } } else if (actorSize == ACTOR_SIZE_2x2) { /* Find valid actor spawn fields for this player. */ ent = G_ClientGetFreeSpawnPoint(player, ET_ACTOR2x2SPAWN); if (ent) { edict_t *copy = G_EdictDuplicate(ent); if (copy != NULL) { copy->type = ET_ACTOR2x2; copy->morale = 100; } ent = copy; } } else { gi.Error("G_ClientGetFreeSpawnPointForActorSize: unknown fieldSize for actor edict (actorSize: %i)\n", actorSize); } if (!ent) return NULL; level.num_spawned[ent->team]++; ent->pnum = player->num; ent->chr.fieldSize = actorSize; ent->fieldSize = ent->chr.fieldSize; ent->flags |= FL_DESTROYABLE; G_VisFlagsReset(ent); gi.LinkEdict(ent); if (ent->spawnflags & STATE_CROUCHED) { ent->think = G_ThinkActorGoCrouch; ent->nextthink = 1; } if (ent->spawnflags & STATE_STUN) { if (ent->spawnflags & STATE_DEAD) ent->HP = 0; ent->think = G_ThinkActorDieAfterSpawn; ent->nextthink = 1; } G_ActorModifyCounters(NULL, ent, 1, 0, 0); G_ReactionFireTargetsCreate(ent); return ent; }
static bool G_InventoryPlaceItemAdjacent (edict_t *ent) { vec2_t oldPos; /* if we have to place it to adjacent */ edict_t *floorAdjacent; int i; Vector2Copy(ent->pos, oldPos); floorAdjacent = NULL; for (i = 0; i < DIRECTIONS; i++) { /** @todo Check whether movement is possible here - otherwise don't use this field */ /* extend pos with the direction vectors */ /** @todo Don't know why the adjacent stuff has been disabled, but if it was buggy, it's probably */ /** because the third ent->pos in the next line should be pos[1] ?!. (Duke, 13.1.11) */ Vector2Set(ent->pos, ent->pos[0] + dvecs[i][0], ent->pos[0] + dvecs[i][1]); /* now try to get a floor entity for that new location */ floorAdjacent = G_GetFloorItems(ent); if (!floorAdjacent) { floorAdjacent = G_SpawnFloor(ent->pos); } else { /* destroy this edict (send this event to all clients that see the edict) */ G_EventPerish(floorAdjacent); G_VisFlagsReset(floorAdjacent); } INVSH_FindSpace(&floorAdjacent->i, &ic->item, INVDEF(gi.csi->idFloor), &x, &y, ic); if (x != NONE) { ic->x = x; ic->y = y; ic->next = FLOOR(floorAdjacent); FLOOR(floorAdjacent) = ic; break; } /* restore original pos */ Vector2Copy(oldPos, ent->pos); } /* added to adjacent pos? */ if (i < DIRECTIONS) { /* restore original pos - if no free space, this was done * already in the for loop */ Vector2Copy(oldPos, ent->pos); return false; } if (floorAdjacent) G_CheckVis(floorAdjacent, true); return true; }
/** * @brief Move the whole given inventory to the floor and destroy the items that do not fit there. * @param[in] ent Pointer to an edict_t being an actor. * @sa G_ActorDie */ void G_InventoryToFloor (edict_t *ent) { invList_t *ic, *next; containerIndex_t container; edict_t *floor; item_t item; /* check for items */ for (container = 0; container < gi.csi->numIDs; container++) { /* ignore items linked from any temp container */ if (INVDEF(container)->temp) continue; if (G_InventoryDropToFloorCheck(ent, container)) break; } /* edict is not carrying any items */ if (container >= gi.csi->numIDs) return; /* find the floor */ floor = G_GetFloorItems(ent); if (!floor) { floor = G_SpawnFloor(ent->pos); } else { /* destroy this edict (send this event to all clients that see the edict) */ G_EventPerish(floor); G_VisFlagsReset(floor); } /* drop items */ /* cycle through all containers */ for (container = 0; container < gi.csi->numIDs; container++) { /* skip floor - we want to drop to floor */ if (container == gi.csi->idFloor) continue; /* skip csi->idArmour, we will collect armours using idArmour container, * not idFloor */ if (container == gi.csi->idArmour) continue; /* now cycle through all items for the container of the character (or the entity) */ for (ic = CONTAINER(ent, container); ic; ic = next) { /* Save the next inv-list before it gets overwritten below. * Do not put this in the "for" statement, * unless you want an endless loop. ;) */ next = ic->next; item = ic->item; /* only floor can summarize, so everything on the actor must have amount=1 */ assert(item.amount == 1); if (!game.i.RemoveFromInventory(&game.i, &ent->chr.i, INVDEF(container), ic)) gi.Error("Could not remove item '%s' from inventory %i of entity %i", ic->item.item->id, container, ent->number); if (game.i.AddToInventory(&game.i, &floor->chr.i, &item, INVDEF(gi.csi->idFloor), NONE, NONE, 1) == NULL) gi.Error("Could not add item '%s' from inventory %i of entity %i to floor container", ic->item.item->id, container, ent->number); #ifdef ADJACENT G_InventoryPlaceItemAdjacent(ent); #endif } /* destroy link */ CONTAINER(ent, container) = NULL; } FLOOR(ent) = FLOOR(floor); /* send item info to the clients */ G_CheckVis(floor); }