Crossfire Archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

CF: patch: merging items



Hi,

this patch attempts to merge most items where merging makes sense.
It is "preliminary" --- I'd like to change things to merge everything
by default, but I'm not sure whether this would affect other things
(like 2 monsters on the same field suddenly turning into "2 zombies" -:)).

You also need gcc to compile --- things basically work as follows:
- CAN_MERGE checks almost everything
- if nrof is 0, MakeMergeable() checks an array to see if the object
  should be merged (based on type). If yes, nrof is set to 1.
  This step needs gcc to initialize the array, but it should be easy to
  modify to work on any compiler. I'm just too lazy right now -:(
  I suppose I could even use if()s to check the type.

Some things have changed, too: since spellbooks are now merged, reading
a spellbook will identify the other spellbooks in the same "object slot"
(just like it works for scrolls).
There is a chance that this patch fixes the "disappearing rings" problem,
too --- but I don't know.

Also, sometimes two seemingly mergeable objects are not merged. I assume
that the FLAG_BEEN_APPLIED causes this. I left it in, because I have no
idea what the flag is good for.

I left the "ignore the INV_LOCK" flag thing in CAN_MERGE(), although
I'll probably remove it from my server. It's just too annoying -:(

The patch will, of course, reduce the appartment effect a little.

Christian

------------------------------ Cut ------------------------------

diff -C 5 -r crossfire-0.93.7/common/object.c crossfire/common/object.c
*** crossfire-0.93.7/common/object.c	Tue Jan  6 10:29:18 1998
--- crossfire/common/object.c	Wed Jan 14 19:21:49 1998
***************
*** 75,84 ****
--- 75,86 ----
   *
   * Improvements made with merge:  Better checking on potion, and also
   * check weight
   */
  
+ #define COMPARE_LIVING(Attr) || (ob1->stats.Attr!=ob2->stats.Attr)
+ #define COMPARE_OBJ(Attr) || (ob1->Attr!=ob2->Attr)
  
  INLINE int CAN_MERGE(object *ob1, object *ob2) {
  
      /* A couple quicksanity checks */
      if ((ob1 == ob2) || (ob1->type != ob2->type)) return 0;
***************
*** 91,121 ****
      if (!QUERY_FLAG(ob1,FLAG_ANIMATE) && FABS((ob1)->speed) > 0.001 ) return 0;
  
      /* the 0x400000 on flags2 is FLAG_INV_LOCK.  I don't think something
       * being locked in inventory should prevent merging.
       */
!     if ((ob1->arch != ob2->arch) || (ob1->stats.sp != ob2->stats.sp) ||
! 	(ob1->flags[0] != ob2->flags[0]) || (ob1->flags[1] != ob2->flags[1]) ||
! 	((ob1->flags[2] & ~0x400000) != (ob2->flags[2] & ~ 0x400000)) ||
! 	(ob1->flags[3] != ob2->flags[3]) || (ob1->magic != ob2->magic) ||
! 	(ob1->name != ob2->name) || (ob1->title != ob2->title) ||
! 	(ob1->msg != ob2->msg) || (ob1->stats.food != ob2->stats.food) ||
! 	(ob1->protected != ob2->protected) || (ob1->immune != ob2->immune) ||
! 	(ob1->vulnerable != ob2->vulnerable) || (ob1->weight != ob2->weight))
  	    return 0;
  
      switch (ob1->type) {
  	case SCROLL:
  	    if (ob1->level != ob2->level) return 0;
  	    break;
! 	case POTION:
! 	    /* This should compare the value of the stats, and not the pointer
! 	     * itself.  There can be cases were potions seem to loose their
! 	     * plus
! 	     */
! 	    if (memcmp(&ob1->stats,&ob2->stats, sizeof(living))) return 0;
! 	    break;
      }
      /* Everything passes, must be OK. */
      return 1;
  }
  
--- 93,171 ----
      if (!QUERY_FLAG(ob1,FLAG_ANIMATE) && FABS((ob1)->speed) > 0.001 ) return 0;
  
      /* the 0x400000 on flags2 is FLAG_INV_LOCK.  I don't think something
       * being locked in inventory should prevent merging.
       */
!      if (0
!  	COMPARE_OBJ(arch)
!  
!  	COMPARE_OBJ(flags[0])
!  	COMPARE_OBJ(flags[1])
!  	COMPARE_OBJ(flags[2] & ~0x400000)
!  	COMPARE_OBJ(flags[3])
!  
!  	|| QUERY_FLAG(ob1,FLAG_APPLIED)
!  
!  	COMPARE_OBJ(name)
!  	COMPARE_OBJ(title)
!  	COMPARE_OBJ(real_name)
!  	COMPARE_OBJ(real_title)
!  
!  	COMPARE_OBJ(msg)
!  	COMPARE_OBJ(weight)
!  	COMPARE_OBJ(magic)
!  
!  	COMPARE_OBJ(armour)
!  
!  	COMPARE_OBJ(vulnerable)
!  	COMPARE_OBJ(protected)
!  	COMPARE_OBJ(immune)
!  
!  	COMPARE_OBJ(attacktype)
!  
!  	COMPARE_OBJ(path_repelled)
!  	COMPARE_OBJ(path_attuned)
!  	COMPARE_OBJ(path_denied)
!  
!  	COMPARE_OBJ(slaying)
!  
!  	COMPARE_OBJ(material)
!  	/* COMPARE_OBJ(value) */ /* don't think this is needed */
!  	COMPARE_OBJ(level)
!  
!  	COMPARE_LIVING(food)
!  
!  	COMPARE_LIVING(Str)
!  	COMPARE_LIVING(Dex)
!  	COMPARE_LIVING(Con)
!  	COMPARE_LIVING(Wis)
!  	COMPARE_LIVING(Cha)
!  	COMPARE_LIVING(Int)
!  	COMPARE_LIVING(Pow)
!  
!  	COMPARE_LIVING(wc)
!  	COMPARE_LIVING(ac)
!  
!  	COMPARE_LIVING(dam)
!  	COMPARE_LIVING(luck)
!  
!  	COMPARE_LIVING(hp)
!  	COMPARE_LIVING(sp)
!  	COMPARE_LIVING(maxhp)
!  	COMPARE_LIVING(maxsp)
!  
!  	COMPARE_LIVING(exp)
!  	COMPARE_LIVING(grace)
!   	)
  	    return 0;
  
      switch (ob1->type) {
+ #if 0
  	case SCROLL:
  	    if (ob1->level != ob2->level) return 0;
  	    break;
! #endif
      }
      /* Everything passes, must be OK. */
      return 1;
  }
  
***************
*** 1084,1093 ****
--- 1134,1168 ----
    ) 
      update_all_los(op->map);	/* first_player is no longer set there */
  
  }
  
+ static object *MakeMergeable(object *ob)
+ {
+   static char Mergeable[500]={[WEAPON] 1,
+ 			      [ARMOUR] 1,
+ 			      [SHIELD] 1,
+ 			      [HELMET] 1,
+ 			      [FLESH] 1,
+ 			      [CLOAK] 1,
+ 			      [BOOK] 1,
+ 			      [BOOTS] 1,
+ 			      [GLOVES] 1,
+ 			      [BRACERS] 1,
+ 			      [GIRDLE] 1,
+ 			      [RING] 1,
+ 			      [AMULET] 1,
+ 			      [SKILL] 1,
+ 			      [SPELLBOOK] 1};
+ 
+   if (ob!=NULL && ob->nrof==0 && Mergeable[ob->type])
+     {
+       ob->nrof=1;
+     }
+   return ob;
+ }
+ 
  /*
   * merge_ob(op,top):
   *
   * This function goes through all objects below and including top, and
   * merges op to the first matching object.
***************
*** 1094,1110 ****
   * If top is NULL, it is calculated.
   * Returns pointer to object if it succeded in the merge, otherwise NULL
   */
  
  object *merge_ob(object *op, object *top) {
!   if(!op->nrof)
!     return 0;
    if(top==NULL)
      for(top=op;top!=NULL&&top->above!=NULL;top=top->above);
    for(;top!=NULL;top=top->below) {
      if(top==op)
        continue;
      if (CAN_MERGE(op,top))
      {
        top->nrof+=op->nrof;
        CLEAR_FLAG(top,FLAG_STARTEQUIP);
        op->weight = 0; /* Don't want any adjustements now */
--- 1169,1191 ----
   * If top is NULL, it is calculated.
   * Returns pointer to object if it succeded in the merge, otherwise NULL
   */
  
  object *merge_ob(object *op, object *top) {
!   if (MakeMergeable(op)->nrof==0)
!     {
!       return 0;
!     }
    if(top==NULL)
      for(top=op;top!=NULL&&top->above!=NULL;top=top->above);
    for(;top!=NULL;top=top->below) {
      if(top==op)
        continue;
+     if (MakeMergeable(top)->nrof==0)
+       {
+ 	continue;
+       }
      if (CAN_MERGE(op,top))
      {
        top->nrof+=op->nrof;
        CLEAR_FLAG(top,FLAG_STARTEQUIP);
        op->weight = 0; /* Don't want any adjustements now */
***************
*** 1274,1284 ****
    }
    if(op->more!=NULL) {
      insert_ob_in_map(op->more,m);
    }
    CLEAR_FLAG(op,FLAG_REMOVED);
!   if(op->nrof)
      for(tmp=get_map_ob(m,op->x,op->y);tmp!=NULL;tmp=tmp->above)
        if (CAN_MERGE(op,tmp))
        {
          op->nrof+=tmp->nrof;
          CLEAR_FLAG(op,FLAG_STARTEQUIP);
--- 1355,1365 ----
    }
    if(op->more!=NULL) {
      insert_ob_in_map(op->more,m);
    }
    CLEAR_FLAG(op,FLAG_REMOVED);
!   if(MakeMergeable(op)->nrof)
      for(tmp=get_map_ob(m,op->x,op->y);tmp!=NULL;tmp=tmp->above)
        if (CAN_MERGE(op,tmp))
        {
          op->nrof+=tmp->nrof;
          CLEAR_FLAG(op,FLAG_STARTEQUIP);
***************
*** 1573,1583 ****
      LOG(llevError, "Tried to insert multipart object %s (%d)\n",
          op->name, op->count);
      return op;
    }
    CLEAR_FLAG(op, FLAG_REMOVED);
!   if(op->nrof) {
      for(tmp=where->inv;tmp!=NULL;tmp=tmp->below)
        if ( CAN_MERGE(tmp,op) ) {
  	/* return the original object and remove inserted object
             (client needs the original object) */
          tmp->nrof += op->nrof;
--- 1654,1664 ----
      LOG(llevError, "Tried to insert multipart object %s (%d)\n",
          op->name, op->count);
      return op;
    }
    CLEAR_FLAG(op, FLAG_REMOVED);
!   if(MakeMergeable(op)->nrof) {
      for(tmp=where->inv;tmp!=NULL;tmp=tmp->below)
        if ( CAN_MERGE(tmp,op) ) {
  	/* return the original object and remove inserted object
             (client needs the original object) */
          tmp->nrof += op->nrof;
diff -C 5 -r crossfire-0.93.7/server/apply.c crossfire/server/apply.c
*** crossfire-0.93.7/server/apply.c	Tue Jan  6 10:29:23 1998
--- crossfire/server/apply.c	Wed Jan 14 19:21:50 1998
***************
*** 1562,1583 ****
  
      new_draw_info_format(NDI_UNIQUE, 0, op, 
  	"The spellbook contains the %s level spell %s.",
              get_levelnumber(spells[tmp->stats.sp].level),
              spells[tmp->stats.sp].name);
      if(check_spell_known(op,tmp->stats.sp)) {
        new_draw_info(NDI_UNIQUE, 0,op,"You already know that spell.\n");
- 
-       if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED)) {
- 	identify(tmp);
- 	if (op->contr->eric_server > 0)
- 	  esrv_send_item(op, tmp);
- 	else if (tmp->env)
- 	  draw_inventory(op);
- 	else
- 	  draw_look(op);
-       }
        return 1;
      }
      /* I changed spell learning in 3 ways:
       *
       *  1- MU spells use Int to learn, Cleric spells use Wisdom
--- 1562,1582 ----
  
      new_draw_info_format(NDI_UNIQUE, 0, op, 
  	"The spellbook contains the %s level spell %s.",
              get_levelnumber(spells[tmp->stats.sp].level),
              spells[tmp->stats.sp].name);
+     if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED)) {
+       identify(tmp);
+       if (op->contr->eric_server > 0)
+ 	esrv_send_item(op, tmp);
+       else if (tmp->env)
+ 	draw_inventory(op);
+       else
+ 	draw_look(op);
+     }
      if(check_spell_known(op,tmp->stats.sp)) {
        new_draw_info(NDI_UNIQUE, 0,op,"You already know that spell.\n");
        return 1;
      }
      /* I changed spell learning in 3 ways:
       *
       *  1- MU spells use Int to learn, Cleric spells use Wisdom
***************
*** 1612,1623 ****
  #ifdef SOUND_EFFECTS
        play_sound_player_only(op->contr, SOUND_FUMBLE_SPELL);
  #endif
        new_draw_info(NDI_UNIQUE, 0,op,"You fail to learn the spell.\n");
      }
!     remove_ob(tmp);
!     free_object(tmp);
      return 1;
    case SCROLL: {
        int scroll_spell=tmp->stats.sp, old_spell=0;
        rangetype old_shoot=range_none;
  
--- 1611,1621 ----
  #ifdef SOUND_EFFECTS
        play_sound_player_only(op->contr, SOUND_FUMBLE_SPELL);
  #endif
        new_draw_info(NDI_UNIQUE, 0,op,"You fail to learn the spell.\n");
      }
!     decrease_ob(tmp);
      return 1;
    case SCROLL: {
        int scroll_spell=tmp->stats.sp, old_spell=0;
        rangetype old_shoot=range_none;
  
[to unsubscribe etc., send mail to crossfire-request@ifi.uio.no]