g_inventory.c

Go to the documentation of this file.
00001 
00005 /*
00006 Copyright (C) 2002-2010 UFO: Alien Invasion.
00007 
00008 This program is free software; you can redistribute it and/or
00009 modify it under the terms of the GNU General Public License
00010 as published by the Free Software Foundation; either version 2
00011 of the License, or (at your option) any later version.
00012 
00013 This program is distributed in the hope that it will be useful,
00014 but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00016 
00017 See the GNU General Public License for more details.
00018 
00019 You should have received a copy of the GNU General Public License
00020 along with this program; if not, write to the Free Software
00021 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00022 
00023 */
00024 
00025 #include "g_local.h"
00026 
00032 edict_t *G_GetFloorItemsFromPos (const pos3_t pos)
00033 {
00034     return G_GetEdictFromPos(pos, ET_ITEM);
00035 }
00036 
00043 edict_t *G_GetFloorItems (edict_t * ent)
00044 {
00045     edict_t *floor = G_GetFloorItemsFromPos(ent->pos);
00046     /* found items */
00047     if (floor) {
00048         FLOOR(ent) = FLOOR(floor);
00049         return floor;
00050     }
00051 
00052     /* no items on ground found */
00053     FLOOR(ent) = NULL;
00054     return NULL;
00055 }
00056 
00064 qboolean G_InventoryRemoveItemByID (const char *itemID, edict_t *ent, containerIndex_t container)
00065 {
00066     invList_t *ic = CONTAINER(ent, container);
00067     while (ic) {
00068         objDef_t *item = ic->item.t;
00069         if (item != NULL && !strcmp(item->id, itemID)) {
00070             /* remove the virtual item to update the inventory lists */
00071             if (!game.i.RemoveFromInventory(&game.i, &ent->chr.i, INVDEF(container), ic))
00072                 gi.Error("Could not remove item '%s' from inventory %i",
00073                         ic->item.t->id, container);
00074             G_EventInventoryDelete(ent, G_VisToPM(ent->visflags), INVDEF(container), ic->x, ic->y);
00075             return qtrue;
00076         }
00077         ic = ic->next;
00078     }
00079 
00080     return qfalse;
00081 }
00082 
00090 static qboolean G_InventoryDropToFloorCheck (edict_t* ent, containerIndex_t container)
00091 {
00092     invList_t* ic = CONTAINER(ent, container);
00093 
00094     if (container == gi.csi->idArmour)
00095         return qfalse;
00096 
00097     if (ic) {
00098         qboolean check = qfalse;
00099         while (ic) {
00100             assert(ic->item.t);
00101             if (ic->item.t->isVirtual) {
00102                 invList_t *next = ic->next;
00103                 /* remove the virtual item to update the inventory lists */
00104                 if (!game.i.RemoveFromInventory(&game.i, &ent->chr.i, INVDEF(container), ic))
00105                     gi.Error("Could not remove virtual item '%s' from inventory %i",
00106                             ic->item.t->id, container);
00107                 ic = next;
00108             } else {
00109                 /* there are none virtual items left that should be send to the client */
00110                 check = qtrue;
00111                 ic = ic->next;
00112             }
00113         }
00114         return check;
00115     }
00116 
00117     return qfalse;
00118 }
00119 
00125 qboolean G_AddItemToFloor (const pos3_t pos, const char *itemID)
00126 {
00127     edict_t *floor;
00128     item_t item = {NONE_AMMO, NULL, NULL, 0, 0};
00129     objDef_t *od = INVSH_GetItemByIDSilent(itemID);
00130     if (!od) {
00131         gi.DPrintf("Could not find item '%s'\n", itemID);
00132         return qfalse;
00133     }
00134 
00135     /* Also sets FLOOR(ent) to correct value. */
00136     floor = G_GetFloorItemsFromPos(pos);
00137     /* nothing on the ground yet? */
00138     if (!floor)
00139         floor = G_SpawnFloor(pos);
00140 
00141     item.t = od;
00142     return game.i.TryAddToInventory(&game.i, &floor->chr.i, item, INVDEF(gi.csi->idFloor));
00143 }
00144 
00147 /* #define ADJACENT */
00148 
00149 #ifdef ADJACENT
00150 static qboolean G_InventoryPlaceItemAdjacent (edict_t *ent)
00151 {
00152     vec2_t oldPos; /* if we have to place it to adjacent  */
00153     edict_t *floorAdjacent;
00154     int i;
00155 
00156     Vector2Copy(ent->pos, oldPos);
00157     floorAdjacent = NULL;
00158 
00159     for (i = 0; i < DIRECTIONS; i++) {
00161         /* extend pos with the direction vectors */
00162         Vector2Set(ent->pos, ent->pos[0] + dvecs[i][0], ent->pos[0] + dvecs[i][1]);
00163         /* now try to get a floor entity for that new location */
00164         floorAdjacent = G_GetFloorItems(ent);
00165         if (!floorAdjacent) {
00166             floorAdjacent = G_SpawnFloor(ent->pos);
00167         } else {
00168             /* destroy this edict (send this event to all clients that see the edict) */
00169             G_EventPerish(floorAdjacent);
00170             floorAdjacent->visflags = 0;
00171         }
00172 
00173         INVSH_FindSpace(&floorAdjacent->i, &ic->item, INVDEF(gi.csi->idFloor), &x, &y, ic);
00174         if (x != NONE) {
00175             ic->x = x;
00176             ic->y = y;
00177             ic->next = FLOOR(floorAdjacent);
00178             FLOOR(floorAdjacent) = ic;
00179             break;
00180         }
00181         /* restore original pos */
00182         Vector2Copy(oldPos, ent->pos);
00183     }
00184 
00185     /* added to adjacent pos? */
00186     if (i < DIRECTIONS) {
00187         /* restore original pos - if no free space, this was done
00188          * already in the for loop */
00189         Vector2Copy(oldPos, ent->pos);
00190         return qfalse;
00191     }
00192 
00193     if (floorAdjacent)
00194         G_CheckVis(floorAdjacent, qtrue);
00195 
00196     return qtrue;
00197 }
00198 #endif
00199 
00205 void G_InventoryToFloor (edict_t *ent)
00206 {
00207     invList_t *ic, *next;
00208     containerIndex_t container;
00209     edict_t *floor;
00210     item_t item;
00211 
00212     /* check for items */
00213     for (container = 0; container < gi.csi->numIDs; container++) {
00214         /* ignore items linked from any temp container */
00215         if (INVDEF(container)->temp)
00216             continue;
00217         if (G_InventoryDropToFloorCheck(ent, container))
00218             break;
00219     }
00220 
00221     /* edict is not carrying any items */
00222     if (container >= gi.csi->numIDs)
00223         return;
00224 
00225     /* find the floor */
00226     floor = G_GetFloorItems(ent);
00227     if (!floor) {
00228         floor = G_SpawnFloor(ent->pos);
00229     } else {
00230         /* destroy this edict (send this event to all clients that see the edict) */
00231         G_EventPerish(floor);
00232         floor->visflags = 0;
00233     }
00234 
00235     /* drop items */
00236     /* cycle through all containers */
00237     for (container = 0; container < gi.csi->numIDs; container++) {
00238         /* skip floor - we want to drop to floor */
00239         if (container == gi.csi->idFloor)
00240             continue;
00241 
00242         /* skip csi->idArmour, we will collect armours using idArmour container,
00243          * not idFloor */
00244         if (container == gi.csi->idArmour)
00245             continue;
00246 
00247         /* now cycle through all items for the container of the character (or the entity) */
00248         for (ic = CONTAINER(ent, container); ic; ic = next) {
00249             /* Save the next inv-list before it gets overwritten below.
00250              * Do not put this in the "for" statement,
00251              * unless you want an endless loop. ;) */
00252             next = ic->next;
00253             item = ic->item;
00254 
00255             /* only floor can summarize, so everything on the actor must have amount=1 */
00256             assert(item.amount == 1);
00257             if (!game.i.RemoveFromInventory(&game.i, &ent->chr.i, INVDEF(container), ic))
00258                 gi.Error("Could not remove item '%s' from inventory %i of entity %i",
00259                         ic->item.t->id, container, ent->number);
00260             if (game.i.AddToInventory(&game.i, &floor->chr.i, item, INVDEF(gi.csi->idFloor), NONE, NONE, 1) == NULL)
00261                 gi.Error("Could not add item '%s' from inventory %i of entity %i to floor container",
00262                         ic->item.t->id, container, ent->number);
00263 #ifdef ADJACENT
00264             G_InventoryPlaceItemAdjacent(ent);
00265 #endif
00266         }
00267         /* destroy link */
00268         CONTAINER(ent, container) = NULL;
00269     }
00270 
00271     FLOOR(ent) = FLOOR(floor);
00272 
00273     /* send item info to the clients */
00274     G_CheckVis(floor, qtrue);
00275 }
00276 
00286 void G_ReadItem (item_t *item, invDef_t **container, int *x, int *y)
00287 {
00288     int t, m;
00289     containerIndex_t containerID;
00290 
00291     gi.ReadFormat("sbsbbbbs", &t, &item->a, &m, &containerID, x, y, &item->rotated, &item->amount);
00292 
00293     if (t < 0 || t >= gi.csi->numODs)
00294         gi.Error("Item index out of bounds: %i", t);
00295     item->t = &gi.csi->ods[t];
00296 
00297     if (m != NONE) {
00298         if (m < 0 || m >= gi.csi->numODs)
00299             gi.Error("Ammo index out of bounds: %i", m);
00300         item->m = &gi.csi->ods[m];
00301     } else {
00302         item->m = NULL;
00303     }
00304 
00305     if (containerID >= 0 && containerID < gi.csi->numIDs)
00306         *container = INVDEF(containerID);
00307     else
00308         gi.Error("container id is out of bounds: %i", containerID);
00309 }
00310 
00320 void G_WriteItem (const item_t *item, const invDef_t *container, int x, int y)
00321 {
00322     assert(item);
00323     assert(item->t);
00324     gi.WriteFormat("sbsbbbbs", item->t->idx, item->a, item->m ? item->m->idx : NONE, container->id, x, y, item->rotated, item->amount);
00325 }
00326 
00334 void G_SendInventory (unsigned int playerMask, const edict_t *ent)
00335 {
00336     invList_t *ic;
00337     int nr = 0;
00338     containerIndex_t container;
00339 
00340     /* test for pointless player mask */
00341     if (!playerMask)
00342         return;
00343 
00344     for (container = 0; container < gi.csi->numIDs; container++) {
00345         for (ic = CONTAINER(ent, container); ic; ic = ic->next)
00346             nr++;
00347     }
00348 
00349     /* return if no inventory items to send */
00350     if (nr == 0)
00351         return;
00352 
00353     G_EventInventoryAdd(ent, playerMask, nr);
00354     for (container = 0; container < gi.csi->numIDs; container++) {
00355         for (ic = CONTAINER(ent, container); ic; ic = ic->next) {
00356             /* send a single item */
00357             assert(ic->item.t);
00358             G_WriteItem(&ic->item, INVDEF(container), ic->x, ic->y);
00359         }
00360     }
00361 }

Generated by  doxygen 1.6.2