Monster inventories

New ideas, features you wish were in the game.
Post Reply
PowerWyrm
Balrog
Posts: 1574
Joined: Sun 27.11.2005, 15:57

Monster inventories

Post by PowerWyrm » Wed 27.02.2008, 19:13

Angband 3.0.x has monster inventories, so that TAKE_ITEM monsters drop all the items they picked up when killed... very cool.
It took me an afternoon only to implement that in PWMAngband... would be nice to have that for Mang 1.0 too.

User avatar
Flambard
King Vampire
Posts: 259
Joined: Wed 20.06.2007, 10:49

Post by Flambard » Mon 03.03.2008, 23:09

Hey PW, have you encountered a bug when monsters drop "(nothing)" while implementing this feature?

PowerWyrm
Balrog
Posts: 1574
Joined: Sun 27.11.2005, 15:57

Post by PowerWyrm » Tue 04.03.2008, 12:13

Not yet... maybe I implemented it right :wink:

PowerWyrm
Balrog
Posts: 1574
Joined: Sun 27.11.2005, 15:57

Post by PowerWyrm » Tue 04.03.2008, 15:45

I just checked the implementation you added for MAng. There are parts of code missing...

load2.c
--------

Code: Select all

static void rd_item(object_type *o_ptr)
{
    ...

    /* Save the inscription */
    if (note[0]) o_ptr->note = quark_add(note);

    /* Monster holding object */
    o_ptr->held_m_idx = read_int("held_m_idx");

    end_section_read("item");

    ...
}
melee1.c
----------

Code: Select all

bool make_attack_normal(int Ind, int m_idx)
{
    ...
    case RBE_EAT_ITEM:
    ...

                    /* Find an item */
                    for (k = 0; k < 10; k++)
                    {
                        object_type *i_ptr;
						object_type object_type_body;

                        /* Pick an item */
                        i = rand_int(INVEN_PACK);

                        /* Obtain the item */
                        o_ptr = &p_ptr->inventory[i];

                        /* Accept real items */
                        if (!o_ptr->k_idx) continue;

                        /* Don't steal artifacts  -CFT */
                        if (artifact_p(o_ptr)) continue;

                        /* Get a description */
                        object_desc(Ind, o_name, o_ptr, FALSE, 3);

                        /* Message */
                        msg_format(Ind, "%sour %s (%c) was stolen!",
                                   ((o_ptr->number > 1) ? "One of y" : "Y"),
                                   o_name, index_to_label(i));

                        /* Get local object */
						i_ptr = &object_type_body;

						/* Obtain local object */
						object_copy(i_ptr, o_ptr);

						/* Modify number */
						i_ptr->number = 1;

						/* Carry the object */
						monster_carry(Ind, m_idx, i_ptr);

                        /* Steal the items */
                        inven_item_increase(Ind, i, -1);
                        inven_item_optimize(Ind, i);

                        /* Obvious */
                        obvious = TRUE;

                        /* Blink away */
                        blinked = 2;

                        /* Done */
                        break;
                    }
    ...
}
monster2.c
-------------

here I'm gonna post the whole beginning of this file, since the deleteXXX and compactXXX functions have been greatly impacted

Code: Select all

#include "angband.h"


/*
 * Excise a dungeon object from any stacks
 */
static void excise_object_idx(int o_idx)
{
	object_type *j_ptr;
	s16b this_o_idx, next_o_idx = 0;
	s16b prev_o_idx = 0;

	/* Object */
	j_ptr = &o_list[o_idx];

	/* Monster */
	if (j_ptr->held_m_idx)
	{
		monster_type *m_ptr;

		/* Monster */
		m_ptr = &m_list[j_ptr->held_m_idx];

		/* Scan all objects in the grid */
		for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx)
		{
			object_type *o_ptr;

			/* Get the object */
			o_ptr = &o_list[this_o_idx];

			/* Get the next object */
			next_o_idx = o_ptr->next_o_idx;

			/* Done */
			if (this_o_idx == o_idx)
			{
				/* No previous */
				if (prev_o_idx == 0)
				{
					/* Remove from list */
					m_ptr->hold_o_idx = next_o_idx;
				}

				/* Real previous */
				else
				{
					object_type *i_ptr;

					/* Previous object */
					i_ptr = &o_list[prev_o_idx];

					/* Remove from list */
					i_ptr->next_o_idx = next_o_idx;
				}

				/* Forget next pointer */
				o_ptr->next_o_idx = 0;

				/* Done */
				break;
			}

			/* Save prev_o_idx */
			prev_o_idx = this_o_idx;
		}
	}

	/* Dungeon */
	else
	{
		int y = j_ptr->iy;
		int x = j_ptr->ix;
        int Depth = j_ptr->dun_depth;
        cave_type *c_ptr = &cave[Depth][y][x];
        int i;

        /* Object is gone */
        c_ptr->o_idx = 0;

        /* No one can see it anymore */
        for (i = 1; i < NumPlayers + 1; i++)
            Players[i]->obj_vis[c_ptr->o_idx] = FALSE;
	}
} 


static void object_wipe(object_type* o_ptr)
{
    /* Wipe the object */
    WIPE(o_ptr, object_type);
}


/*
 * Delete a dungeon object
 */
void delete_object_idx(int o_idx)
{
    object_type *j_ptr;

	/* Excise */
	excise_object_idx(o_idx);

	/* Object */
	j_ptr = &o_list[o_idx];

	/* Dungeon floor */
	if (!j_ptr->held_m_idx)
	{
		int y, x, Depth;

		/* Location */
		y = j_ptr->iy;
		x = j_ptr->ix;
        Depth = j_ptr->dun_depth;

		/* Visual update */
		everyone_lite_spot(Depth, y, x);
	}

	/* Wipe the object */
	object_wipe(j_ptr);
}


/*
 * Deletes object from given location
 */
void delete_object(int Depth, int y, int x)
{
    cave_type *c_ptr;

    /* Paranoia */
    if (!in_bounds(Depth, y, x)) return;

    /* Paranoia -- make sure the level has been allocated */
    if (!cave[Depth])
    {
        printf("Error : tried to delete object on unallocated level %d\n",Depth);
        return;
    }

    /* Find where it was */
    c_ptr = &cave[Depth][y][x];

    /* Delete the object */
    if (c_ptr->o_idx) delete_object_idx(c_ptr->o_idx);
}


/*
 * Move an object from index i1 to index i2 in the object list
 */
static void compact_objects_aux(int i1, int i2)
{
	int i, Ind;
	object_type *o_ptr;

	/* Do nothing */
	if (i1 == i2) return;

	/* Repair objects */
	for (i = 1; i < o_max; i++)
	{
		/* Get the object */
		o_ptr = &o_list[i];

		/* Skip "dead" objects */
		if (!o_ptr->k_idx) continue;

		/* Repair "next" pointers */
		if (o_ptr->next_o_idx == i1)
		{
			/* Repair */
			o_ptr->next_o_idx = i2;
		}
	}

	/* Get the object */
	o_ptr = &o_list[i1];

	/* Monster */
	if (o_ptr->held_m_idx)
	{
		monster_type *m_ptr;

		/* Get the monster */
		m_ptr = &m_list[o_ptr->held_m_idx];

		/* Repair monster */
		if (m_ptr->hold_o_idx == i1)
		{
			/* Repair */
			m_ptr->hold_o_idx = i2;
		}
	}

	/* Dungeon */
	else
	{
		int y, x, Depth;

		/* Get location */
		y = o_ptr->iy;
		x = o_ptr->ix;
        Depth = o_ptr->dun_depth;

		/* Repair grid */
        if (cave[Depth] && (cave[Depth][y][x].o_idx == i1))
		{
			/* Repair */
			cave[Depth][y][x].o_idx = i2;
		}
	}

    /* Copy the visibility flags for each player */
    for (Ind = 1; Ind < NumPlayers + 1; Ind++)
        Players[Ind]->obj_vis[i2] = Players[Ind]->obj_vis[i1];

	/* Hack -- move object */
	COPY(&o_list[i2], &o_list[i1], object_type);

	/* Hack -- wipe hole */
	object_wipe(o_ptr);
}


/*
 * Compact and reorder the object list
 *
 * This function can be very dangerous, use with caution!
 *
 * When compacting objects, we first destroy gold, on the basis that by the
 * time item compaction becomes an issue, the player really won't care.
 * We also nuke items marked as squelch.
 *
 * When compacting other objects, we base the saving throw on a combination of
 * object level, distance from player, and current "desperation".
 *
 * After compacting, we "reorder" the objects into a more compact order, and we
 * reset the allocation info, and the "live" array.
 */
void compact_objects(int size)
{
    int i, y, x, cnt;
	int cur_lev, cur_val, chance;

	/* Reorder objects when not passed a size */
	if (!size)
	{
		/* Excise dead objects (backwards!) */
		for (i = o_max - 1; i >= 1; i--)
		{
			object_type *o_ptr = &o_list[i];

			/* Skip real objects */
			if (o_ptr->k_idx) continue;

			/* Move last object into open hole */
			compact_objects_aux(o_max - 1, i);

			/* Compress "o_max" */
			o_max--;
		}

        /* Reset "o_nxt" */
        o_nxt = o_max;

        /* Reset "o_top" */
        o_top = 0;

        /* Collect "live" objects */
        for (i = 0; i < o_max; i++)
        {
            /* Collect indexes */
            o_fast[o_top++] = i;
        }

		return;
	}

	/* Message */
	s_printf("Compacting objects...\n");

	/*** Try destroying objects ***/

	/* First do gold */
	for (i = 1; (i < o_max) && (size); i++)
	{
		object_type *o_ptr = &o_list[i];

		/* Nuke gold */
		if (o_ptr->tval == TV_GOLD)
		{
			delete_object_idx(i);
			size--;
		}
	}

	/* Compact at least 'size' objects */
	for (cnt = 1; size; cnt++)
	{
		/* Get more vicious each iteration */
		cur_lev = 5 * cnt;

		/* Destroy more valuable items each iteration */
		cur_val = 500 * (cnt - 1);

		/* Examine the objects */
		for (i = 1; (i < o_max) && (size); i++)
		{
			object_type *o_ptr = &o_list[i];
			object_kind *k_ptr = &k_info[o_ptr->k_idx];

			/* Skip dead objects */
			if (!o_ptr->k_idx) continue;

			/* Hack -- High level objects start out "immune" */
			if (k_ptr->level > cur_lev) continue;

            /* Valuable objects start out "immune" */
            if (object_value(0, o_ptr) > cur_val) continue;

			/* Saving throw */
			chance = 90;

			/* Monster */
			if (o_ptr->held_m_idx)
			{
				monster_type *m_ptr;

				/* Get the monster */
				m_ptr = &m_list[o_ptr->held_m_idx];

				/* Monsters protect their objects */
				if (magik(90)) continue;
			}

			/* Dungeon */
			else
			{
				/* Get the location */
				y = o_ptr->iy;
				x = o_ptr->ix;

                /* Hack -- only compact items in houses in emergencies */
                if (!o_ptr->dun_depth && (cave[0][y][x].info & CAVE_ICKY))
                {
                    /* Grant immunity except in emergencies */
                    if (cnt < 1000) chance = 100;
                }
			}

			/* Hack -- only compact artifacts in emergencies */
			if (artifact_p(o_ptr) && (cnt < 1000)) chance = 100;

			/* Apply the saving throw */
			if (magik(chance)) continue;

			/* Delete the object */
			delete_object_idx(i);
			size--;
		}
	}

	/* Reorder objects */
	compact_objects(0);
}
and this is missing in inven_carry()

Code: Select all

    /* Structure copy to insert the new item */
    p_ptr->inventory[i] = (*o_ptr);

    /* Get the new object */
    j_ptr = &p_ptr->inventory[i];

    /* Forget monster */
    j_ptr->held_m_idx = 0;

    /* Forget location */
    j_ptr->iy = j_ptr->ix = j_ptr->dun_depth = 0;
save.c
-------

Code: Select all

static void wr_item(object_type *o_ptr)
{
    ...

    /* Held by monster index */
    write_int("held_m_idx", o_ptr->held_m_idx);

    end_section("item");
    ...
}
This could explain the (nothing)s you get...

User avatar
Flambard
King Vampire
Posts: 259
Joined: Wed 20.06.2007, 10:49

Post by Flambard » Tue 04.03.2008, 15:47

lol, ok, thank you :) seems like I missed alot, thanks for pointing that out

Post Reply