--- deliantra/server/common/object.C 2010/07/02 19:54:41 1.340
+++ deliantra/server/common/object.C 2012/11/12 03:14:32 1.355
@@ -1,24 +1,24 @@
/*
* This file is part of Deliantra, the Roguelike Realtime MMORPG.
- *
- * Copyright (©) 2005,2006,2007,2008,2009,2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
+ *
+ * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
* Copyright (©) 2001 Mark Wedel & Crossfire Development Team
* Copyright (©) 1992 Frank Tore Johansen
- *
+ *
* Deliantra is free software: you can redistribute it and/or modify it under
* the terms of the Affero GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the Affero GNU General Public License
* and the GNU General Public License along with this program. If not, see
* .
- *
+ *
* The authors can be reached via e-mail to
*/
@@ -235,14 +235,14 @@
static bool
compare_ob_value_lists_one (const object *wants, const object *has)
{
- /* n-squared behaviour (see kv_get), but I'm hoping both
+ /* n-squared behaviour (see kv.get), but I'm hoping both
* objects with lists are rare, and lists stay short. If not, use a
* different structure or at least keep the lists sorted...
*/
/* For each field in wants, */
- for (key_value *kv = wants->key_values; kv; kv = kv->next)
- if (has->kv_get (kv->key) != kv->value)
+ for (key_value *kv = wants->kv.first; kv; kv = kv->next)
+ if (has->kv.get (kv->key) != kv->value)
return false;
/* If we get here, every field in wants has a matching field in has. */
@@ -276,9 +276,10 @@
{
/* A couple quick sanity checks */
if (ob1 == ob2
- || ob1->type != ob2->type
- || ob1->value != ob2->value
- || ob1->name != ob2->name
+ || ob1->type != ob2->type
+ || ob1->value != ob2->value
+ || ob1->name != ob2->name
+ || ob1->custom_name != ob2->custom_name
|| fabs (ob1->speed - ob2->speed) >= MIN_ACTIVE_SPEED)
return 0;
@@ -374,10 +375,10 @@
break;
}
- if (ob1->key_values || ob2->key_values)
+ if (!ob1->kv.empty () || !ob2->kv.empty ())
{
/* At least one of these has key_values. */
- if ((!ob1->key_values) != (!ob2->key_values))
+ if (ob1->kv.empty () != ob2->kv.empty ())
return 0; /* One has fields, but the other one doesn't. */
if (!compare_ob_value_lists (ob1, ob2))
@@ -447,12 +448,13 @@
}
// adjust weight per container type ("of holding")
-static uint32
-weight_adjust_for (object *op, uint32 weight)
+static weight_t
+weight_adjust_for (object *op, weight_t weight)
{
- return op->type == CONTAINER
- ? weight - weight * op->stats.Str / 100
- : weight;
+ if (op->type == CONTAINER)
+ weight -= weight * op->stats.Str / 100;
+
+ return weight;
}
/*
@@ -460,22 +462,22 @@
* and also updates how much the environment(s) is/are carrying.
*/
static void
-adjust_weight (object *op, sint32 sub, sint32 add)
+adjust_weight (object *op, weight_t sub, weight_t add)
{
while (op)
{
- sint32 ocarrying = op->carrying;
+ weight_t carrying = op->carrying
+ - weight_adjust_for (op, sub);
+ + weight_adjust_for (op, add);
- op->carrying -= weight_adjust_for (op, sub);
- op->carrying += weight_adjust_for (op, add);
+ sub = op->carrying;
+ op->carrying = carrying;
+ add = op->carrying;
if (object *pl = op->visible_to ())
if (pl != op) // player is handled lazily
esrv_update_item (UPD_WEIGHT, pl, op);
- sub = ocarrying;
- add = op->carrying;
-
op = op->env;
}
}
@@ -488,7 +490,7 @@
void
object::update_weight ()
{
- sint32 sum = 0;
+ weight_t sum = 0;
for (object *op = inv; op; op = op->below)
{
@@ -600,23 +602,6 @@
this->owner = owner;
}
-/* Zero the key_values on op, decrementing the shared-string
- * refcounts and freeing the links.
- */
-static void
-free_key_values (object *op)
-{
- for (key_value *i = op->key_values; i; )
- {
- key_value *next = i->next;
- delete i;
-
- i = next;
- }
-
- op->key_values = 0;
-}
-
/*
* copy_to first frees everything allocated by the dst object,
* and then copies the contents of itself into the second
@@ -630,36 +615,11 @@
{
dst->remove ();
*(object_copy *)dst = *this;
- dst->flag [FLAG_REMOVED] = true;
-
- /* Copy over key_values, if any. */
- if (key_values)
- {
- key_value *tail = 0;
- dst->key_values = 0;
-
- for (key_value *i = key_values; i; i = i->next)
- {
- key_value *new_link = new key_value;
- new_link->next = 0;
- new_link->key = i->key;
- new_link->value = i->value;
-
- /* Try and be clever here, too. */
- if (!dst->key_values)
- {
- dst->key_values = new_link;
- tail = new_link;
- }
- else
- {
- tail->next = new_link;
- tail = new_link;
- }
- }
- }
+ // maybe move to object_copy?
+ dst->kv = kv;
+ dst->flag [FLAG_REMOVED] = true;
dst->activate ();
}
@@ -669,7 +629,7 @@
if (!uuid.seq) // HACK
uuid = UUID::gen ();
- // TODO: unclean state changes, should nt be done in copy_to AND instantiate
+ // TODO: unclean state changes, should not be done in copy_to AND instantiate
if (flag [FLAG_RANDOM_SPEED] && speed)
speed_left = - speed - rndm (); // TODO animation
else
@@ -780,7 +740,7 @@
mapspace &m = op->ms ();
if (!(m.flags_ & P_UPTODATE))
- /* nop */;
+ m.update_up (); // nothing to do except copy up
else if (action == UP_OBJ_INSERT)
{
#if 0
@@ -811,7 +771,7 @@
else if (action == UP_OBJ_CHANGE || action == UP_OBJ_REMOVE)
m.invalidate ();
else if (action == UP_OBJ_FACE)
- /* Nothing to do for that case */ ;
+ m.update_up (); // nothing to do for that case, except copy up
else
LOG (llevError, "update_object called with invalid action: %d\n", action);
@@ -832,7 +792,7 @@
{
unlink ();
- free_key_values (this);
+ kv.clear ();
}
void object::link ()
@@ -941,7 +901,7 @@
*/
if (!drop_to_ground
|| !map
- || map->in_memory != MAP_ACTIVE
+ || !map->linkable ()
|| map->no_drop
|| ms ().move_block == MOVE_ALL)
{
@@ -1048,25 +1008,6 @@
++free_count;
}
-static struct freed_map : maptile
-{
- freed_map ()
- : maptile (3, 3)
- {
- path = "";
- name = "/internal/freed_objects_map";
- no_drop = 1;
- no_reset = 1;
-
- in_memory = MAP_ACTIVE;
- }
-
- ~freed_map ()
- {
- destroy ();
- }
-} freed_map; // freed objects are moved here to avoid crashes
-
void
object::do_destroy ()
{
@@ -1242,9 +1183,6 @@
ms.invalidate ();
- if (map->in_memory == MAP_SAVING)
- return;
-
int check_walk_off = !flag [FLAG_NO_APPLY];
if (object *pl = ms.player ())
@@ -1388,7 +1326,7 @@
if (m == &freed_map)//D TODO: remove soon
{//D
- LOG (llevError | logBacktrace, "tries to insret object on freed objects map: %s", op->debug_desc ());//D
+ LOG (llevError | logBacktrace, "tries to insert object on freed objects map: %s", op->debug_desc ());//D
}//D
/* Ideally, the caller figures this out. However, it complicates a lot
@@ -1671,7 +1609,7 @@
if (nrof > nr)
{
- sint64 oweight = total_weight ();
+ weight_t oweight = total_weight ();
nrof -= nr;
@@ -1765,15 +1703,15 @@
/* return the original object and remove inserted object
(client prefers the original object) */
- // carring must be 0 for mergable objects
- sint64 oweight = tmp->weight * tmp->nrof;
+ // carrying must be 0 for mergable objects
+ weight_t oweight = weight_t (tmp->weight) * tmp->nrof;
tmp->nrof += op->nrof;
if (object *pl = tmp->visible_to ())
esrv_update_item (UPD_NROF, pl, tmp);
- adjust_weight (this, oweight, tmp->weight * tmp->nrof);
+ adjust_weight (this, oweight, weight_t (tmp->weight) * tmp->nrof);
op->destroy ();
op = tmp;
@@ -2073,7 +2011,7 @@
find_free_spot (const object *ob, maptile *m, int x, int y, int start, int stop)
{
int altern[SIZEOFFREE];
- int index = 0, flag;
+ int index = 0;
for (int i = start; i < stop; i++)
{
@@ -2195,7 +2133,7 @@
int
find_dir (maptile *m, int x, int y, object *exclude)
{
- int max = SIZEOFFREE, mflags;
+ int max = SIZEOFFREE;
MoveType move_type;
if (exclude && exclude->head_ () != exclude)
@@ -2456,6 +2394,8 @@
!item->flag [FLAG_ALIVE] && !item->invisible && (who->is_player () || item->weight < who->weight / 3));
}
+//-GPL
+
/*
* create clone from object to another
*/
@@ -2495,10 +2435,26 @@
return 0;
}
+/* Zero the key_values on op, decrementing the shared-string
+ * refcounts and freeing the links.
+ */
+void
+key_values::clear ()
+{
+ for (key_value *kvp = first; kvp; )
+ {
+ key_value *next = kvp->next;
+ delete kvp;
+ kvp = next;
+ }
+
+ first = 0;
+}
+
shstr_tmp
-object::kv_get (shstr_tmp key) const
+key_values::get (shstr_tmp key) const
{
- for (key_value *kv = key_values; kv; kv = kv->next)
+ for (key_value *kv = first; kv; kv = kv->next)
if (kv->key == key)
return kv->value;
@@ -2506,28 +2462,34 @@
}
void
-object::kv_set (shstr_tmp key, shstr_tmp value)
+key_values::add (shstr_tmp key, shstr_tmp value)
+{
+ key_value *kv = new key_value;
+
+ kv->next = first;
+ kv->key = key;
+ kv->value = value;
+
+ first = kv;
+}
+
+void
+key_values::set (shstr_tmp key, shstr_tmp value)
{
- for (key_value *kv = key_values; kv; kv = kv->next)
+ for (key_value *kv = first; kv; kv = kv->next)
if (kv->key == key)
{
kv->value = value;
return;
}
- key_value *kv = new key_value;
-
- kv->next = key_values;
- kv->key = key;
- kv->value = value;
-
- key_values = kv;
+ add (key, value);
}
void
-object::kv_del (shstr_tmp key)
+key_values::del (shstr_tmp key)
{
- for (key_value **kvp = &key_values; *kvp; kvp = &(*kvp)->next)
+ for (key_value **kvp = &first; *kvp; kvp = &(*kvp)->next)
if ((*kvp)->key == key)
{
key_value *kv = *kvp;
@@ -2537,6 +2499,34 @@
}
}
+void
+key_values::reverse ()
+{
+ key_value *prev = 0;
+ key_value *head = first;
+
+ while (head)
+ {
+ key_value *node = head;
+ head = head->next;
+ node->next = prev;
+ prev = node;
+ }
+
+ first = prev;
+}
+
+key_values &
+key_values::operator =(const key_values &kv)
+{
+ clear ();
+
+ for (key_value *kvp = kv.first; kvp; kvp = kvp->next)
+ add (kvp->key, kvp->value);
+
+ reverse ();
+}
+
object::depth_iterator::depth_iterator (object *container)
: iterator_base (container)
{
@@ -2628,6 +2618,8 @@
: region::default_region ();
}
+//+GPL
+
void
object::open_container (object *new_container)
{
@@ -2694,6 +2686,38 @@
// contr->ns->floorbox_reset ();
}
+//-GPL
+
+// prefetch some flat area around the player
+static void
+prefetch_surrounding_area (object *op, maptile *map, int range)
+{
+ for (maprect *rect = map->split_to_tiles (mapwalk_buf,
+ op->x - range , op->y - range ,
+ op->x + range + 1, op->y + range + 1);
+ rect->m;
+ ++rect)
+ {
+ rect->m->touch ();
+ rect->m->activate ();
+ }
+}
+
+// prefetch a generous area around the player, also up and down
+void
+object::prefetch_surrounding_maps ()
+{
+ prefetch_surrounding_area (this, map, 40);
+
+ if (maptile *m = map->tile_available (TILE_DOWN))
+ prefetch_surrounding_area (this, m, 20);
+
+ if (maptile *m = map->tile_available (TILE_UP))
+ prefetch_surrounding_area (this, m, 20);
+}
+
+//+GPL
+
object *
object::force_find (shstr_tmp name)
{
@@ -2707,8 +2731,6 @@
return 0;
}
-//-GPL
-
void
object::force_set_timer (int duration)
{
@@ -2724,7 +2746,7 @@
if (object *force = force_find (name))
force->destroy ();
- object *force = get_archetype (FORCE_NAME);
+ object *force = archetype::get (FORCE_NAME);
force->slaying = name;
force->force_set_timer (duration);