(Not a hold hand snippet, but all the code required to do this)
Two big reasons for doing this include:
No more kill stealing
No more power leveling
You get out of a fight what you put into it.
In doing this, I also changed how experience works.
No longer, is experience based on difference of levels, it's now based on
level of the mob.
For instance, a level 100 mob will give 500 experience regardless of players
level. (not quite true, see below)
So, if a level 1 player does 1% of damage to a level 100 mob, they get
exactly that.. 1% of the full experience.
Which would be 5 :) The other player(s) get 495.
In doing testing of this, I found that players could kill mobs 1-5 levels
below them easier, and faster and get comparable experience, thus leveling
either faster, or nearly as fast. So, I have added some calculations to
reduce the amount earned as you get higher, never dropping below a certain
point.
As for code, I can share some here, but each mud is different, as is
programming style, and this may or may not work with you, or your mud.
My struct:
struct damage_data
{
bool valid; /* for recycling */
char name[64]; /* the name, nothing to allocate */
bool NPC; /* we need NPC's in here. */
CHAR_DATA *npc;
unsigned int damage; /* running total */
int hits; /* running total of damage hits */
DAMAGE_DATA *next;
};
rececyle stuff:
DAMAGE_DATA *dam_free;
DAMAGE_DATA *new_damage_data(void)
{
DAMAGE_DATA dam_zero;
DAMAGE_DATA *dam;
if (!dam_free)
dam = calloc(sizeof(*dam), 1);
else {
dam = dam_free;
dam_free = dam_free->next;
*dam = dam_zero;
}
VALIDATE(dam);
return dam;
}
void free_damage_data(DAMAGE_DATA *dam)
{
if (!IS_VALID(dam))
return;
dam->next = dam_free;
dam_free = dam;
INVALIDATE(dam);
}
in extract_char() add remove_damage_records();
and if it's also an NPC remove_damage_records_others();
/* removes all my damage records once I'm dead */
void remove_damage_records(CHAR_DATA *ch)
{
DAMAGE_DATA *dam=NULL, *dam_next=NULL, *prev = NULL;
for (dam=ch->damage_data; dam!=NULL;dam = dam_next){
dam_next = dam->next;
UNLINK(dam, ch->damage_data, prev);
free_damage_data(dam);
}
ch->damage_data = NULL;
}
/* removes damage records from everyone else that has me in their list */
void remove_damage_records_others(CHAR_DATA *ch)
{
DAMAGE_DATA *dam=NULL, *dam_next=NULL, *prev = NULL;
CHAR_DATA *loop;
for (loop=char_list; loop!=NULL; loop=loop->next){
for (dam=loop->damage_data; dam!=NULL;dam = dam_next){
dam_next = dam->next;
if (dam->NPC && dam->npc == ch){
UNLINK(dam, loop->damage_data, prev);
free_damage_data(dam);
}
}
}
}
In group_gain i do alot of stuff, but for starters:
/* this counts group numbers and adds up total damage to mob, you should
remove the group stuff */
for (dam = victim->damage_data; dam!=NULL; dam=dam->next){
if (ch->group && !dam->NPC)
groupc++;
dam_total+=dam->damage;
}
Here's the loop that I use to give out experience. You won't be able to use
this straight out.
for (dam = victim->damage_data; dam!=NULL; dam=dam->next){
if (dam->NPC) continue;
och = get_char_player(ch, dam->name);
if (!och) {
och = str_load_char_offline(dam->name);
if (!och) /* not existant */
continue;
offline=TRUE;
}
xp = xp_compute(och, victim);
/* how much damage done */
damage = dam_total*100/dam->damage;
/* let's do the math here */
exp = xp*100/damage;
if (groupc>1){ /* only if group is greater than one */
exp+=(exp*group);
}
if (offline) {
char buf[128];
if (IS_GHOST(och))
och->pcdata->odeath_points+=exp;
else
och->pcdata->offline_exp+=exp;
sprintf(buf, "Offline player %s earned %i points in the death of
%s.", och->name, exp, victim->name);
wiznet(buf, NULL,NULL, WIZ_INFO,0,0);
log_string(buf);
save_char_obj(och);
free_char(och);
continue;
}
/* killing animated zombies reaps no rewards */
if ( (IS_NPC(victim)) && (victim->pIndexData->vnum ==
MOB_VNUM_ZOMBIE ||
victim->pIndexData->vnum ==
MOB_VNUM_ELEMENTAL ||
victim->pIndexData->vnum ==
MOB_VNUM_GOOD_GUARDIAN||
victim->pIndexData->vnum ==
MOB_VNUM_EVIL_GUARDIAN))
xp = 0;
if (och->in_room != victim->in_room){
sprintf(buf, "{%cYou aided in the death of %s and receive {%c%d
{%c%s point%s.{x\n\r",
IS_GHOST(och) ? 'c' : 'r',
PERS(victim, och),
IS_GHOST(och) ? 'C' : 'R', exp,
IS_GHOST(och) ? 'c' : 'r',
IS_GHOST(och) ? "death" : "experience", (exp>1)?"s":"");
}
else
sprintf(buf, "{%cYou receive {%c%d {%c%s point%s.{x\n\r",
IS_GHOST(och) ? 'c' : 'r',
IS_GHOST(och) ? 'C' : 'R', exp,
IS_GHOST(och) ? 'c' : 'r',
IS_GHOST(och) ? "death" : "experience", (exp>1)?"s":"");
send_to_char(buf, och);
if (IS_GHOST(och))
gain_death(och, exp);
else{
gain_exp(och,exp);
}
save_char_obj(och);
}
update_damage_record is called in damage (whenever there is damage)
void update_damage_record(CHAR_DATA *ch, CHAR_DATA *victim, int dam)
{
DAMAGE_DATA *dam_list;
/* see if there is a record for this user */
for (dam_list = victim->damage_data; dam_list!=NULL;
dam_list=dam_list->next){
if (!strcmp(ch->name, dam_list->name)) {/* found it */
dam_list->damage+=dam;
dam_list->hits++;
if (IS_NPC(ch)){
if (ch->leader!=NULL){
if (!IS_NPC(ch->leader))
update_damage_record(ch->leader, victim, dam);
}
else if (ch->master!=NULL){
if (!IS_NPC(ch->master))
update_damage_record(ch->leader, victim, dam);
}
}
return;
}
}
/* didn't find an entry, add a new one */
dam_list = new_damage_data();
if (IS_NPC(ch)){
dam_list->NPC = TRUE;
dam_list->npc = ch;
}
else{
dam_list->NPC = FALSE;
dam_list->npc = NULL;
}
strcpy(dam_list->name, ch->name);
dam_list->hits=1;
dam_list->damage=dam;
dam_list->next = victim->damage_data;
victim->damage_data=dam_list;
if (IS_NPC(ch)){
if (ch->leader!=NULL){
if (!IS_NPC(ch->leader))
update_damage_record(ch->leader, victim, dam);
}
else if (ch->master!=NULL){
if (!IS_NPC(ch->master))
update_damage_record(ch->leader, victim, dam);
}
}
}
Cute little imm command to show you who has damaged who and how much:
void do_damage(CHAR_DATA *ch, char *argument)
{
DAMAGE_DATA *dam=NULL;
CHAR_DATA *loop;
int count=0, count2=0;
printf_to_char(ch, "{gDamage data:\n");
printf_to_char(ch, "{w============\n");
for (loop=char_list; loop!=NULL; loop = loop->next){
if (loop->damage_data==NULL) continue;
count++;
printf_to_char(ch, "{g%s:\n", loop->name);
for (dam = loop->damage_data; dam!=NULL; dam=dam->next){
printf_to_char(ch, "\t{w%-20s Damage: %4i Hits: %4i\n\r",
(dam->NPC)?dam->npc->name:dam->name, dam->damage,
dam->hits);
count2++;
}
printf_to_char(ch, "\n");
}
printf_to_char(ch, "\n{W%i {wrecords from {W%i {wcharacters.\n", count,
count2);
}
That's it... Have fun.
Jason
-----Original Message-----
From: Michael Gerner Andreasen [mailto:[EMAIL PROTECTED]
Sent: Tuesday, August 13, 2002 4:49 AM
To: rom list
Subject: Fw: Idea about new exp system
----- Original Message -----
From: "Michael Gerner Andreasen" <[EMAIL PROTECTED]>
To: "Jason Gauthier" <[EMAIL PROTECTED]>
Sent: Tuesday, August 13, 2002 10:47 AM
Subject: Re: Idea about new exp system
> > A little late, as I've been on vacation.
> Np.
>
> > This is very close to, if not exactly what I've implemented.
> Good, now i know atleast one other person who likes the idea.
>
> > (I save the damage and tally it for each unique attacker)
> > Then you divide it up, and give the percentages.
> The same plan here.
>
> > But adding up total damage, if the mob is wrathed, or heals, you get an
> > accurate percentage.
> Thats true, wants it to be fair of all.
>
> > One caveat is with pets. If an NPC does damage and has no master, I
don't
> > update/add anything.
> > Otherwise, it's master gets the credit.
> Ahh nice dident think of this, but then again, i only got stuff on paper
at
> the moment,
> can see the picture, but the hands are still.
>
> Would you like to share some code, with the rest of us? would like to see
> loops for updating in healing and exp gains.
>
> and any info on linked lists would be help full, as it is not what I
> normally play with all day long.
>
> will send some code to the list, as I get stuff coded, will properly be
full
> of bugs and what not, but atleast iam trying something new.
>
> and to make ppl on the list happy, iam gona try pass this mail via the
spell
> checker...
> That spell checker didn't complete, but I hope you can read it anyways.
>
> -- Kawaki
>
--
ROM mailing list
[email protected]
http://www.rom.org/cgi-bin/mailman/listinfo/rom