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

Destruction





Hi again..

I asked about the problem with destruction a couple of days ago.
Now I've found it now + some other bugs. BTW. I'm useing Crossfire
version 0.91.4 + (my own patches :) on site zeem.dtek.chalmers.se
(129.16.30.12)

I don't know how I should tell you what my changes are, but I could
start with posting some changes here...

I have tried to make crossfire more balanced and remove every cheat
bugs and all other major crash bugs. 
One of the major problem is that you could double all things. I don't
know if it's a good idea to save the player every time he drops a thing
or if it's good to not allow one player have many chars in game at the
same time. Some player have more than one account, and it would take
much time to save the player. I'm running on a slow disk partition
so it would not be a good solution.
Any good solutions out there ?

I have rather decided to make a server which not crash under any
circumstances... :)

I could type the worst bugs here... Prepare for a long list.
There are many strange constructions in the source. How could
the auther make things like this...

int hit_player(object *op,int dam, object *hitter, int type) {
  ....
  dam = 50;
  type = 234;
  ....
}

There could be many side-effects with such coding.
I've changed some functions which look like that. But there are many
dangerous functions left...


I hope some of these changes could be included in next version.
Some of them could be discussed if they should be done, but some
of them solve some problems.


I think Crossfire should be concentrated on players around level 6-15.
The quest system should be more develeped so a player could get a reward
once, and had to make a more intelligent search for the clues.
It's not very good if it's only to type "say coffer", "say king" and
so on...  Don't spend so much time on making mega spells for those
level 60-90 players...

There should be a maximum magic on weapons... How fun is it when a player
has a Taifu +40 with str+8 con+9 dex+6 int+10 and it gives you ac-40,
str 30, dex 30, con 30, int 30 and so on...

Shouldn't it be fair to set maximum +2 on a stat binded to a weapon.
Who cares if the player is a barbarian or wizard. Both of them have
the possibility to get 30 in all stats...  There should be some
other maximum values.


I hope we could have a dicussion how to make Crossfire better balanced
for medium level players..


BTW. I have made some changes in the maps. There are one store in
where you can polymorph a dragon shield/mail (unpaid) to another
artifact. I've set this shop (ground) to no_spell to avoid cheat.
The map is /mcz/Navar_city/city1smith.

There are two wizards on map /city/taverns/goths. It is an easy level 0
map which should be used to get information about some quests, but
the "Wizard with an aura of great power" is strange...  He has no weapons,
no spells, he's placed on a easy map, he has 1000000 exp, he is level 49,
and when you attack him the server crashes. There seem to be a major
fault with "arch wizard" so I changed it to "arch dwarf" with "exp 1000"
temporary to avoid the server crash and unfair exp points. 
He could be killed if you attack him with magic bullet or something else,
and he would give you  add_exp(player, 500000);
Please change that in the map!!



OK... Here I post the major changes I've made on my site. I hope you
understand what my changes are, otherwise you could wait until the
next version is released with my changes... :)

/Mag

------------------------------------------------

attack.c

/* d1mag Don't change a inparameter called be value!! */
int hit_player(object *op,int indam, object *hitter, int intype) {
  char buf[MAX_BUF];
  int dam = indam;
  int type = intype;

....

  if(op->type==DOOR && op->inv && op->inv->type==RUNE) spring_trap(op->inv,hitter);

....

    if(hitter!=op&&!QUERY_FLAG(op, FLAG_WAS_WIZ)) {
      int exp=op->stats.exp;
      if(hitter->level > op->level) {
/* d1mag patch  not division by zero */
        exp = (exp*(op->level+1))/( (hitter->level>0 ? (hitter->level+1) : 1));
      }
#ifdef SIMPLE_PARTY_SYSTEM
      exp=exp/2;
      if(exp>50000) {
	fprintf(logfile, "Kill: [%s] killed [%s] Exp: %d ??\n",hitter->name, op->name, exp);
      }

....

}

------------------------------------------------

spell_util.c

/* d1mag patch inop */
int cast_spell(object *inop,object *caster,int dir,int type,int ability,SpellTypeFrom item,char *stringarg) {
  spell *s=find_spell(type);
  int success=0,bonus;
  int duration=SP_PARAMETERS[type].bdur;  /*  get the base duration */
  object casting_object;
/* d1mag patch puhhhhhh.... ??? */
  object *op = inop;

  if(item!=spellNormal&&caster!=op) {
	reset_object(&casting_object);
	(void) memcpy((void *)((char *) &casting_object +
		offsetof(object,name)),
                (void *)((char *) op+offsetof(object,name)),
                sizeof(object)-offsetof(object, name));

.....

  case SP_DESTRUCTION:
/* d1mag patch for destruction, this will make scrolls be as powerful
   as the player are.
*/
    success = cast_destruction(inop,5+inop->stats.Int,AT_MAGIC);
    break;

.....

}


------------------------------------------------

apply.c

int apply(object *op, object *tmp) {

.....

  case SCROLL: {
      int old_shoot=0, old_spell=0;

    if(QUERY_FLAG(tmp, FLAG_UNPAID)) {
      draw_info(op,"You should pay for it first.");
      break;
    }
    if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED))
      identify(tmp);
    if( tmp->stats.sp < 0 || tmp->stats.sp >= NROFREALSPELLS) {
	sprintf(buf, "The scroll just doesn't make sense!");
	break;
    }
    sprintf(buf, "The scroll of %s turns to dust.", spells[tmp->stats.sp].name);
    draw_info(op,buf);
    sprintf(buf,"%s reads a scroll of %s.",op->name,spells[tmp->stats.sp].name);
    info_all(buf,6);
/* d1mag patch descrease was here before.... */
    if(op->type==PLAYER) {
      old_shoot= op->contr->shoottype;
      old_spell = op->contr->chosen_spell;
      op->contr->shoottype=range_scroll;
      op->contr->chosen_spell = tmp->stats.sp;
    }
    cast_spell(op,tmp,0,tmp->stats.sp,0,spellScroll,NULL);
    if(op->type==PLAYER) {
      if(op->contr->golem==NULL) {
        op->contr->shoottype=old_shoot;
	op->contr->chosen_spell = old_spell;
      }
      draw_stats(op);
    }
/* d1mag patch descrease nrof scrolls after usage */
    decrease_ob(tmp);
    break;
  }

.....

}

------------------------------------------------

living.c

/* d1mag don't change inparameter */
void add_exp(object *op,int inexp) {
  char buf[MAX_BUF];
  int exp = inexp;

.....

  /* d1mag patch */
  op->stats.exp += (signed long)exp;

.....

}


------------------------------------------------

spell_effect.c

void polymorph(object *op, object *who) {

....

/* polymorph decreadsed to 10% success  d1mag */
  if((RANDOM()%10)) {
    sprintf(buf,"%s%s glows red, melts and evaporates!",
            op->nrof?"":"The ",query_name(op));

....

  }
  polymorph_item(op);
}

......

/* d1mag don't change inparameter... */
int cast_destruction(object *op, int indam, int attacktype) {
  int dam = indam;

...

}

------------------------------------------------

c_chat.c

int command_say (object *op, char *params)
{
  char buf[MAX_BUF];
/* d1mag patch, crash if say was called without argment */
  if(!params) return 0;
  sprintf(buf, "%s says %s",op->name, params);
  info_map_color (op->map, buf, 1);
  communicate(op, params);
  
  return 0;
}

------------------------------------------------

c_party.c

int command_gsay(object *op, char *params)
{
  char party_params[MAX_BUF];
  strcpy(party_params, "say "); 
/* d1mag added to secure... params is NULL when input is 'gsay' only */
  if(!params) return 0;
  strcat(party_params,params);
  command_party(op,party_params);
  return 0;
}

------------------------------------------------

commands.c

On our system there seem to be a bug with XKeysymToString function.
If key number 22 or 99 was pressed, the function crashed the server.
Number 99 was the key "5" on the keypad, so I had to map that to
a period instead. There might be more keys which not are allowed.
We are running crossfire under Solaris 2.3 (SparcStation 5)

void insert_key_complex(player *p, KeySym ks2, KeyCode keycode2, int flags, char* line)
{
  int ix, len;
  char *cp;
  Key_s *newkey =(Key_s *)malloc(sizeof(Key_s));
  KeySym ks;
  KeyCode keycode;

  /* d1mag Patch to remove key number 5 */
  if(keycode2==99 || keycode2==22) {
    keycode = 115;
    ks = XStringToKeysym("period");
  } else {
    keycode = keycode2;
    ks = XStringToKeysym(XKeysymToString(ks2));
  }

.....

}


void configure_keys(object *op, KeyCode k2, KeySym keysym2)
{
  int flags;
  char buf[MAX_BUF], *cp;
  KeySym keysym;
  KeyCode k;

  /* d1mag Patch to remove key number 5 */
  if(k2==99 || k2==22) {
    k = 115;
    keysym = XStringToKeysym("period");
  } else {
    k = k2;
    keysym = XStringToKeysym(XKeysymToString(keysym2));
  }

....

}


------------------------------------------------

player.c

To avoid a "window kill" crashes the server I've made some changes here.
A corpse is placed there and the player is saved!


int mag_linkdead(object *op);


void handle_player(object *op) {

.....

    case ClientMessage:
      cmev = (XClientMessageEvent *) & op->contr->gevent;
      if (cmev->message_type == Protocol_atom && cmev->data.l[0] == Kill_atom) {
        LOG(llevDebug,"Got WM_DELETE_WINDOW from %s.\n",op->name);
        if (op->map->in_memory == MAP_IN_MEMORY)
        {
          if (!QUERY_FLAG(op,FLAG_REMOVED)) {
		op->map->players--;
		remove_ob(op);
	  }
        }
        strcpy(op->contr->killer, "lost connection");
	mag_linkdead(op);       /* added by d1mag */
				/* make a corpse at the escape place */
        op->contr->state = 1;
        op->direction = 0;
        op->contr->count_left = 0;
        sprintf(buf, "%s lost connection.", op->name);
        info_all(buf, 5);
        check_score(op);
        (void) save_player(op, 0);
        remove_lock(op->contr);
        info_flush();
        free_player(op->contr);
        if(first_player==NULL) {
	   if (server_mode != SERVER_ENABLED)
             exit(0);
	   XCloseDisplay(op->contr->gdisp);
	   LOG(llevDebug, "In server mode: continuing action.\n");
	 }
#if 0 /* This should crash if it doesn't return! -Frank */
	if (first_player==NULL)
#endif /* (Also, free_player() must be before the NULL test!) */
        return;
      }
      break;

.....

}



void do_some_living(object *op) {

....

#ifdef NOT_PERMADEATH

 /**************************************/
 /*                                    */
 /* Pick a stat, and steal on pt from  */
 /* it...                              */
 /*                                    */
 /**************************************/
    i = RANDOM() % 6;
    change_attr_value(&(op->stats), i,-1);
    check_stat_bounds(&(op->stats));
    change_attr_value(&(op->contr->orig_stats), i,-1);
    check_stat_bounds(&(op->contr->orig_stats));
    draw_info(op, lose_msg[i]);

    /*  peterm:  added to create a corpse at deathsite.  */
    tmp=arch_to_object(find_archetype("corpse_pl"));
    sprintf(buf,"%s", op->name);
    if (tmp->name)
	free_string (tmp->name);
    tmp->name=add_string(buf);
    tmp->level=op->level;
    tmp->x=x;tmp->y=y;
    if (tmp->msg)
	free_string(tmp->msg);
    sprintf(buf,"RIP\nHere rests the hero %s the %s,\n"
	    "who was in level %d and lost %d experience\n"
	    "when killed by %s.\n",
	    op->name, op->contr->title, (int)op->level, 
	    (int)(op->stats.exp * 0.20), op->contr->killer);
    tmp->msg = add_string(buf);
    SET_FLAG (tmp, FLAG_UNIQUE);
    insert_ob_in_map(tmp,map);


    cast_heal(op, 0, SP_CURE_POISON);
    cast_heal(op, 0, SP_CURE_CONFUSION);
    add_exp(op, (op->stats.exp * -0.20));
    if(op->stats.food < 0) op->stats.food = 500;
    op->stats.hp = op->stats.maxhp;


    tmp=get_object();
    EXIT_PATH(tmp) = add_string(first_map_path);
    enter_exit(op,tmp);
/* commenting this out seems to fix core dumps on some systems. */
    free_object(tmp);


    draw_stats(op);
    draw_all_inventory(op);
    draw_info(op,"YOU HAVE DIED.");
/* save player at once to avoid cheat... d1mag */
    draw_info(op,"You have been saved.");
    save_player(op, 1);

    return;
#endif


------------------------------------------------

xio.c


/* added by d1mag, just put a corpse with link dead name */

int mag_linkdead(object *op) {

  int x,y;
  object *tmp;
  mapstruct *map;  /*  this is for resurrection */
  char buf[MAX_BUF];

  if(!op) {
    LOG(llevError,"couldn't save null player.\n");
    return 0;
  }
  /*  save the map location for corpse, gravestone*/
  x=op->x;y=op->y;map=op->map;
  strcpy(op->contr->killer, "lost connection");

  /*  peterm:  added to create a corpse at deathsite.  */
  tmp=arch_to_object(find_archetype("corpse_pl"));
  sprintf(buf,"%s (link dead)", op->name);
  if (tmp->name)
    free_string (tmp->name);
  tmp->name=add_string(buf);
  tmp->level=op->level;
  tmp->x=x;tmp->y=y;
  if (tmp->msg)
    free_string(tmp->msg);
  tmp->msg = add_string(gravestone_text(op));
  SET_FLAG (tmp, FLAG_UNIQUE);
  insert_ob_in_map(tmp,map); /* insert gravestone in map */
  return 1;
}


/* handle a cheating player, who kills the window.. */
/* uses longjump !! */

int IOerrors(Display *d) {
  player *pl;
  char buf[MAX_BUF];
  object *op;

  LOG(llevError,"Fatal error on display.\n");
/* Mol(mol@meryl.csd.uu.se 9211211 Temporary patch. The game locks in an 
   infinite save-loop when using the original emergency_save(2)
 */
/*
   emergency_save(0);
*/

  if(editor)
    exit(-1);
  for(pl=first_player;pl!=NULL;pl=pl->next)
    if(pl->gdisp==d)
      break;
  if(pl==NULL) {
    for(pl=first_player;pl!=NULL;pl=pl->next)
      if(pl->ob->contr->gdisp==d)
	break;
  }
  if(pl==NULL) return 0;
  op = pl->ob;
  /* d1mag patch */
  LOG(llevError,"Player %s lost the display.\n",pl->name);
  LOG(llevError,"Saveing escaping player [%s]\n", query_name(op));

/* d1mag patch to get a corpse */
  mag_linkdead(op);

  /* prevent updating inventory of player for whom there is no longer a
  ** functional display */
  pl->freeze_inv = 1;

  if(pl->ob->state== ST_PLAYING ||pl->ob->state==ST_CHANGE_CLASS ||
	pl->ob->state==ST_CONFIGURE)
	    if( !QUERY_FLAG(pl->ob,FLAG_REMOVED)) remove_ob(pl->ob);

  op->contr->state = 1;
  op->direction = 0;
  op->contr->count_left = 0;
  sprintf(buf, "%s lost connection.", op->name);
  info_all(buf, 5);
  check_score(op);
  (void) save_player(op, 0);
  remove_lock(op->contr);
  info_flush();
  free_player(op->contr);
  if(first_player==NULL) {
    if (server_mode != SERVER_ENABLED)
      exit(0);
    XCloseDisplay(op->contr->gdisp);
    LOG(llevDebug, "In server mode: continuing action.\n");
  }

  longjmp(jump_addr,1);
  return 0;
  /* just return here... */
}



------------------------------------------------






-- 
|  Christian 'Mag' Magnusson		Computer Science and Engineering
|  Internet: d1mag@dtek.chalmers.se	Chalmers University of Technology
|  Amiga Programmer:	VoiXEL, HP28S-Com