Date: Monday October 16, 2000 @ 12:19 Author: peterm Update of /home/cvs/CVS/crossfire/server In directory boltzmann.eecs.berkeley.edu:/tmp/cvs-serv24589 Modified Files: apply.c login.c player.c skill_util.c spell_util.c time.c Log Message: Major race/class change by PeterM: BEGIN: ***************** apply.c: new function, apply changes to player. If the change is a CLASS, player receives certain attributes from the class. login.c: make sure people using the old race/class archetypes in their player files can still use them. player.c: 1) give_initial_items modified for greater flexibility: you can pass in a treasurelist. 2) Also, initial forces are applied to the player. 3) Comment added on the stat roll function. 4) Word of recall into the new class-choice map (unfortunately hard-wired.) for newly-rolled players. 5) gen_sp and gen_hp and gen_grace now allowed to go negative to slow down player regen. skill_util.c 1) Don't give out basic skills anymore. This interferes with the class code. spell_util.c 1) Praying failures moderated in frequency. 2) Summoned creatures enhanced in wc, speed, depending on casting level. 3) Word of recall allowed to work in no-magic areas if a flag is set. time.c 1) Move player changer function added. 2) Marker object expiration added. END race/class stuff 10/16/2000 *************************** **************************************** Index: crossfire/server/apply.c diff -u crossfire/server/apply.c:1.19 crossfire/server/apply.c:1.20 --- crossfire/server/apply.c:1.19 Thu Oct 12 10:17:04 2000 +++ crossfire/server/apply.c Mon Oct 16 12:19:31 2000 @@ -1,6 +1,6 @@ /* * static char *rcsid_apply_c = - * "$Id: apply.c,v 1.19 2000/10/12 17:17:04 peterm Exp $"; + * "$Id: apply.c,v 1.20 2000/10/16 19:19:31 peterm Exp $"; */ /* CrossFire, A Multiplayer game for X-windows @@ -2537,4 +2537,58 @@ cast_mana_storm(op,power); } #endif +} + +void apply_changes_to_player(object *player, object *change) { + object *op; + switch (change->type) { + case CLASS: + { + living *stats = &(player->contr->orig_stats); + living *ns = &(change->stats); + object *walk; + int flag_change_face=1; + + /* reshuffle the stats */ + stats->Str += ns->Str; + stats->Dex += ns->Dex; + stats->Con += ns->Con; + stats->Int += ns->Int; + stats->Wis += ns->Wis; + stats->Pow += ns->Pow; + stats->Cha += ns->Cha; + + /* insert the randomitems from the change's treasurelist into + the player ref: player.c*/ + if(change->randomitems!=NULL) + give_initial_items(player,change->randomitems); + + + /* set up the face, for some races. */ + + /* first, look for the force object banning + changing the face. Certain races never change face with class. */ + for(walk=player->inv;walk!=NULL;walk=walk->below) + if (!strcmp(walk->name,"NOCLASSFACECHANGE")) flag_change_face=0; + + if(flag_change_face) { + player->animation_id = GET_ANIM_ID(change); + player->face = change->face; + + if(QUERY_FLAG(change,FLAG_ANIMATE)) + SET_FLAG(player,FLAG_ANIMATE); + else + CLEAR_FLAG(player,FLAG_ANIMATE); + } + + /* check the special case of can't use weapons */ + /*if(QUERY_FLAG(change,FLAG_USE_WEAPON)) CLEAR_FLAG(player,FLAG_USE_WEAPON);*/ + if(!strcmp(change->name,"monk")) CLEAR_FLAG(player,FLAG_USE_WEAPON); + + break; + + } + } + + } Index: crossfire/server/login.c diff -u crossfire/server/login.c:1.9 crossfire/server/login.c:1.10 --- crossfire/server/login.c:1.9 Mon Aug 7 23:57:57 2000 +++ crossfire/server/login.c Mon Oct 16 12:19:31 2000 @@ -1,6 +1,6 @@ /* * static char *rcsid_login_c = - * "$Id: login.c,v 1.9 2000/08/08 06:57:57 cvs Exp $"; + * "$Id: login.c,v 1.10 2000/10/16 19:19:31 peterm Exp $"; */ /* @@ -507,7 +507,7 @@ player *pl = op->contr; int correct = 0; - strcpy (pl->maplevel, first_map_path); + strcpy (pl->maplevel,first_map_path); /* First, lets check for newest form of save */ sprintf(filename,"%s/%s/%s/%s.pl",settings.localdir,settings.playerdir,op->name,op->name); @@ -695,6 +695,8 @@ } } + /* make sure he's a player--needed because of class change. */ + op->type = PLAYER; enter_exit(op,NULL); /* This won't insert the player any longer! */ pl->name_changed=1; Index: crossfire/server/player.c diff -u crossfire/server/player.c:1.16 crossfire/server/player.c:1.17 --- crossfire/server/player.c:1.16 Tue Aug 1 23:04:50 2000 +++ crossfire/server/player.c Mon Oct 16 12:19:31 2000 @@ -1,6 +1,6 @@ /* * static char *rcsid_player_c = - * "$Id: player.c,v 1.16 2000/08/02 06:04:50 cvs Exp $"; + * "$Id: player.c,v 1.17 2000/10/16 19:19:31 peterm Exp $"; */ /* @@ -318,12 +318,12 @@ return dir; } -void give_initial_items(object *pl) { +void give_initial_items(object *pl,treasurelist *items) { object *op,*next=NULL; static uint8 start_spells[] = {0, 1, 4, 5, 7,17,168}; static uint8 start_prayers[] = {19, 31, 32, 129}; if(pl->randomitems!=NULL) - create_treasure(pl->randomitems,pl,GT_INVENTORY,1,0); + create_treasure(items,pl,GT_INVENTORY,1,0); for (op=pl->inv; op; op=next) { next = op->below; @@ -333,6 +333,7 @@ /* Not marked as starting equipment, so set 0 value. */ if (QUERY_FLAG(op,FLAG_IS_THROWN)) op->value=0; + if(op->type==FORCE) { SET_FLAG(op,FLAG_APPLIED);}; if(op->type==SPELLBOOK) { /* fix spells for first level spells */ if(!strcmp(op->arch->name,"cleric_book")) op->stats.sp=start_prayers[RANDOM()%(sizeof(start_prayers)/sizeof(uint8))]; @@ -426,6 +427,8 @@ send_query(&op->contr->socket, CS_QUERY_HIDEINPUT, "What is the password?\n:"); } + +/* This rolls four 1-6 rolls and sums the best 3 of the 4. */ int roll_stat() { int a[4],i,j,k; for(i=0;i<4;i++) @@ -601,15 +604,18 @@ #endif switch (key) { case 'n': - case 'N': + case 'N': { SET_FLAG(op, FLAG_WIZ); if(op->map==NULL) { LOG(llevError,"Map == NULL in state 2\n"); break; } + /* So that enter_exit will put us at startx/starty */ op->x= -1; + enter_exit(op,NULL); + /* Enter exit adds a player otherwise */ if(op->contr->loading == NULL) { insert_ob_in_map(op,op->map,op); @@ -621,7 +627,7 @@ send_query(&op->contr->socket,CS_QUERY_SINGLECHAR,"Now choose a character.\nPress any key to change outlook.\nPress `d' when you're pleased.\n"); op->contr->state = ST_CHANGE_CLASS; return 0; - + } case 'y': case 'Y': roll_stats(op); @@ -680,11 +686,22 @@ #ifdef ALLOW_SKILLS (void) init_player_exp(op); #endif - give_initial_items(op); + give_initial_items(op,op->randomitems); #ifdef ALLOW_SKILLS (void) link_player_skills(op); #endif esrv_send_inventory(op, op); + { + object *WoR = get_archetype("force"); + WoR->speed = .5; + WoR->speed_left = -1; + WoR->type = WORD_OF_RECALL; + WoR->stats.hp = 1; + EXIT_PATH(WoR) = add_string("/HallOfSelection"); + EXIT_X(WoR) = 1; + EXIT_Y(WoR) = 1; + insert_ob_in_ob(WoR,op); + } return 0; } @@ -1459,9 +1476,9 @@ int gen_hp, gen_sp, gen_grace; int over_hp, over_sp, over_grace; int i; - const int rate_hp = 1200; - const int rate_sp = 2500; - const int rate_grace = 2000; + int rate_hp = 1200; + int rate_sp = 2500; + int rate_grace = 2000; const int max_hp = 1; const int max_sp = 1; const int max_grace = 1; @@ -1474,9 +1491,27 @@ } if(op->contr->state==ST_PLAYING) { - gen_hp=(op->contr->gen_hp+1)*op->stats.maxhp; - gen_sp=(op->contr->gen_sp+1)*op->stats.maxsp; - gen_grace=(op->contr->gen_grace+1)*op->stats.maxgrace; + + /* these next three if clauses make it possible to SLOW DOWN + hp/grace/spellpoint regeneration. */ + if(op->contr->gen_hp >= 0 ) + gen_hp=(op->contr->gen_hp+1)*op->stats.maxhp; + else { + gen_hp = op->stats.maxhp; + rate_hp -= rate_hp/2 * op->contr->gen_hp; + } + if(op->contr->gen_sp >= 0 ) + gen_sp=(op->contr->gen_sp+1)*op->stats.maxsp; + else { + gen_sp = op->stats.maxsp; + rate_sp -= rate_sp/2 * op->contr->gen_sp; + } + if(op->contr->gen_grace >= 0) + gen_grace=(op->contr->gen_grace+1)*op->stats.maxgrace; + else { + gen_grace = op->stats.maxgrace; + rate_grace -= rate_grace/2 * op->contr->gen_grace; + } /* Regenerate Spell Points */ if(op->contr->golem==NULL&&--op->last_sp<0) { @@ -1560,8 +1595,10 @@ if(--op->last_eat<0) { int bonus=op->contr->digestion>0?op->contr->digestion:0, penalty=op->contr->digestion<0?-op->contr->digestion:0; - - op->last_eat=25*(1+bonus)/(op->contr->gen_hp+penalty+1); + if(op->contr->gen_hp > 0) + op->last_eat=25*(1+bonus)/(op->contr->gen_hp+penalty+1); + else + op->last_eat=25*(1+bonus)/(penalty +1); op->stats.food--; } } Index: crossfire/server/skill_util.c diff -u crossfire/server/skill_util.c:1.9 crossfire/server/skill_util.c:1.10 --- crossfire/server/skill_util.c:1.9 Tue Sep 26 17:50:47 2000 +++ crossfire/server/skill_util.c Mon Oct 16 12:19:31 2000 @@ -1,6 +1,6 @@ /* * static char *rcsid_skill_util_c = - * "$Id: skill_util.c,v 1.9 2000/09/27 00:50:47 peterm Exp $"; + * "$Id: skill_util.c,v 1.10 2000/10/16 19:19:31 peterm Exp $"; */ /* CrossFire, A Multiplayer game for X-windows @@ -882,7 +882,8 @@ /* This looks like we have an old player file, so give those basic * skills to the player in this case. */ - if(old_file) { + /* No, don't do this anymore. */ + if(0) { object *tmp2; int limit = sizeof(basic_skills)/sizeof(char *); @@ -903,19 +904,20 @@ break; } - if(add) { - insert_ob_in_ob(tmp,pl); - sk_ob[sk_index] = tmp; - sk_index++; - LOG(llevDebug,"Added basic skill: %s to inventory of %s\n", - basic_skills[i], pl->name); + if(add) { + insert_ob_in_ob(tmp,pl); + sk_ob[sk_index] = tmp; + sk_index++; + LOG(llevDebug,"Added basic skill: %s to inventory of %s\n", + basic_skills[i], pl->name); } } else { - LOG(llevError, - "init_player_skills() - can't find basic skill: %s\n",basic_skills[i]); - return 0; - } - } + LOG(llevError, + "init_player_skills() - can't find basic skill: %s\n",basic_skills[i]); + return 0; + } + + } /* Ok, create linked list and link the associated skills to exp objects */ for(i=0;i<sk_index;i++) { #ifdef LINKED_SKILL_LIST Index: crossfire/server/spell_util.c diff -u crossfire/server/spell_util.c:1.17 crossfire/server/spell_util.c:1.18 --- crossfire/server/spell_util.c:1.17 Tue Jun 13 06:30:03 2000 +++ crossfire/server/spell_util.c Mon Oct 16 12:19:31 2000 @@ -1,6 +1,6 @@ /* * static char *rcsid_spell_util_c = - * "$Id: spell_util.c,v 1.17 2000/06/13 13:30:03 jec Exp $"; + * "$Id: spell_util.c,v 1.18 2000/10/16 19:19:31 peterm Exp $"; */ /* @@ -309,8 +309,10 @@ return 0; } if(item == spellNormal && op->type==PLAYER&&s->cleric&& - RANDOM()%100< s->level*2 - op->level + cleric_chance[op->stats.Wis]- - op->stats.luck*3) { + /* RANDOM()%100< s->level*2 - op->level + cleric_chance[op->stats.Wis]- + op->stats.luck*3) {*/ + RANDOM()%100 < s->level/(float)MAX(1,op->level) * cleric_chance[op->stats.Wis]- + op->stats.luck*3) { play_sound_player_only(op->contr, SOUND_FUMBLE_SPELL,0,0); new_draw_info(NDI_UNIQUE, 0,op,"You fumble the spell."); #ifdef CASTING_TIME @@ -848,6 +850,10 @@ 10 * SP_level_strength_adjust(op,caster,spellnum); tmp->stats.dam= SP_PARAMETERS[spellnum].bdam + 2* SP_level_dam_adjust(op,caster,spellnum); + tmp->stats.wc -= SP_level_dam_adjust(op,caster,spellnum); + tmp->speed += .05 * SP_level_dam_adjust(op,caster,spellnum); + /* limit the speed to 1 */ + tmp->speed = MIN(tmp->speed,1); if(tmp->stats.dam<0) tmp->stats.dam=127; /*seen this go negative!*/ /* make experience increase in proportion to the strength of the summoned creature. */ tmp->stats.exp *= SP_level_spellpoint_cost(op,caster,spellnum)/spells[spellnum].sp; Index: crossfire/server/time.c diff -u crossfire/server/time.c:1.10 crossfire/server/time.c:1.11 --- crossfire/server/time.c:1.10 Fri Jul 28 00:10:21 2000 +++ crossfire/server/time.c Mon Oct 16 12:19:31 2000 @@ -1,6 +1,6 @@ /* * static char *rcsid_time_c = - * "$Id: time.c,v 1.10 2000/07/28 07:10:21 cvs Exp $"; + * "$Id: time.c,v 1.11 2000/10/16 19:19:31 peterm Exp $"; */ /* @@ -155,7 +155,7 @@ while(op!=NULL&&op->type!=PLAYER) op=op->env; if(op!=NULL) { - if(blocks_magic(op->map,op->x,op->y)) + if(blocks_magic(op->map,op->x,op->y) && wor->stats.hp != 1) new_draw_info(NDI_UNIQUE, 0,op,"You feel something fizzle inside you."); else enter_exit(op,wor); @@ -669,9 +669,10 @@ } void move_teleporter(object *op) { + if(op->above!=NULL) { if(EXIT_PATH(op)) { - if(op->above->type==PLAYER) + if(op->above->type==PLAYER) enter_exit(op->above,op); else return; @@ -691,6 +692,31 @@ } } +/* This object will teleport someone to a different map + and will also apply changes to the player from its inventory. + This was invented for giving classes, but there's no reason it + can't be generalized. +*/ + +void move_player_changer(object *op) { + object *player; + object *walk; + if(op->above!=NULL) { + if(EXIT_PATH(op)) { + if(op->above->type==PLAYER) { + player=op->above; + for(walk=op->inv;walk!=NULL;walk=walk->below) + apply_changes_to_player(player,walk); + link_player_skills(op->above); + esrv_send_inventory(op->above,op->above); + enter_exit(op->above,op); + } + else + return; + } + } +} + /* peterm: firewalls generalized to be able to shoot any type of spell at all. the stats.dam field of a firewall object contains it's spelltype. The direction of the wall is stored @@ -795,7 +821,9 @@ it, and insert an invisible, weightless force into him with a specific code as the slaying field. At that time, it writes the contents of its own message - field to the player. */ + field to the player. The marker will decrement hp to + 0 and then delete itself every time it grants a mark. + unless hp was zero to start with, in which case it is infinite.*/ void move_marker(object *op) { object *tmp,*tmp2; @@ -821,6 +849,7 @@ /* if we didn't find our own MARK */ if(tmp2==NULL) { + object *force = get_archetype("force"); force->speed = 0; if(op->stats.food) { @@ -830,8 +859,18 @@ update_ob_speed (force); /* put in the lock code */ force->slaying = add_string(op->slaying); - insert_ob_in_ob(force,tmp); - + insert_ob_in_ob(force,tmp); + if(op->msg) + new_draw_info(NDI_UNIQUE|NDI_NAVY,0,tmp,op->msg); + if(op->stats.hp > 0) { + op->stats.hp--; + if(op->stats.hp==0) { + /* marker expires--granted mark number limit */ + remove_ob(op); + free_object(op); + return; + } + } } } @@ -992,6 +1031,9 @@ return 0; case MARKER: move_marker(op); + return 0; + case PLAYER_CHANGER: + move_player_changer(op); return 0; }