--- deliantra/server/common/object.C 2006/09/11 12:10:21 1.28
+++ deliantra/server/common/object.C 2007/08/20 19:13:10 1.183
@@ -1,25 +1,25 @@
/*
- CrossFire, A Multiplayer game for X-windows
-
- Copyright (C) 2001 Mark Wedel & Crossfire Development Team
- Copyright (C) 1992 Frank Tore Johansen
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 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 GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- The authors can be reached via e-mail at crossfire-devel@real-time.com
-*/
+ * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
+ *
+ * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
+ * Copyright (©) 2001,2007 Mark Wedel & Crossfire Development Team
+ * Copyright (©) 1992,2007 Frank Tore Johansen
+ *
+ * Crossfire TRT is free software: you can redistribute it and/or modify
+ * it under the terms of the 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 GNU General Public License
+ * along with this program. If not, see .
+ *
+ * The authors can be reached via e-mail to
+ */
/* Eneq(@csd.uu.se): Added weight-modifiers in environment of objects.
sub/add_weight will transcend the environment updating the carrying
@@ -30,13 +30,17 @@
#include
#include
#include
-#include
+#include
#include
+#include
+
int nrofallocobjects = 0;
+static UUID uuid;
+const uint64 UUID_SKIP = 1<<19;
-object *objects; /* Pointer to the list of used objects */
-object *active_objects; /* List of active objects that need to be processed */
+objectvec objects;
+activevec actives;
short freearr_x[SIZEOFFREE] = { 0, 0, 1, 1, 1, 0, -1, -1, -1, 0, 1, 2, 2, 2, 2, 2, 1, 0, -1, -2, -2, -2, -2, -2, -1,
0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0, -1, -2, -3, -3, -3, -3, -3, -3, -3, -2, -1
@@ -52,6 +56,83 @@
1, 2, 2, 2, 2, 2, 3, 4, 4, 4, 4, 4, 5, 6, 6, 6, 6, 6, 7, 8, 8, 8, 8, 8
};
+static void
+write_uuid (void)
+{
+ char filename1[MAX_BUF], filename2[MAX_BUF];
+
+ sprintf (filename1, "%s/uuid", settings.localdir);
+ sprintf (filename2, "%s/uuid~", settings.localdir);
+
+ FILE *fp;
+
+ if (!(fp = fopen (filename2, "w")))
+ {
+ LOG (llevError, "ERROR: cannot open %s for writing, unable to write UUID!\n", filename2);
+ return;
+ }
+
+ fprintf (fp, "<1,%llx>\n", (unsigned long long)uuid.seq + UUID_SKIP * 2);
+ fclose (fp);
+ rename (filename2, filename1);
+}
+
+static void
+read_uuid (void)
+{
+ char filename[MAX_BUF];
+
+ sprintf (filename, "%s/uuid", settings.localdir);
+
+ FILE *fp;
+
+ if (!(fp = fopen (filename, "r")))
+ {
+ if (errno == ENOENT)
+ {
+ LOG (llevInfo, "RESET uid to 1\n");
+ uuid.seq = 0;
+ write_uuid ();
+ return;
+ }
+
+ LOG (llevError, "FATAL: cannot open %s for reading!\n", filename);
+ _exit (1);
+ }
+
+ int version;
+ unsigned long long uid;
+ if (2 != fscanf (fp, "<%d,%llx>\n", &version, &uid) || version != 1)
+ {
+ LOG (llevError, "FATAL: error reading uid from %s!\n", filename);
+ _exit (1);
+ }
+
+ uuid.seq = uid;
+ write_uuid ();
+ LOG (llevDebug, "read UID: %" PRId64 "\n", uid);
+ fclose (fp);
+}
+
+UUID
+gen_uuid ()
+{
+ UUID uid;
+
+ uid.seq = ++uuid.seq;
+
+ if (!(uuid.seq & (UUID_SKIP - 1)))
+ write_uuid ();
+
+ return uid;
+}
+
+void
+init_uuid ()
+{
+ read_uuid ();
+}
+
/* Returns TRUE if every key_values in wants has a partner with the same value in has. */
static int
compare_ob_value_lists_one (const object *wants, const object *has)
@@ -64,7 +145,7 @@
*/
/* For each field in wants, */
- for (wants_field = wants->key_values; wants_field != NULL; wants_field = wants_field->next)
+ for (wants_field = wants->key_values; wants_field; wants_field = wants_field->next)
{
key_value *has_field;
@@ -108,21 +189,22 @@
* replaces - this is mostly for clarity - a decent compiler should hopefully
* reduce this to the same efficiency.
*
- * Check nrof variable *before* calling CAN_MERGE()
+ * Check nrof variable *before* calling can_merge()
*
* Improvements made with merge: Better checking on potion, and also
* check weight
*/
-
-bool object::can_merge (object *ob1, object *ob2)
+bool object::can_merge_slow (object *ob1, object *ob2)
{
/* A couple quicksanity checks */
- if ((ob1 == ob2) || (ob1->type != ob2->type))
- return 0;
-
- if (ob1->speed != ob2->speed)
+ if (ob1 == ob2
+ || ob1->type != ob2->type
+ || ob1->speed != ob2->speed
+ || ob1->value != ob2->value
+ || ob1->name != ob2->name)
return 0;
+ //TODO: this ain't working well, use nicer and correct overflow check
/* Do not merge objects if nrof would overflow. We use 1UL<<31 since that
* value could not be stored in a sint32 (which unfortunately sometimes is
* used to store nrof).
@@ -142,37 +224,31 @@
if (QUERY_FLAG (ob2, FLAG_IDENTIFIED))
SET_FLAG (ob2, FLAG_BEEN_APPLIED);
-
- /* the 0x400000 on flags2 is FLAG_INV_LOCK. I don't think something
- * being locked in inventory should prevent merging.
- * 0x4 in flags3 is CLIENT_SENT
- */
- if ((ob1->arch != ob2->arch) ||
- (ob1->flags[0] != ob2->flags[0]) ||
- (ob1->flags[1] != ob2->flags[1]) ||
- ((ob1->flags[2] & ~0x400000) != (ob2->flags[2] & ~0x400000)) ||
- ((ob1->flags[3] & ~0x4) != (ob2->flags[3] & ~0x4)) ||
- (ob1->name != ob2->name) ||
- (ob1->title != ob2->title) ||
- (ob1->msg != ob2->msg) ||
- (ob1->weight != ob2->weight) ||
- (memcmp (&ob1->resist, &ob2->resist, sizeof (ob1->resist)) != 0) ||
- (memcmp (&ob1->stats, &ob2->stats, sizeof (ob1->stats)) != 0) ||
- (ob1->attacktype != ob2->attacktype) ||
- (ob1->magic != ob2->magic) ||
- (ob1->slaying != ob2->slaying) ||
- (ob1->skill != ob2->skill) ||
- (ob1->value != ob2->value) ||
- (ob1->animation_id != ob2->animation_id) ||
- (ob1->client_type != ob2->client_type) ||
- (ob1->materialname != ob2->materialname) ||
- (ob1->lore != ob2->lore) ||
- (ob1->subtype != ob2->subtype) ||
- (ob1->move_type != ob2->move_type) ||
- (ob1->move_block != ob2->move_block) ||
- (ob1->move_allow != ob2->move_allow) ||
- (ob1->move_on != ob2->move_on) ||
- (ob1->move_off != ob2->move_off) || (ob1->move_slow != ob2->move_slow) || (ob1->move_slow_penalty != ob2->move_slow_penalty))
+ if ((ob1->flag ^ ob2->flag).reset (FLAG_INV_LOCKED).reset (FLAG_CLIENT_SENT).any ()
+ || ob1->arch != ob2->arch
+ || ob1->name != ob2->name
+ || ob1->title != ob2->title
+ || ob1->msg != ob2->msg
+ || ob1->weight != ob2->weight
+ || memcmp (&ob1->resist, &ob2->resist, sizeof (ob1->resist))
+ || memcmp (&ob1->stats , &ob2->stats , sizeof (ob1->stats) )
+ || ob1->attacktype != ob2->attacktype
+ || ob1->magic != ob2->magic
+ || ob1->slaying != ob2->slaying
+ || ob1->skill != ob2->skill
+ || ob1->value != ob2->value
+ || ob1->animation_id != ob2->animation_id
+ || ob1->client_type != ob2->client_type
+ || ob1->materialname != ob2->materialname
+ || ob1->lore != ob2->lore
+ || ob1->subtype != ob2->subtype
+ || ob1->move_type != ob2->move_type
+ || ob1->move_block != ob2->move_block
+ || ob1->move_allow != ob2->move_allow
+ || ob1->move_on != ob2->move_on
+ || ob1->move_off != ob2->move_off
+ || ob1->move_slow != ob2->move_slow
+ || ob1->move_slow_penalty != ob2->move_slow_penalty)
return 0;
/* This is really a spellbook check - really, we should
@@ -185,7 +261,7 @@
return 0;
/* Now check to see if the two inventory objects could merge */
- if (!CAN_MERGE (ob1->inv, ob2->inv))
+ if (!object::can_merge (ob1->inv, ob2->inv))
return 0;
/* inventory ok - still need to check rest of this object to see
@@ -204,15 +280,15 @@
* be animated or have a very low speed. Is this an attempted monster
* check?
*/
- if (!QUERY_FLAG (ob1, FLAG_ANIMATE) && FABS ((ob1)->speed) > MIN_ACTIVE_SPEED)
+ if (!QUERY_FLAG (ob1, FLAG_ANIMATE) && ob1->has_active_speed ())
return 0;
switch (ob1->type)
{
- case SCROLL:
- if (ob1->level != ob2->level)
- return 0;
- break;
+ case SCROLL:
+ if (ob1->level != ob2->level)
+ return 0;
+ break;
}
if (ob1->key_values != NULL || ob2->key_values != NULL)
@@ -225,14 +301,14 @@
return 0;
}
- //TODO: generate an event or call into perl for additional checks
if (ob1->self || ob2->self)
{
ob1->optimise ();
ob2->optimise ();
if (ob1->self || ob2->self)
- return 0;
+ if (!cfperl_can_merge (ob1, ob2))
+ return 0;
}
/* Everything passes, must be OK. */
@@ -250,16 +326,20 @@
long sum;
object *inv;
- for (sum = 0, inv = op->inv; inv != NULL; inv = inv->below)
+ for (sum = 0, inv = op->inv; inv; inv = inv->below)
{
if (inv->inv)
sum_weight (inv);
+
sum += inv->carrying + inv->weight * (inv->nrof ? inv->nrof : 1);
}
+
if (op->type == CONTAINER && op->stats.Str)
sum = (sum * (100 - op->stats.Str)) / 100;
+
if (op->carrying != sum)
op->carrying = sum;
+
return sum;
}
@@ -276,102 +356,19 @@
}
/*
- * Eneq(@csd.uu.se): Since we can have items buried in a character we need
- * a better check. We basically keeping traversing up until we can't
- * or find a player.
- */
-
-object *
-is_player_inv (object *op)
-{
- for (; op != NULL && op->type != PLAYER; op = op->env)
- if (op->env == op)
- op->env = NULL;
- return op;
-}
-
-/*
* Used by: Crossedit: dump. Server DM commands: dumpbelow, dump.
* Some error messages.
* The result of the dump is stored in the static global errmsg array.
*/
-
-void
-dump_object2 (object *op)
-{
- errmsg[0] = 0;
- return;
- //TODO//D#d#
-#if 0
- char *cp;
-
-/* object *tmp;*/
-
- if (op->arch != NULL)
- {
- strcat (errmsg, "arch ");
- strcat (errmsg, op->arch->name ? op->arch->name : "(null)");
- strcat (errmsg, "\n");
- if ((cp = get_ob_diff (op, &empty_archetype->clone)) != NULL)
- strcat (errmsg, cp);
-# if 0
- /* Don't dump player diffs - they are too long, mostly meaningless, and
- * will overflow the buffer.
- * Changed so that we don't dump inventory either. This may
- * also overflow the buffer.
- */
- if (op->type != PLAYER && (cp = get_ob_diff (op, &empty_archetype->clone)) != NULL)
- strcat (errmsg, cp);
- for (tmp = op->inv; tmp; tmp = tmp->below)
- dump_object2 (tmp);
-# endif
- strcat (errmsg, "end\n");
- }
- else
- {
- strcat (errmsg, "Object ");
- if (op->name == NULL)
- strcat (errmsg, "(null)");
- else
- strcat (errmsg, op->name);
- strcat (errmsg, "\n");
-# if 0
- if ((cp = get_ob_diff (op, &empty_archetype->clone)) != NULL)
- strcat (errmsg, cp);
- for (tmp = op->inv; tmp; tmp = tmp->below)
- dump_object2 (tmp);
-# endif
- strcat (errmsg, "end\n");
- }
-#endif
-}
-
-/*
- * Dumps an object. Returns output in the static global errmsg array.
- */
-
-void
+char *
dump_object (object *op)
{
- if (op == NULL)
- {
- strcpy (errmsg, "[NULL pointer]");
- return;
- }
- errmsg[0] = '\0';
- dump_object2 (op);
-}
-
-void
-dump_all_objects (void)
-{
- object *op;
+ if (!op)
+ return strdup ("[NULLOBJ]");
- for (op = objects; op != NULL; op = op->next)
- {
- dump_object (op);
- fprintf (logfile, "Object %d\n:%s\n", op->count, errmsg);
- }
+ object_freezer freezer;
+ op->write (freezer);
+ return freezer.as_string ();
}
/*
@@ -397,16 +394,14 @@
/*
* Returns the object which has the count-variable equal to the argument.
*/
-
object *
find_object (tag_t i)
{
- object *op;
+ for_all_objects (op)
+ if (op->count == i)
+ return op;
- for (op = objects; op != NULL; op = op->next)
- if (op->count == i)
- break;
- return op;
+ return 0;
}
/*
@@ -414,15 +409,14 @@
* Used only by the patch command, but not all that useful.
* Enables features like "patch food 999"
*/
-
object *
find_object_name (const char *str)
{
- const char *name = shstr::find (str);
+ shstr_cmp str_ (str);
object *op;
- for (op = objects; op != NULL; op = op->next)
- if (&op->name == name)
+ for_all_objects (op)
+ if (op->name == str_)
break;
return op;
@@ -435,102 +429,85 @@
}
/*
- * Returns the object which this object marks as being the owner.
- * A id-scheme is used to avoid pointing to objects which have been
- * freed and are now reused. If this is detected, the owner is
- * set to NULL, and NULL is returned.
- * Changed 2004-02-12 - if the player is setting at the play again
- * prompt, he is removed, and we don't want to treat him as an owner of
- * anything, so check removed flag. I don't expect that this should break
- * anything - once an object is removed, it is basically dead anyways.
+ * Sets the owner and sets the skill and exp pointers to owner's current
+ * skill and experience objects.
+ * ACTUALLY NO! investigate! TODO
*/
-
-object *
-get_owner (object *op)
+void
+object::set_owner (object *owner)
{
- if (op->owner == NULL)
- return NULL;
-
- if (!QUERY_FLAG (op->owner, FLAG_FREED) && !QUERY_FLAG (op->owner, FLAG_REMOVED) && op->owner->count == op->ownercount)
- return op->owner;
+ // allow objects which own objects
+ if (owner)
+ while (owner->owner)
+ owner = owner->owner;
- op->owner = NULL;
- op->ownercount = 0;
- return NULL;
+ this->owner = owner;
}
-void
-clear_owner (object *op)
+int
+object::slottype () const
{
- if (!op)
- return;
-
- if (op->owner && op->ownercount == op->owner->count)
- op->owner->refcount--;
-
- op->owner = NULL;
- op->ownercount = 0;
+ if (type == SKILL)
+ {
+ if (IS_COMBAT_SKILL (subtype)) return slot_combat;
+ if (IS_RANGED_SKILL (subtype)) return slot_ranged;
+ }
+ else
+ {
+ if (slot [body_combat].info) return slot_combat;
+ if (slot [body_range ].info) return slot_ranged;
+ }
+
+ return slot_none;
}
-/*
- * Sets the owner and sets the skill and exp pointers to owner's current
- * skill and experience objects.
- */
-void
-set_owner (object *op, object *owner)
+bool
+object::change_weapon (object *ob)
{
- if (owner == NULL || op == NULL)
- return;
+ if (current_weapon == ob)
+ return true;
- /* next line added to allow objects which own objects */
- /* Add a check for ownercounts in here, as I got into an endless loop
- * with the fireball owning a poison cloud which then owned the
- * fireball. I believe that was caused by one of the objects getting
- * freed and then another object replacing it. Since the ownercounts
- * didn't match, this check is valid and I believe that cause is valid.
- */
- while (owner->owner && owner != owner->owner && owner->ownercount == owner->owner->count)
- owner = owner->owner;
+ if (chosen_skill)
+ chosen_skill->flag [FLAG_APPLIED] = false;
- /* IF the owner still has an owner, we did not resolve to a final owner.
- * so lets not add to that.
- */
- if (owner->owner)
- return;
+ current_weapon = ob;
+ chosen_skill = !ob || ob->type == SKILL ? ob : find_skill_by_name (this, ob->skill);
- op->owner = owner;
+ if (chosen_skill)
+ chosen_skill->flag [FLAG_APPLIED] = true;
- op->ownercount = owner->count;
- owner->refcount++;
-}
+ update_stats ();
-/* Set the owner to clone's current owner and set the skill and experience
- * objects to clone's objects (typically those objects that where the owner's
- * current skill and experience objects at the time when clone's owner was
- * set - not the owner's current skill and experience objects).
- *
- * Use this function if player created an object (e.g. fire bullet, swarm
- * spell), and this object creates further objects whose kills should be
- * accounted for the player's original skill, even if player has changed
- * skills meanwhile.
- */
-void
-copy_owner (object *op, object *clone)
-{
- object *owner = get_owner (clone);
+ if (ob)
+ {
+ // now check wether any body locations became invalid, in which case
+ // we cannot apply the weapon at the moment.
+ for (int i = 0; i < NUM_BODY_LOCATIONS; ++i)
+ if (slot[i].used < 0)
+ {
+ current_weapon = chosen_skill = 0;
+ update_stats ();
- if (owner == NULL)
+ new_draw_info_format (NDI_UNIQUE, 0, this,
+ "You try to balance all your items at once, "
+ "but the %s is just too much for your body. "
+ "[You need to unapply some items first.]", &ob->name);
+ return false;
+ }
+
+ //new_draw_info_format (NDI_UNIQUE, 0, this, "You switch to your %s.", &ob->name);
+ }
+ else
+ ;//new_draw_info_format (NDI_UNIQUE, 0, this, "You unwield your weapons.");
+
+ if (ob && !ob->flag [FLAG_APPLIED] && ob->type != SPELL)
{
- /* players don't have owners - they own themselves. Update
- * as appropriate.
- */
- if (clone->type == PLAYER)
- owner = clone;
- else
- return;
+ LOG (llevError | logBacktrace, "%s changed to unapplied weapon %s",
+ &name, ob->debug_desc ());
+ return false;
}
- set_owner (op, owner);
+ return true;
}
/* Zero the key_values on op, decrementing the shared-string
@@ -539,7 +516,7 @@
static void
free_key_values (object *op)
{
- for (key_value *i = op->key_values; i != 0;)
+ for (key_value *i = op->key_values; i; )
{
key_value *next = i->next;
delete i;
@@ -550,105 +527,24 @@
op->key_values = 0;
}
-void object::clear ()
-{
- attachable_base::clear ();
-
- free_key_values (this);
-
- clear_owner (this);
-
- name = 0;
- name_pl = 0;
- title = 0;
- race = 0;
- slaying = 0;
- skill = 0;
- msg = 0;
- lore = 0;
- custom_name = 0;
- materialname = 0;
-
- memset (static_cast < object_pod * >(this), 0, sizeof (object_pod));
-
- SET_FLAG (this, FLAG_REMOVED);
-}
-
-void object::clone (object *destination)
-{
- *(object_copy *) destination = *this;
- *(object_pod *) destination = *this;
-
- if (self || cb)
- INVOKE_OBJECT (CLONE, this, ARG_OBJECT (destination));
-}
-
-/*
- * clear_object() frees everything allocated by an object, and also
- * clears all variables and flags to default settings.
- */
-
-void
-clear_object (object *op)
-{
- op->clear ();
-
- op->contr = NULL;
- op->below = NULL;
- op->above = NULL;
- op->inv = NULL;
- op->container = NULL;
- op->env = NULL;
- op->more = NULL;
- op->head = NULL;
- op->map = NULL;
- op->refcount = 0;
- op->active_next = NULL;
- op->active_prev = NULL;
- /* What is not cleared is next, prev, and count */
-
- op->expmul = 1.0;
- op->face = blank_face;
- op->attacked_by_count = -1;
-
- if (settings.casting_time)
- op->casting_time = -1;
-}
-
-/*
- * copy object first frees everything allocated by the second object,
- * and then copies the contends of the first object into the second
- * object, allocating what needs to be allocated. Basically, any
- * data that is malloc'd needs to be re-malloc/copied. Otherwise,
- * if the first object is freed, the pointers in the new object
- * will point at garbage.
- */
-
-void
-copy_object (object *op2, object *op)
+object &
+object::operator =(const object &src)
{
- bool is_freed = QUERY_FLAG (op, FLAG_FREED);
- bool is_removed = QUERY_FLAG (op, FLAG_REMOVED);
-
- op2->clone (op);
+ bool is_freed = flag [FLAG_FREED];
+ bool is_removed = flag [FLAG_REMOVED];
- if (is_freed)
- SET_FLAG (op, FLAG_FREED);
- if (is_removed)
- SET_FLAG (op, FLAG_REMOVED);
+ *(object_copy *)this = src;
- if (op2->speed < 0)
- op->speed_left = op2->speed_left - RANDOM () % 200 / 100.0;
+ flag [FLAG_FREED] = is_freed;
+ flag [FLAG_REMOVED] = is_removed;
/* Copy over key_values, if any. */
- if (op2->key_values)
+ if (src.key_values)
{
key_value *tail = 0;
- key_value *i;
-
- op->key_values = 0;
+ key_values = 0;
- for (i = op2->key_values; i; i = i->next)
+ for (key_value *i = src.key_values; i; i = i->next)
{
key_value *new_link = new key_value;
@@ -657,9 +553,9 @@
new_link->value = i->value;
/* Try and be clever here, too. */
- if (!op->key_values)
+ if (!key_values)
{
- op->key_values = new_link;
+ key_values = new_link;
tail = new_link;
}
else
@@ -669,8 +565,52 @@
}
}
}
+}
- update_ob_speed (op);
+/*
+ * copy_to first frees everything allocated by the dst object,
+ * and then copies the contents of itself into the second
+ * object, allocating what needs to be allocated. Basically, any
+ * data that is malloc'd needs to be re-malloc/copied. Otherwise,
+ * if the first object is freed, the pointers in the new object
+ * will point at garbage.
+ */
+void
+object::copy_to (object *dst)
+{
+ *dst = *this;
+
+ if (speed < 0)
+ dst->speed_left = speed_left - rndm ();
+
+ dst->set_speed (dst->speed);
+}
+
+void
+object::instantiate ()
+{
+ if (!uuid.seq) // HACK
+ uuid = gen_uuid ();
+
+ speed_left = -0.1f;
+ /* copy the body_info to the body_used - this is only really
+ * need for monsters, but doesn't hurt to do it for everything.
+ * by doing so, when a monster is created, it has good starting
+ * values for the body_used info, so when items are created
+ * for it, they can be properly equipped.
+ */
+ for (int i = NUM_BODY_LOCATIONS; i--; )
+ slot[i].used = slot[i].info;
+
+ attachable::instantiate ();
+}
+
+object *
+object::clone ()
+{
+ object *neu = create ();
+ copy_to (neu);
+ return neu;
}
/*
@@ -678,12 +618,12 @@
* to the closest player being on the other side, this function can
* be called to update the face variable, _and_ how it looks on the map.
*/
-
void
update_turn_face (object *op)
{
- if (!QUERY_FLAG (op, FLAG_IS_TURNABLE) || op->arch == NULL)
+ if (!QUERY_FLAG (op, FLAG_IS_TURNABLE) || !op->arch)
return;
+
SET_ANIMATION (op, op->direction);
update_object (op, UP_OBJ_FACE);
}
@@ -693,98 +633,25 @@
* value, or vice versa, then add/remove the object from the active list.
* This function needs to be called whenever the speed of an object changes.
*/
-
void
-update_ob_speed (object *op)
+object::set_speed (float speed)
{
- extern int arch_init;
-
- /* No reason putting the archetypes objects on the speed list,
- * since they never really need to be updated.
- */
-
- if (QUERY_FLAG (op, FLAG_FREED) && op->speed)
+ if (flag [FLAG_FREED] && speed)
{
- LOG (llevError, "Object %s is freed but has speed.\n", &op->name);
-#ifdef MANY_CORES
- abort ();
-#else
- op->speed = 0;
-#endif
+ LOG (llevError, "Object %s is freed but has speed.\n", &name);
+ speed = 0;
}
- if (arch_init)
- {
- return;
- }
- if (FABS (op->speed) > MIN_ACTIVE_SPEED)
- {
- /* If already on active list, don't do anything */
- if (op->active_next || op->active_prev || op == active_objects)
- return;
-
- /* process_events() expects us to insert the object at the beginning
- * of the list. */
- op->active_next = active_objects;
- if (op->active_next != NULL)
- op->active_next->active_prev = op;
- active_objects = op;
- }
- else
- {
- /* If not on the active list, nothing needs to be done */
- if (!op->active_next && !op->active_prev && op != active_objects)
- return;
- if (op->active_prev == NULL)
- {
- active_objects = op->active_next;
- if (op->active_next != NULL)
- op->active_next->active_prev = NULL;
- }
- else
- {
- op->active_prev->active_next = op->active_next;
- if (op->active_next)
- op->active_next->active_prev = op->active_prev;
- }
- op->active_next = NULL;
- op->active_prev = NULL;
- }
-}
+ this->speed = speed;
-/* This function removes object 'op' from the list of active
- * objects.
- * This should only be used for style maps or other such
- * reference maps where you don't want an object that isn't
- * in play chewing up cpu time getting processed.
- * The reverse of this is to call update_ob_speed, which
- * will do the right thing based on the speed of the object.
- */
-void
-remove_from_active_list (object *op)
-{
- /* If not on the active list, nothing needs to be done */
- if (!op->active_next && !op->active_prev && op != active_objects)
- return;
-
- if (op->active_prev == NULL)
- {
- active_objects = op->active_next;
- if (op->active_next != NULL)
- op->active_next->active_prev = NULL;
- }
+ if (has_active_speed ())
+ activate ();
else
- {
- op->active_prev->active_next = op->active_next;
- if (op->active_next)
- op->active_next->active_prev = op->active_prev;
- }
- op->active_next = NULL;
- op->active_prev = NULL;
+ deactivate ();
}
/*
- * update_object() updates the array which represents the map.
+ * update_object() updates the the map.
* It takes into account invisible objects (and represent squares covered
* by invisible objects by whatever is below them (unless it's another
* invisible object, etc...)
@@ -793,10 +660,6 @@
* updating that window, though, since update_object() is called _often_)
*
* action is a hint of what the caller believes need to be done.
- * For example, if the only thing that has changed is the face (due to
- * an animation), we don't need to call update_position until that actually
- * comes into view of a player. OTOH, many other things, like addition/removal
- * of walls or living creatures may need us to update the flags now.
* current action are:
* UP_OBJ_INSERT: op was inserted
* UP_OBJ_REMOVE: op was removed
@@ -804,13 +667,9 @@
* as that is easier than trying to look at what may have changed.
* UP_OBJ_FACE: only the objects face has changed.
*/
-
void
update_object (object *op, int action)
{
- int update_now = 0, flags;
- MoveType move_on, move_off, move_block, move_slow;
-
if (op == NULL)
{
/* this should never happen */
@@ -818,7 +677,7 @@
return;
}
- if (op->env != NULL)
+ if (op->env)
{
/* Animation is currently handled by client, so nothing
* to do in this case.
@@ -833,7 +692,7 @@
return;
/* make sure the object is within map boundaries */
- if (op->x < 0 || op->x >= MAP_WIDTH (op->map) || op->y < 0 || op->y >= MAP_HEIGHT (op->map))
+ if (op->x < 0 || op->x >= op->map->width || op->y < 0 || op->y >= op->map->height)
{
LOG (llevError, "update_object() called for object out of map!\n");
#ifdef MANY_CORES
@@ -842,467 +701,431 @@
return;
}
- flags = GET_MAP_FLAGS (op->map, op->x, op->y);
- SET_MAP_FLAGS (op->map, op->x, op->y, flags | P_NEED_UPDATE);
- move_slow = GET_MAP_MOVE_SLOW (op->map, op->x, op->y);
- move_on = GET_MAP_MOVE_ON (op->map, op->x, op->y);
- move_block = GET_MAP_MOVE_BLOCK (op->map, op->x, op->y);
- move_off = GET_MAP_MOVE_OFF (op->map, op->x, op->y);
-
- if (action == UP_OBJ_INSERT)
- {
- if (QUERY_FLAG (op, FLAG_BLOCKSVIEW) && !(flags & P_BLOCKSVIEW))
- update_now = 1;
-
- if (QUERY_FLAG (op, FLAG_NO_MAGIC) && !(flags & P_NO_MAGIC))
- update_now = 1;
-
- if (QUERY_FLAG (op, FLAG_DAMNED) && !(flags & P_NO_CLERIC))
- update_now = 1;
-
- if (QUERY_FLAG (op, FLAG_ALIVE) && !(flags & P_IS_ALIVE))
- update_now = 1;
-
- if (op->type == SAFE_GROUND && !(flags & P_SAFE))
- update_now = 1;
-
- if ((move_on | op->move_on) != move_on)
- update_now = 1;
-
- if ((move_off | op->move_off) != move_off)
- update_now = 1;
-
- /* This isn't perfect, but I don't expect a lot of objects to
- * to have move_allow right now.
- */
- if (((move_block | op->move_block) & ~op->move_allow) != move_block)
- update_now = 1;
+ mapspace &m = op->ms ();
- if ((move_slow | op->move_slow) != move_slow)
- update_now = 1;
- }
- /* if the object is being removed, we can't make intelligent
- * decisions, because remove_ob can't really pass the object
- * that is being removed.
- */
+ if (!(m.flags_ & P_UPTODATE))
+ /* nop */;
+ else if (action == UP_OBJ_INSERT)
+ {
+ // this is likely overkill, TODO: revisit (schmorp)
+ if ((QUERY_FLAG (op, FLAG_BLOCKSVIEW) && !(m.flags_ & P_BLOCKSVIEW))
+ || (QUERY_FLAG (op, FLAG_NO_MAGIC) && !(m.flags_ & P_NO_MAGIC))
+ || (op->type == PLAYER && !(m.flags_ & P_PLAYER))
+ || (op->type == SAFE_GROUND && !(m.flags_ & P_SAFE))
+ || (QUERY_FLAG (op, FLAG_ALIVE) && !(m.flags_ & P_IS_ALIVE))
+ || (QUERY_FLAG (op, FLAG_DAMNED) && !(m.flags_ & P_NO_CLERIC))
+ || (m.move_on | op->move_on ) != m.move_on
+ || (m.move_off | op->move_off ) != m.move_off
+ || (m.move_slow | op->move_slow) != m.move_slow
+ /* This isn't perfect, but I don't expect a lot of objects to
+ * to have move_allow right now.
+ */
+ || ((m.move_block | op->move_block) & ~op->move_allow) != m.move_block
+ || 1) // the above is not strong enough a test to skip updating. los maybe? TODO (Schmorp)
+ m.flags_ = 0;
+ }
+ /* if the object is being removed, we can't make intelligent
+ * decisions, because remove_ob can't really pass the object
+ * that is being removed.
+ */
else if (action == UP_OBJ_CHANGE || action == UP_OBJ_REMOVE)
- update_now = 1;
+ m.flags_ = 0;
else if (action == UP_OBJ_FACE)
- /* Nothing to do for that case */;
+ /* Nothing to do for that case */ ;
else
LOG (llevError, "update_object called with invalid action: %d\n", action);
- if (update_now)
- {
- SET_MAP_FLAGS (op->map, op->x, op->y, flags | P_NO_ERROR | P_NEED_UPDATE);
- update_position (op->map, op->x, op->y);
- }
-
- if (op->more != NULL)
+ if (op->more)
update_object (op->more, action);
}
-static unordered_vector