version 1.194 | | version 1.195 |
---|
| | |
/* | | /* |
* static char *rcsid_player_c = | | * static char *rcsid_player_c = |
* "$Id: player.c,v 1.194 2006/03/14 17:12:28 ryo_saeba Exp $"; | | * "$Id: player.c,v 1.195 2006/03/18 15:05:37 ryo_saeba Exp $"; |
*/ | | */ |
| | |
/* | | /* |
| | |
return 1; | | return 1; |
} | | } |
| | |
/* This no longer sets the player map. Also, it now updates | | /** |
| | * This no longer sets the player map. Also, it now updates |
* all the pointers so the caller doesn't need to do that. | | * all the pointers so the caller doesn't need to do that. |
* Caller is responsible for setting the correct map. | | * Caller is responsible for setting the correct map. |
*/ | | * |
| | * Redo this to do both get_player_ob and get_player. |
/* Redo this to do both get_player_ob and get_player. | | |
* Hopefully this will be less bugfree and simpler. | | * Hopefully this will be less bugfree and simpler. |
* Returns the player structure. If 'p' is null, | | * Returns the player structure. If 'p' is null, |
* we create a new one. Otherwise, we recycle | | * we create a new one. Otherwise, we recycle |
| | |
} | | } |
| | |
| | |
/* This loads the first map an puts the player on it. */ | | /** This loads the first map an puts the player on it. */ |
static void set_first_map(object *op) | | static void set_first_map(object *op) |
{ | | { |
strcpy(op->contr->maplevel, first_map_path); | | strcpy(op->contr->maplevel, first_map_path); |
| | |
enter_exit(op, NULL); | | enter_exit(op, NULL); |
} | | } |
| | |
/* Tries to add player on the connection passwd in ns. | | /** |
| | * Tries to add player on the connection passwd in ns. |
* All we can really get in this is some settings like host and display | | * All we can really get in this is some settings like host and display |
* mode. | | * mode. |
*/ | | */ |
| | |
int add_player(NewSocket *ns) { | | int add_player(socket_struct *ns) { |
player *p; | | player *p; |
| | |
p=get_player(NULL); | | p=get_player(NULL); |
memcpy(&p->socket, ns, sizeof(NewSocket)); | | memcpy(&p->socket, ns, sizeof(socket_struct)); |
p->socket.faces_sent = malloc(p->socket.faces_sent_len*sizeof(*p->socket.faces_sent)); | | p->socket.faces_sent = malloc(p->socket.faces_sent_len*sizeof(*p->socket.faces_sent)); |
if(p->socket.faces_sent == NULL) | | if(p->socket.faces_sent == NULL) |
fatal(OUT_OF_MEMORY); | | fatal(OUT_OF_MEMORY); |
| | |
return 0; | | return 0; |
} | | } |
| | |
/* | | /** |
* get_player_archetype() return next player archetype from archetype | | * get_player_archetype() return next player archetype from archetype |
* list. Not very efficient routine, but used only creating new players. | | * list. Not very efficient routine, but used only creating new players. |
* Note: there MUST be at least one player archetype! | | * Note: there MUST be at least one player archetype! |
| | |
return op; | | return op; |
} | | } |
| | |
/* I believe this can safely go to 2, 3 is questionable, 4 will likely | | /** |
| | * I believe this can safely go to 2, 3 is questionable, 4 will likely |
* result in a monster paths backtracking. It basically determines how large a | | * result in a monster paths backtracking. It basically determines how large a |
* detour a monster will take from the direction path when looking | | * detour a monster will take from the direction path when looking |
* for a path to the player. The values are in the amount of direction | | * for a path to the player. The values are in the amount of direction |
| | |
*/ | | */ |
#define DETOUR_AMOUNT 2 | | #define DETOUR_AMOUNT 2 |
| | |
/* This is used to prevent infinite loops. Consider a case where the | | /** |
| | * This is used to prevent infinite loops. Consider a case where the |
* player is in a chamber (with gate closed), and monsters are outside. | | * player is in a chamber (with gate closed), and monsters are outside. |
* with DETOUR_AMOUNT==2, the function will turn each corner, trying to | | * with DETOUR_AMOUNT==2, the function will turn each corner, trying to |
* find a path into the chamber. This is a good thing, but since there | | * find a path into the chamber. This is a good thing, but since there |
| | |
#define MAX_SPACES 50 | | #define MAX_SPACES 50 |
| | |
| | |
/* | | /** |
* Returns the direction to the player, if valid. Returns 0 otherwise. | | * Returns the direction to the player, if valid. Returns 0 otherwise. |
* modified to verify there is a path to the player. Does this by stepping towards | | * modified to verify there is a path to the player. Does this by stepping towards |
* player and if path is blocked then see if blockage is close enough to player that | | * player and if path is blocked then see if blockage is close enough to player that |
| | |
} | | } |
| | |
| | |
/* This rolls four 1-6 rolls and sums the best 3 of the 4. */ | | /** This rolls four 1-6 rolls and sums the best 3 of the 4. */ |
int roll_stat(void) { | | int roll_stat(void) { |
int a[4],i,j,k; | | int a[4],i,j,k; |
| | |
| | |
op->contr->orig_stats=op->stats; | | op->contr->orig_stats=op->stats; |
} | | } |
| | |
void Roll_Again(object *op) | | void roll_again(object *op) |
{ | | { |
esrv_new_player(op->contr, 0); | | esrv_new_player(op->contr, 0); |
send_query(&op->contr->socket,CS_QUERY_SINGLECHAR,"[y] to roll new stats [n] to use stats\n[1-7] [1-7] to swap stats.\nRoll again (y/n/1-7)? "); | | send_query(&op->contr->socket,CS_QUERY_SINGLECHAR,"[y] to roll new stats [n] to use stats\n[1-7] [1-7] to swap stats.\nRoll again (y/n/1-7)? "); |
} | | } |
| | |
void Swap_Stat(object *op,int Swap_Second) | | static void swap_stat(object *op,int Swap_Second) |
{ | | { |
signed char tmp; | | signed char tmp; |
char buf[MAX_BUF]; | | char buf[MAX_BUF]; |
| | |
if ( op->contr->Swap_First == -1 ) { | | if ( op->contr->Swap_First == -1 ) { |
new_draw_info(NDI_UNIQUE, 0,op,"How the hell did you get here?!?!!!"); | | new_draw_info(NDI_UNIQUE, 0,op,"How the hell did you get here?!?!!!"); |
new_draw_info(NDI_UNIQUE, 0,op,"Error in Swap_Stat code,"); | | new_draw_info(NDI_UNIQUE, 0,op,"Error in swap_stat code,"); |
new_draw_info(NDI_UNIQUE, 0,op,"mail korg@rdt.monash.edu.au"); | | new_draw_info(NDI_UNIQUE, 0,op,"mail korg@rdt.monash.edu.au"); |
return; | | return; |
} | | } |
| | |
} | | } |
| | |
| | |
/* This code has been greatly reduced, because with set_attr_value | | /** |
| | * This code has been greatly reduced, because with set_attr_value |
* and get_attr_value, the stats can be accessed just numeric | | * and get_attr_value, the stats can be accessed just numeric |
* ids. stat_trans is a table that translate the number entered | | * ids. stat_trans is a table that translate the number entered |
* into the actual stat. It is needed because the order the stats | | * into the actual stat. It is needed because the order the stats |
| | |
new_draw_info(NDI_UNIQUE, 0,op,buf); | | new_draw_info(NDI_UNIQUE, 0,op,buf); |
} | | } |
else | | else |
Swap_Stat(op,stat_trans[keynum]); | | swap_stat(op,stat_trans[keynum]); |
| | |
send_query(&op->contr->socket,CS_QUERY_SINGLECHAR,""); | | send_query(&op->contr->socket,CS_QUERY_SINGLECHAR,""); |
return 1; | | return 1; |
| | |
} | | } |
| | |
| | |
/* check_pick sees if there is stuff to be picked up/picks up stuff. | | /** |
| | * check_pick sees if there is stuff to be picked up/picks up stuff. |
* IT returns 1 if the player should keep on moving, 0 if he should | | * IT returns 1 if the player should keep on moving, 0 if he should |
* stop. | | * stop. |
*/ | | */ |
| | |
char putstring[128], tmpstr[16]; | | char putstring[128], tmpstr[16]; |
| | |
| | |
/* if you're flying, you cna't pick up anything */ | | /* if you're flying, you can't pick up anything */ |
if (op->move_type & MOVE_FLYING) | | if (op->move_type & MOVE_FLYING) |
return 1; | | return 1; |
| | |
| | |
} | | } |
} | | } |
new_draw_info(NDI_UNIQUE, 0,op,putstring); | | new_draw_info(NDI_UNIQUE, 0,op,putstring); |
| | |
#if 0 | | |
/* print the flags too */ | | |
for(k=0;k<4;k++) | | |
{ | | |
fprintf(stderr,"%d [%d] ", k, k*32+31); | | |
for(j=0;j<32;j++) | | |
{ | | |
fprintf(stderr,"%d",tmp->flags[k]>>(31-j)&0x01); | | |
if(!((j+1)%4))fprintf(stderr," "); | | |
} | | |
fprintf(stderr," [%d]\n", k*32); | | |
} | | |
#endif | | |
} | | } |
/* philosophy: | | /* philosophy: |
* It's easy to grab an item type from a pile, as long as it's | | * It's easy to grab an item type from a pile, as long as it's |
| | |
return ! stop; | | return ! stop; |
} | | } |
| | |
/* | | /** |
* Find an arrow in the inventory and after that | | * Find an arrow in the inventory and after that |
* in the right type container (quiver). Pointer to the | | * in the right type container (quiver). Pointer to the |
* found object is returned. | | * found object is returned. |
| | |
return tmp; | | return tmp; |
} | | } |
| | |
/* | | /** |
* Similar to find_arrow, but looks for (roughly) the best arrow to use | | * Similar to find_arrow, but looks for (roughly) the best arrow to use |
* against the target. A full test is not performed, simply a basic test | | * against the target. A full test is not performed, simply a basic test |
* of resistances. The archer is making a quick guess at what he sees down | | * of resistances. The archer is making a quick guess at what he sees down |
| | |
return tmp; | | return tmp; |
} | | } |
| | |
/* looks in a given direction, finds the first valid target, and calls | | /** |
| | * looks in a given direction, finds the first valid target, and calls |
* find_better_arrow to find a decent arrow to use. | | * find_better_arrow to find a decent arrow to use. |
* op = the shooter | | * op = the shooter |
* type = bow->race | | * type = bow->race |
| | |
return find_better_arrow(op, tmp, type, &i); | | return find_better_arrow(op, tmp, type, &i); |
} | | } |
| | |
/* | | /** |
* Creature fires a bow - op can be monster or player. Returns | | * Creature fires a bow - op can be monster or player. Returns |
* 1 if bow was actually fired, 0 otherwise. | | * 1 if bow was actually fired, 0 otherwise. |
* op is the object firing the bow. | | * op is the object firing the bow. |
| | |
return 1; | | return 1; |
} | | } |
| | |
/* Special fire code for players - this takes into | | /** |
| | * Special fire code for players - this takes into |
* account the special fire modes players can have | | * account the special fire modes players can have |
* but monsters can't. Putting that code here | | * but monsters can't. Putting that code here |
* makes the fire_bow code much cleaner. | | * makes the fire_bow code much cleaner. |
| | |
} | | } |
| | |
| | |
/* Fires a misc (wand/rod/horn) object in 'dir'. | | /** |
| | * Fires a misc (wand/rod/horn) object in 'dir'. |
* Broken apart from 'fire' to keep it more readable. | | * Broken apart from 'fire' to keep it more readable. |
*/ | | */ |
void fire_misc_object(object *op, int dir) | | void fire_misc_object(object *op, int dir) |
| | |
} | | } |
} | | } |
| | |
/* Received a fire command for the player - go and do it. | | /** |
| | * Received a fire command for the player - go and do it. |
*/ | | */ |
void fire(object *op,int dir) { | | void fire(object *op,int dir) { |
int spellcost=0; | | int spellcost=0; |
| | |
| | |
| | |
| | |
/* find_key | | /** |
* We try to find a key for the door as passed. If we find a key | | * We try to find a key for the door as passed. If we find a key |
* and successfully use it, we return the key, otherwise NULL | | * and successfully use it, we return the key, otherwise NULL |
* This function merges both normal and locked door, since the logic | | * This function merges both normal and locked door, since the logic |
| | |
return tmp; | | return tmp; |
} | | } |
| | |
/* moved door processing out of move_player_attack. | | /** |
| | * moved door processing out of move_player_attack. |
* returns 1 if player has opened the door with a key | | * returns 1 if player has opened the door with a key |
* such that the caller should not do anything more, | | * such that the caller should not do anything more, |
* 0 otherwise | | * 0 otherwise |
| | |
return 0; | | return 0; |
} | | } |
| | |
/* This function is just part of a breakup from move_player. | | /** |
| | * This function is just part of a breakup from move_player. |
* It should keep the code cleaner. | | * It should keep the code cleaner. |
* When this is called, the players direction has been updated | | * When this is called, the players direction has been updated |
* (taking into account confusion.) The player is also actually | | * (taking into account confusion.) The player is also actually |
| | |
return 0; | | return 0; |
} | | } |
| | |
/* This is similar to handle_player, below, but is only used by the | | /** |
| | * This is similar to handle_player, below, but is only used by the |
* new client/server stuff. | | * new client/server stuff. |
* This is sort of special, in that the new client/server actually uses | | * This is sort of special, in that the new client/server actually uses |
* the new speed values for commands. | | * the new speed values for commands. |
| | |
* the players time has been increased when doericserver has been | | * the players time has been increased when doericserver has been |
* called, so we recheck it here. | | * called, so we recheck it here. |
*/ | | */ |
HandleClient(&op->contr->socket, op->contr); | | handle_client(&op->contr->socket, op->contr); |
if (op->speed_left<0) return 0; | | if (op->speed_left<0) return 0; |
| | |
if(op->direction && (op->contr->run_on || op->contr->fire_on)) { | | if(op->direction && (op->contr->run_on || op->contr->fire_on)) { |
| | |
return 0; | | return 0; |
} | | } |
| | |
int save_life(object *op) { | | /** |
| | * Returns 1 if player had his life saved by an item. |
| | * In this case, first item saving life is removed. |
| | */ |
| | static int save_life(object *op) { |
object *tmp; | | object *tmp; |
| | |
if(!QUERY_FLAG(op,FLAG_LIFESAVE)) | | if(!QUERY_FLAG(op,FLAG_LIFESAVE)) |
| | |
for(tmp=op->inv;tmp!=NULL;tmp=tmp->below) | | for(tmp=op->inv;tmp!=NULL;tmp=tmp->below) |
if(QUERY_FLAG(tmp, FLAG_APPLIED)&&QUERY_FLAG(tmp,FLAG_LIFESAVE)) { | | if(QUERY_FLAG(tmp, FLAG_APPLIED)&&QUERY_FLAG(tmp,FLAG_LIFESAVE)) { |
play_sound_map(op->map, op->x, op->y, SOUND_OB_EVAPORATE); | | play_sound_map(op->map, op->x, op->y, SOUND_OB_EVAPORATE); |
new_draw_info_format(NDI_UNIQUE, 0,op, | | new_draw_info_format(NDI_UNIQUE, 0,op,"Your %s vibrates violently, then evaporates.",query_name(tmp)); |
"Your %s vibrates violently, then evaporates.", | | |
query_name(tmp)); | | |
if (op->contr) | | if (op->contr) |
esrv_del_item(op->contr, tmp->count); | | esrv_del_item(op->contr, tmp->count); |
remove_ob(tmp); | | remove_ob(tmp); |
| | |
return 0; | | return 0; |
} | | } |
| | |
/* This goes throws the inventory and removes unpaid objects, and puts them | | /** |
| | * This goes throws the inventory and removes unpaid objects, and puts them |
* back in the map (location and map determined by values of env). This | | * back in the map (location and map determined by values of env). This |
* function will descend into containers. op is the object to start the search | | * function will descend into containers. op is the object to start the search |
* from. | | * from. |
| | |
} | | } |
| | |
| | |
/* | | /** |
* Returns pointer a static string containing gravestone text | | * Returns pointer a static string containing gravestone text |
* Moved from apply.c to player.c - player.c is what | | * Moved from apply.c to player.c - player.c is what |
* actually uses this function. player.c may not be quite the | | * actually uses this function. player.c may not be quite the |
* best, a misc file for object actions is probably better, | | * best, a misc file for object actions is probably better, |
* but there isn't one in the server directory. | | * but there isn't one in the server directory. |
*/ | | */ |
char *gravestone_text (object *op) | | static const char *gravestone_text (object *op) |
{ | | { |
static char buf2[MAX_BUF]; | | static char buf2[MAX_BUF]; |
char buf[MAX_BUF]; | | char buf[MAX_BUF]; |
| | |
return buf2; | | return buf2; |
} | | } |
| | |
| | /** |
| | * Regenerate hp/sp/gr, decreases food. This only works for players. |
| | * Will grab food if needed, or kill player. |
| | */ |
void do_some_living(object *op) { | | void do_some_living(object *op) { |
int last_food=op->stats.food; | | int last_food=op->stats.food; |
int gen_hp, gen_sp, gen_grace; | | int gen_hp, gen_sp, gen_grace; |
| | |
} | | } |
| | |
| | |
| | static void loot_object(object *op) { /* Grab and destroy some treasure */ |
| | object *tmp,*tmp2,*next; |
| | |
| | if (op->container) { /* close open sack first */ |
| | esrv_apply_container (op, op->container); |
| | } |
| | |
| | for(tmp=op->inv;tmp!=NULL;tmp=next) { |
| | next=tmp->below; |
| | if (tmp->type==EXPERIENCE || tmp->invisible) continue; |
| | remove_ob(tmp); |
| | tmp->x=op->x,tmp->y=op->y; |
| | if (tmp->type == CONTAINER) { /* empty container to ground */ |
| | loot_object(tmp); |
| | } |
| | if(!QUERY_FLAG(tmp, FLAG_UNIQUE) && (QUERY_FLAG(tmp, FLAG_STARTEQUIP) |
| | || QUERY_FLAG(tmp,FLAG_NO_DROP) || !(RANDOM()%3))) { |
| | if(tmp->nrof>1) { |
| | tmp2=get_split_ob(tmp,1+RANDOM()%(tmp->nrof-1)); |
| | free_object(tmp2); |
| | insert_ob_in_map(tmp,op->map,NULL,0); |
| | } else |
| | free_object(tmp); |
| | } else |
| | insert_ob_in_map(tmp,op->map,NULL,0); |
| | } |
| | } |
| | |
| | |
/* If the player should die (lack of hp, food, etc), we call this. | | /** |
| | * If the player should die (lack of hp, food, etc), we call this. |
* op is the player in jeopardy. If the player can not be saved (not | | * op is the player in jeopardy. If the player can not be saved (not |
* permadeath, no lifesave), this will take care of removing the player | | * permadeath, no lifesave), this will take care of removing the player |
* file. | | * file. |
| | |
} | | } |
} | | } |
| | |
| | /** |
void loot_object(object *op) { /* Grab and destroy some treasure */ | | |
object *tmp,*tmp2,*next; | | |
| | |
if (op->container) { /* close open sack first */ | | |
esrv_apply_container (op, op->container); | | |
} | | |
| | |
for(tmp=op->inv;tmp!=NULL;tmp=next) { | | |
next=tmp->below; | | |
if (tmp->type==EXPERIENCE || tmp->invisible) continue; | | |
remove_ob(tmp); | | |
tmp->x=op->x,tmp->y=op->y; | | |
if (tmp->type == CONTAINER) { /* empty container to ground */ | | |
loot_object(tmp); | | |
} | | |
if(!QUERY_FLAG(tmp, FLAG_UNIQUE) && (QUERY_FLAG(tmp, FLAG_STARTEQUIP) | | |
|| QUERY_FLAG(tmp,FLAG_NO_DROP) || !(RANDOM()%3))) { | | |
if(tmp->nrof>1) { | | |
tmp2=get_split_ob(tmp,1+RANDOM()%(tmp->nrof-1)); | | |
free_object(tmp2); | | |
insert_ob_in_map(tmp,op->map,NULL,0); | | |
} else | | |
free_object(tmp); | | |
} else | | |
insert_ob_in_map(tmp,op->map,NULL,0); | | |
} | | |
} | | |
| | |
/* | | |
* fix_weight(): Check recursively the weight of all players, and fix | | * fix_weight(): Check recursively the weight of all players, and fix |
* what needs to be fixed. Refresh windows and fix speed if anything | | * what needs to be fixed. Refresh windows and fix speed if anything |
* was changed. | | * was changed. |
| | |
} | | } |
| | |
| | |
/* cast_dust() - handles op throwing objects of type 'DUST'. | | /** |
| | * Handles op throwing objects of type 'DUST'. |
* This is much simpler in the new spell code - we basically | | * This is much simpler in the new spell code - we basically |
* just treat this as any other spell casting object. | | * just treat this as any other spell casting object. |
*/ | | */ |
| | |
return 0; | | return 0; |
} | | } |
| | |
/* look at the surrounding terrain to determine | | /** |
| | * Look at the surrounding terrain to determine |
* the hideability of this object. Positive levels | | * the hideability of this object. Positive levels |
* indicate greater hideability. | | * indicate greater hideability. |
*/ | | */ |
| | |
return level; | | return level; |
} | | } |
| | |
/* For Hidden creatures - a chance of becoming 'unhidden' | | /** |
| | * For Hidden creatures - a chance of becoming 'unhidden' |
* every time they move - as we subtract off 'invisibility' | | * every time they move - as we subtract off 'invisibility' |
* AND, for players, if they move into a ridiculously unhideable | | * AND, for players, if they move into a ridiculously unhideable |
* spot (surrounded by clear terrain in broad daylight). -b.t. | | * spot (surrounded by clear terrain in broad daylight). -b.t. |
| | |
} | | } |
} | | } |
| | |
/* determine if who is standing near a hostile creature. */ | | /** determine if who is standing near a hostile creature. */ |
| | |
int stand_near_hostile( object *who ) { | | int stand_near_hostile( object *who ) { |
object *tmp=NULL; | | object *tmp=NULL; |
| | |
return 0; | | return 0; |
} | | } |
| | |
/* check the player los field for viewability of the | | /** |
| | * Check the player los field for viewability of the |
* object op. This function works fine for monsters, | | * object op. This function works fine for monsters, |
* but we dont worry if the object isnt the top one in | | * but we dont worry if the object isnt the top one in |
* a pile (say a coin under a table would return "viewable" | | * a pile (say a coin under a table would return "viewable" |
| | |
return 0; | | return 0; |
} | | } |
| | |
/* routine for both players and monsters. We call this when | | /** |
| | * routine for both players and monsters. We call this when |
* there is a possibility for our action distrubing our hiding | | * there is a possibility for our action distrubing our hiding |
* place or invisiblity spell. Artefact invisiblity is not | | * place or invisiblity spell. Artefact invisiblity is not |
* effected by this. If we arent invisible to begin with, we | | * effected by this. If we arent invisible to begin with, we |
| | |
return 0; | | return 0; |
} | | } |
| | |
/* op_on_battleground - checks if the given object op (usually | | /** |
| | * op_on_battleground - checks if the given object op (usually |
* a player) is standing on a valid battleground-tile, | | * a player) is standing on a valid battleground-tile, |
* function returns TRUE/FALSE. If true x, y returns the battleground | | * function returns TRUE/FALSE. If true x, y returns the battleground |
* -exit-coord. (and if x, y not NULL) | | * -exit-coord. (and if x, y not NULL) |
| | |
return 0; | | return 0; |
} | | } |
| | |
/* | | /** |
* When a dragon-player gains a new stage of evolution, | | * When a dragon-player gains a new stage of evolution, |
* he gets some treasure | | * he gets some treasure |
* | | * |