1 | /* |
1 | /* |
2 | * static char *rcsid_player_c = |
2 | * static char *rcsid_player_c = |
3 | * "$Id: player.c,v 1.1.1.3 2006/03/15 14:05:37 elmex Exp $"; |
3 | * "$Id: player.c,v 1.19 2006/06/02 01:32:36 pippijn Exp $"; |
4 | */ |
4 | */ |
5 | |
5 | |
6 | /* |
6 | /* |
7 | CrossFire, A Multiplayer game for X-windows |
7 | CrossFire, A Multiplayer game for X-windows |
8 | |
8 | |
… | |
… | |
37 | #include <living.h> |
37 | #include <living.h> |
38 | #include <object.h> |
38 | #include <object.h> |
39 | #include <spells.h> |
39 | #include <spells.h> |
40 | #include <skills.h> |
40 | #include <skills.h> |
41 | #include <newclient.h> |
41 | #include <newclient.h> |
|
|
42 | |
|
|
43 | #ifdef COZY_SERVER |
|
|
44 | extern int same_party (partylist *a, partylist *b); |
|
|
45 | #endif |
42 | |
46 | |
43 | player *find_player(const char *plname) |
47 | player *find_player(const char *plname) |
44 | { |
48 | { |
45 | player *pl; |
49 | player *pl; |
46 | for(pl=first_player;pl!=NULL;pl=pl->next) |
50 | for(pl=first_player;pl!=NULL;pl=pl->next) |
… | |
… | |
145 | continue; |
149 | continue; |
146 | if ( *buf =='%'){ /* send one news */ |
150 | if ( *buf =='%'){ /* send one news */ |
147 | if (size>0) |
151 | if (size>0) |
148 | draw_ext_info_format(NDI_UNIQUE | NDI_GREEN, 0, op, |
152 | draw_ext_info_format(NDI_UNIQUE | NDI_GREEN, 0, op, |
149 | MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_NEWS, |
153 | MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_NEWS, |
150 | "!! informations: %s\n%s", |
154 | "INFORMATION: %s\n%s", |
151 | "%s\n%s", |
155 | "%s\n%s", |
152 | subject, news); /*send previously read news*/ |
156 | subject, news); /*send previously read news*/ |
153 | strcpy(subject,buf+1); |
157 | strcpy(subject,buf+1); |
154 | strip_endline(subject); |
158 | strip_endline(subject); |
155 | size=0; |
159 | size=0; |
… | |
… | |
166 | } |
170 | } |
167 | } |
171 | } |
168 | |
172 | |
169 | draw_ext_info_format(NDI_UNIQUE | NDI_GREEN, 0, op, |
173 | draw_ext_info_format(NDI_UNIQUE | NDI_GREEN, 0, op, |
170 | MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_NEWS, |
174 | MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_NEWS, |
171 | "!! informations: %s\n%s\n", |
175 | "INFORMATION: %s\n%s\n", |
172 | "%s\n%s", |
176 | "%s\n%s", |
173 | subject, news); |
177 | subject, news); |
174 | close_and_delete(fp, comp); |
178 | close_and_delete(fp, comp); |
175 | } |
179 | } |
176 | |
180 | |
… | |
… | |
224 | } |
228 | } |
225 | |
229 | |
226 | /* Clears basically the entire player structure except |
230 | /* Clears basically the entire player structure except |
227 | * for next and socket. |
231 | * for next and socket. |
228 | */ |
232 | */ |
229 | memset((void*)((char*)p + offsetof(player, maplevel)), 0, |
233 | memset((void*)((char*)p + offsetof(player, ob)), 0, |
230 | sizeof(player) - offsetof(player, maplevel)); |
234 | sizeof(player) - offsetof(player, ob)); |
231 | |
235 | |
232 | /* There are some elements we want initialized to non zero value - |
236 | /* There are some elements we want initialized to non zero value - |
233 | * we deal with that below this point. |
237 | * we deal with that below this point. |
234 | */ |
238 | */ |
235 | p->party=NULL; |
239 | p->party=NULL; |
… | |
… | |
260 | p->gen_sp_armour=10; |
264 | p->gen_sp_armour=10; |
261 | p->last_speed= -1; |
265 | p->last_speed= -1; |
262 | p->shoottype=range_none; |
266 | p->shoottype=range_none; |
263 | p->bowtype=bow_normal; |
267 | p->bowtype=bow_normal; |
264 | p->petmode=pet_normal; |
268 | p->petmode=pet_normal; |
265 | p->listening=9; |
269 | p->listening=10; |
|
|
270 | p->usekeys=containers; |
266 | p->last_weapon_sp= -1; |
271 | p->last_weapon_sp= -1; |
267 | p->peaceful=1; /* default peaceful */ |
272 | p->peaceful=1; /* default peaceful */ |
268 | p->do_los=1; |
273 | p->do_los=1; |
269 | p->explore=0; |
274 | p->explore=0; |
270 | p->no_shout=0; /* default can shout */ |
275 | p->no_shout=0; /* default can shout */ |
… | |
… | |
312 | |
317 | |
313 | int add_player(NewSocket *ns) { |
318 | int add_player(NewSocket *ns) { |
314 | player *p; |
319 | player *p; |
315 | |
320 | |
316 | p=get_player(NULL); |
321 | p=get_player(NULL); |
317 | memcpy(&p->socket, ns, sizeof(NewSocket)); |
322 | p->socket = *ns; |
318 | p->socket.faces_sent = malloc(p->socket.faces_sent_len*sizeof(*p->socket.faces_sent)); |
323 | p->socket.faces_sent = malloc(p->socket.faces_sent_len*sizeof(*p->socket.faces_sent)); |
319 | if(p->socket.faces_sent == NULL) |
324 | if(p->socket.faces_sent == NULL) |
320 | fatal(OUT_OF_MEMORY); |
325 | fatal(OUT_OF_MEMORY); |
321 | memcpy(p->socket.faces_sent, ns->faces_sent, p->socket.faces_sent_len*sizeof(*p->socket.faces_sent)); |
326 | memcpy(p->socket.faces_sent, ns->faces_sent, p->socket.faces_sent_len*sizeof(*p->socket.faces_sent)); |
322 | /* Needed because the socket we just copied over needs to be cleared. |
327 | /* Needed because the socket we just copied over needs to be cleared. |
… | |
… | |
397 | op=ol->ob; |
402 | op=ol->ob; |
398 | lastdist=rv.distance; |
403 | lastdist=rv.distance; |
399 | } |
404 | } |
400 | } |
405 | } |
401 | for (pl=first_player; pl != NULL; pl=pl->next) { |
406 | for (pl=first_player; pl != NULL; pl=pl->next) { |
402 | if (on_same_map(mon, pl->ob)&& can_detect_enemy(mon, pl->ob,&rv)) { |
407 | if (can_detect_enemy(mon, pl->ob,&rv)) { |
403 | |
408 | |
404 | if(lastdist>rv.distance) { |
409 | if(lastdist>rv.distance) { |
405 | op=pl->ob; |
410 | op=pl->ob; |
406 | lastdist=rv.distance; |
411 | lastdist=rv.distance; |
407 | } |
412 | } |
… | |
… | |
946 | } |
951 | } |
947 | return 0; |
952 | return 0; |
948 | } |
953 | } |
949 | |
954 | |
950 | /* This function takes the key that is passed, and does the |
955 | /* This function takes the key that is passed, and does the |
951 | * appropriate action with it (change class, or other things. |
956 | * appropriate action with it (change race, or other things). |
|
|
957 | * The function name is for historical reasons - now we have |
|
|
958 | * separate race and class; this actually changes the RACE, |
|
|
959 | * not the class. |
952 | */ |
960 | */ |
953 | |
961 | |
954 | int key_change_class(object *op, char key) |
962 | int key_change_class(object *op, char key) |
955 | { |
963 | { |
956 | int tmp_loop; |
964 | int tmp_loop; |
957 | |
965 | |
958 | if(key=='q'||key=='Q') { |
966 | if(key=='q'||key=='Q') { |
959 | remove_ob(op); |
967 | remove_ob(op); |
960 | play_again(op); |
968 | play_again(op); |
961 | return 0; |
969 | return 0; |
… | |
… | |
992 | CLEAR_FLAG(op, FLAG_WIZ); |
1000 | CLEAR_FLAG(op, FLAG_WIZ); |
993 | give_initial_items(op,op->randomitems); |
1001 | give_initial_items(op,op->randomitems); |
994 | link_player_skills(op); |
1002 | link_player_skills(op); |
995 | esrv_send_inventory(op, op); |
1003 | esrv_send_inventory(op, op); |
996 | fix_player(op); |
1004 | fix_player(op); |
|
|
1005 | |
|
|
1006 | /* This moves the player to a different start map, if there |
|
|
1007 | * is one for this race |
|
|
1008 | */ |
|
|
1009 | if(*first_map_ext_path) { |
|
|
1010 | object *tmp; |
|
|
1011 | mapstruct *oldmap = op->map; |
|
|
1012 | char mapname[MAX_BUF]; |
|
|
1013 | snprintf(mapname, MAX_BUF-1, "%s/%s", |
|
|
1014 | first_map_ext_path, op->arch->name); |
|
|
1015 | tmp=get_object(); |
|
|
1016 | EXIT_PATH(tmp) = add_string(mapname); |
|
|
1017 | EXIT_X(tmp) = op->x; |
|
|
1018 | EXIT_Y(tmp) = op->y; |
|
|
1019 | enter_exit(op,tmp); /* we don't really care if it succeeded; |
|
|
1020 | * if the map isn't there, then stay on the |
|
|
1021 | * default initial map */ |
|
|
1022 | free_object(tmp); |
|
|
1023 | } else { |
|
|
1024 | LOG(llevDebug,"first_map_ext_path not set\n"); |
|
|
1025 | } |
997 | return 0; |
1026 | return 0; |
998 | } |
1027 | } |
999 | |
1028 | |
1000 | /* Following actually changes the class - this is the default command |
1029 | /* Following actually changes the race - this is the default command |
1001 | * if we don't match with one of the options above. |
1030 | * if we don't match with one of the options above. |
1002 | */ |
1031 | */ |
1003 | |
1032 | |
1004 | tmp_loop = 0; |
1033 | tmp_loop = 0; |
1005 | while(!tmp_loop) { |
1034 | while(!tmp_loop) { |
… | |
… | |
2060 | |
2089 | |
2061 | /* If the creature is a pet, push it even if the player is not |
2090 | /* If the creature is a pet, push it even if the player is not |
2062 | * peaceful. Our assumption is the creature is a pet if the |
2091 | * peaceful. Our assumption is the creature is a pet if the |
2063 | * player owns it and it is either friendly or unagressive. |
2092 | * player owns it and it is either friendly or unagressive. |
2064 | */ |
2093 | */ |
2065 | if ((op->type==PLAYER) && get_owner(mon)==op && |
2094 | if ((op->type==PLAYER) |
|
|
2095 | #if COZY_SERVER |
|
|
2096 | && |
|
|
2097 | ( |
|
|
2098 | (get_owner(mon) && get_owner(mon)->contr |
|
|
2099 | && same_party (get_owner(mon)->contr->party, op->contr->party)) |
|
|
2100 | || get_owner(mon) == op |
|
|
2101 | ) |
|
|
2102 | #else |
|
|
2103 | && get_owner(mon)==op |
|
|
2104 | #endif |
2066 | (QUERY_FLAG(mon,FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY))) |
2105 | && (QUERY_FLAG(mon,FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY))) |
2067 | { |
2106 | { |
2068 | /* If we're braced, we don't want to switch places with it */ |
2107 | /* If we're braced, we don't want to switch places with it */ |
2069 | if (op->contr->braced) return; |
2108 | if (op->contr->braced) return; |
2070 | play_sound_map(tpl->map, tpl->x, tpl->y, SOUND_PUSH_PLAYER); |
2109 | play_sound_map(tpl->map, tpl->x, tpl->y, SOUND_PUSH_PLAYER); |
2071 | (void) push_ob(mon,dir,op); |
2110 | (void) push_ob(mon,dir,op); |
… | |
… | |
2078 | * someone, but put it inside this loop so that you won't |
2117 | * someone, but put it inside this loop so that you won't |
2079 | * attack them either. |
2118 | * attack them either. |
2080 | */ |
2119 | */ |
2081 | if ((mon->type==PLAYER || mon->enemy != op) && |
2120 | if ((mon->type==PLAYER || mon->enemy != op) && |
2082 | (mon->type==PLAYER || QUERY_FLAG(mon,FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY)) && |
2121 | (mon->type==PLAYER || QUERY_FLAG(mon,FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY)) && |
2083 | (op->contr->peaceful && !on_battleground)) { |
2122 | ( |
|
|
2123 | #ifdef PROHIBIT_PLAYERKILL |
|
|
2124 | (op->contr->peaceful || (mon->type == PLAYER && mon->contr->peaceful)) && |
|
|
2125 | #else |
|
|
2126 | op->contr->peaceful && |
|
|
2127 | #endif |
|
|
2128 | !on_battleground |
|
|
2129 | )) { |
2084 | if (!op->contr->braced) { |
2130 | if (!op->contr->braced) { |
2085 | play_sound_map(tpl->map, tpl->x, tpl->y, SOUND_PUSH_PLAYER); |
2131 | play_sound_map(tpl->map, tpl->x, tpl->y, SOUND_PUSH_PLAYER); |
2086 | (void) push_ob(mon,dir,op); |
2132 | (void) push_ob(mon,dir,op); |
2087 | } else { |
2133 | } else { |
2088 | new_draw_info(0, 0,op,"You withhold your attack"); |
2134 | new_draw_info(0, 0,op,"You withhold your attack"); |
… | |
… | |
2216 | */ |
2262 | */ |
2217 | int handle_newcs_player(object *op) |
2263 | int handle_newcs_player(object *op) |
2218 | { |
2264 | { |
2219 | if (op->contr->hidden) { |
2265 | if (op->contr->hidden) { |
2220 | op->invisible = 1000; |
2266 | op->invisible = 1000; |
2221 | /* the socket code flasehs the player visible/invisible |
2267 | /* the socket code flashes the player visible/invisible |
2222 | * depending on the value if invisible, so we need to |
2268 | * depending on the value of invisible, so we need to |
2223 | * alternate it here for it to work correctly. |
2269 | * alternate it here for it to work correctly. |
2224 | */ |
2270 | */ |
2225 | if (pticks & 2) op->invisible--; |
2271 | if (pticks & 2) op->invisible--; |
2226 | } |
2272 | } |
2227 | else if(op->invisible&&!(QUERY_FLAG(op,FLAG_MAKE_INVIS))) { |
2273 | else if(op->invisible&&!(QUERY_FLAG(op,FLAG_MAKE_INVIS))) { |
… | |
… | |
2495 | } |
2541 | } |
2496 | } |
2542 | } |
2497 | |
2543 | |
2498 | /* Digestion */ |
2544 | /* Digestion */ |
2499 | if(--op->last_eat<0) { |
2545 | if(--op->last_eat<0) { |
|
|
2546 | #ifdef COZY_SERVER |
|
|
2547 | int dg = op->contr->digestion>=0 && op->contr->digestion<2 ? 2 : op->contr->digestion; |
|
|
2548 | int bonus=dg>0?dg:0, |
|
|
2549 | penalty=dg<0?-dg:0; |
|
|
2550 | #else |
2500 | int bonus=op->contr->digestion>0?op->contr->digestion:0, |
2551 | int bonus=op->contr->digestion>0?op->contr->digestion:0, |
2501 | penalty=op->contr->digestion<0?-op->contr->digestion:0; |
2552 | penalty=op->contr->digestion<0?-op->contr->digestion:0; |
|
|
2553 | #endif |
|
|
2554 | |
2502 | if(op->contr->gen_hp > 0) |
2555 | if(op->contr->gen_hp > 0) |
2503 | op->last_eat=25*(1+bonus)/(op->contr->gen_hp+penalty+1); |
2556 | op->last_eat=25*(1+bonus)/(op->contr->gen_hp+penalty+1); |
2504 | else |
2557 | else |
2505 | op->last_eat=25*(1+bonus)/(penalty +1); |
2558 | op->last_eat=25*(1+bonus)/(penalty +1); |
2506 | /* dms do not consume food */ |
2559 | /* dms do not consume food */ |
… | |
… | |
2619 | |
2672 | |
2620 | /* Lauwenmark: Handle for plugin death event */ |
2673 | /* Lauwenmark: Handle for plugin death event */ |
2621 | if (execute_event(op, EVENT_DEATH,NULL,NULL,NULL,SCRIPT_FIX_ALL) != 0) |
2674 | if (execute_event(op, EVENT_DEATH,NULL,NULL,NULL,SCRIPT_FIX_ALL) != 0) |
2622 | return; |
2675 | return; |
2623 | |
2676 | |
|
|
2677 | command_kill_pets (op, 0); |
|
|
2678 | |
2624 | /* Lauwenmark: Handle for the global death event */ |
2679 | /* Lauwenmark: Handle for the global death event */ |
2625 | execute_global_event(EVENT_PLAYER_DEATH, op); |
2680 | execute_global_event(EVENT_PLAYER_DEATH, op); |
2626 | if(op->stats.food<0) { |
2681 | if(op->stats.food<0) { |
2627 | if (op->contr->explore) { |
2682 | if (op->contr->explore) { |
2628 | new_draw_info(NDI_UNIQUE, 0,op,"You would have starved, but you are"); |
2683 | new_draw_info(NDI_UNIQUE, 0,op,"You would have starved, but you are"); |
… | |
… | |
2656 | |
2711 | |
2657 | /* Basically two ways to go - remove a stat permanently, or just |
2712 | /* Basically two ways to go - remove a stat permanently, or just |
2658 | * make it depletion. This bunch of code deals with that aspect |
2713 | * make it depletion. This bunch of code deals with that aspect |
2659 | * of death. |
2714 | * of death. |
2660 | */ |
2715 | */ |
2661 | |
2716 | #ifndef COZY_SERVER |
2662 | if (settings.balanced_stat_loss) { |
2717 | if (settings.balanced_stat_loss) { |
2663 | /* If stat loss is permanent, lose one stat only. */ |
2718 | /* If stat loss is permanent, lose one stat only. */ |
2664 | /* Lower level chars don't lose as many stats because they suffer |
2719 | /* Lower level chars don't lose as many stats because they suffer |
2665 | more if they do. */ |
2720 | more if they do. */ |
2666 | /* Higher level characters can afford things such as potions of |
2721 | /* Higher level characters can afford things such as potions of |
… | |
… | |
2675 | num_stats_lose = 1; |
2730 | num_stats_lose = 1; |
2676 | } |
2731 | } |
2677 | lost_a_stat = 0; |
2732 | lost_a_stat = 0; |
2678 | |
2733 | |
2679 | for (z=0; z<num_stats_lose; z++) { |
2734 | for (z=0; z<num_stats_lose; z++) { |
|
|
2735 | i = RANDOM() % NUM_STATS; |
|
|
2736 | |
2680 | if (settings.stat_loss_on_death) { |
2737 | if (settings.stat_loss_on_death) { |
2681 | /* Pick a random stat and take a point off it. Tell the player |
2738 | /* Pick a random stat and take a point off it. Tell the player |
2682 | * what he lost. |
2739 | * what he lost. |
2683 | */ |
2740 | */ |
2684 | i = RANDOM() % 7; |
|
|
2685 | change_attr_value(&(op->stats), i,-1); |
2741 | change_attr_value(&(op->stats), i,-1); |
2686 | check_stat_bounds(&(op->stats)); |
2742 | check_stat_bounds(&(op->stats)); |
2687 | change_attr_value(&(op->contr->orig_stats), i,-1); |
2743 | change_attr_value(&(op->contr->orig_stats), i,-1); |
2688 | check_stat_bounds(&(op->contr->orig_stats)); |
2744 | check_stat_bounds(&(op->contr->orig_stats)); |
2689 | new_draw_info(NDI_UNIQUE, 0,op, lose_msg[i]); |
2745 | new_draw_info(NDI_UNIQUE, 0,op, lose_msg[i]); |
… | |
… | |
2691 | } else { |
2747 | } else { |
2692 | /* deplete a stat */ |
2748 | /* deplete a stat */ |
2693 | archetype *deparch=find_archetype("depletion"); |
2749 | archetype *deparch=find_archetype("depletion"); |
2694 | object *dep; |
2750 | object *dep; |
2695 | |
2751 | |
2696 | i = RANDOM() % 7; |
|
|
2697 | dep = present_arch_in_ob(deparch,op); |
2752 | dep = present_arch_in_ob(deparch,op); |
2698 | if(!dep) { |
2753 | if(!dep) { |
2699 | dep = arch_to_object(deparch); |
2754 | dep = arch_to_object(deparch); |
2700 | insert_ob_in_ob(dep, op); |
2755 | insert_ob_in_ob(dep, op); |
2701 | } |
2756 | } |
… | |
… | |
2757 | " you.", god); |
2812 | " you.", god); |
2758 | else |
2813 | else |
2759 | new_draw_info(NDI_UNIQUE, 0, op, "For a brief moment you" |
2814 | new_draw_info(NDI_UNIQUE, 0, op, "For a brief moment you" |
2760 | " feel a holy presence protecting you."); |
2815 | " feel a holy presence protecting you."); |
2761 | } |
2816 | } |
|
|
2817 | #endif |
|
|
2818 | new_draw_info(NDI_UNIQUE, 0, op, "For a brief moment you" |
|
|
2819 | " feel a holy presence protecting you from losing yourself completely."); |
2762 | |
2820 | |
2763 | /* Put a gravestone up where the character 'almost' died. List the |
2821 | /* Put a gravestone up where the character 'almost' died. List the |
2764 | * exp loss on the stone. |
2822 | * exp loss on the stone. |
2765 | */ |
2823 | */ |
2766 | tmp=arch_to_object(find_archetype("gravestone")); |
2824 | tmp=arch_to_object(find_archetype("gravestone")); |