1 | /* |
1 | /* |
2 | * static char *rcsid_player_c = |
2 | * static char *rcsid_player_c = |
3 | * "$Id: player.c,v 1.1 2006/02/03 07:14:35 root Exp $"; |
3 | * "$Id: player.c,v 1.8 2006/03/16 22:47:22 root 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 | |
… | |
… | |
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 | |
42 | |
|
|
43 | #ifdef COZY_SERVER |
|
|
44 | extern int same_party (partylist *a, partylist *b); |
|
|
45 | #endif |
|
|
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) |
47 | { |
51 | { |
… | |
… | |
73 | } |
77 | } |
74 | } |
78 | } |
75 | return found; |
79 | return found; |
76 | } |
80 | } |
77 | |
81 | |
78 | void display_motd(object *op) { |
82 | void display_motd(const object *op) { |
79 | char buf[MAX_BUF]; |
83 | char buf[MAX_BUF]; |
80 | char motd[HUGE_BUF]; |
84 | char motd[HUGE_BUF]; |
81 | FILE *fp; |
85 | FILE *fp; |
82 | int comp; |
86 | int comp; |
83 | int size; |
87 | int size; |
… | |
… | |
96 | } |
100 | } |
97 | draw_ext_info(NDI_UNIQUE | NDI_GREEN, 0, op, MSG_TYPE_MOTD, MSG_SUBTYPE_NONE, motd, NULL); |
101 | draw_ext_info(NDI_UNIQUE | NDI_GREEN, 0, op, MSG_TYPE_MOTD, MSG_SUBTYPE_NONE, motd, NULL); |
98 | close_and_delete(fp, comp); |
102 | close_and_delete(fp, comp); |
99 | } |
103 | } |
100 | |
104 | |
101 | void send_rules(object *op) { |
105 | void send_rules(const object *op) { |
102 | char buf[MAX_BUF]; |
106 | char buf[MAX_BUF]; |
103 | char rules[HUGE_BUF]; |
107 | char rules[HUGE_BUF]; |
104 | FILE *fp; |
108 | FILE *fp; |
105 | int comp; |
109 | int comp; |
106 | int size; |
110 | int size; |
… | |
… | |
124 | } |
128 | } |
125 | draw_ext_info(NDI_UNIQUE | NDI_GREEN, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_RULES, rules, NULL); |
129 | draw_ext_info(NDI_UNIQUE | NDI_GREEN, 0, op, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_RULES, rules, NULL); |
126 | close_and_delete(fp, comp); |
130 | close_and_delete(fp, comp); |
127 | } |
131 | } |
128 | |
132 | |
129 | void send_news(object *op) { |
133 | void send_news(const object *op) { |
130 | char buf[MAX_BUF]; |
134 | char buf[MAX_BUF]; |
131 | char news[HUGE_BUF]; |
135 | char news[HUGE_BUF]; |
132 | char subject[MAX_BUF]; |
136 | char subject[MAX_BUF]; |
133 | FILE *fp; |
137 | FILE *fp; |
134 | int comp; |
138 | int comp; |
… | |
… | |
249 | op->speed_left=0.5; |
253 | op->speed_left=0.5; |
250 | op->speed=1.0; |
254 | op->speed=1.0; |
251 | op->direction=5; /* So player faces south */ |
255 | op->direction=5; /* So player faces south */ |
252 | op->stats.wc=2; |
256 | op->stats.wc=2; |
253 | op->run_away = 25; /* Then we panick... */ |
257 | op->run_away = 25; /* Then we panick... */ |
|
|
258 | p->socket.monitor_spells = 0; /* Needed because esrv_update_spells( ) gets called by roll_stats */ |
254 | |
259 | |
255 | roll_stats(op); |
260 | roll_stats(op); |
256 | p->state=ST_ROLL_STAT; |
261 | p->state=ST_ROLL_STAT; |
257 | clear_los(op); |
262 | clear_los(op); |
258 | |
263 | |
… | |
… | |
396 | op=ol->ob; |
401 | op=ol->ob; |
397 | lastdist=rv.distance; |
402 | lastdist=rv.distance; |
398 | } |
403 | } |
399 | } |
404 | } |
400 | for (pl=first_player; pl != NULL; pl=pl->next) { |
405 | for (pl=first_player; pl != NULL; pl=pl->next) { |
401 | if (on_same_map(mon, pl->ob)&& can_detect_enemy(mon, pl->ob,&rv)) { |
406 | if (can_detect_enemy(mon, pl->ob,&rv)) { |
402 | |
407 | |
403 | if(lastdist>rv.distance) { |
408 | if(lastdist>rv.distance) { |
404 | op=pl->ob; |
409 | op=pl->ob; |
405 | lastdist=rv.distance; |
410 | lastdist=rv.distance; |
406 | } |
411 | } |
… | |
… | |
634 | if(op->type==SPELL) { |
639 | if(op->type==SPELL) { |
635 | remove_ob(op); |
640 | remove_ob(op); |
636 | free_object(op); |
641 | free_object(op); |
637 | continue; |
642 | continue; |
638 | } |
643 | } |
639 | if(op->type==SKILL) { |
644 | else if(op->type==SKILL) { |
640 | SET_FLAG(op, FLAG_CAN_USE_SKILL); |
645 | SET_FLAG(op, FLAG_CAN_USE_SKILL); |
641 | op->stats.exp = 0; |
646 | op->stats.exp = 0; |
642 | op->level = 1; |
647 | op->level = 1; |
643 | } |
648 | } |
|
|
649 | /* lock all 'normal items by default */ |
|
|
650 | else SET_FLAG(op, FLAG_INV_LOCKED); |
644 | } /* for loop of objects in player inv */ |
651 | } /* for loop of objects in player inv */ |
645 | |
652 | |
646 | /* Need to set up the skill pointers */ |
653 | /* Need to set up the skill pointers */ |
647 | link_player_skills(pl); |
654 | link_player_skills(pl); |
648 | } |
655 | } |
… | |
… | |
1983 | * going to try and move (not fire weapons). |
1990 | * going to try and move (not fire weapons). |
1984 | */ |
1991 | */ |
1985 | |
1992 | |
1986 | void move_player_attack(object *op, int dir) |
1993 | void move_player_attack(object *op, int dir) |
1987 | { |
1994 | { |
1988 | object *tmp, *mon; |
1995 | object *tmp, *mon, *tpl; |
1989 | sint16 nx=freearr_x[dir]+op->x,ny=freearr_y[dir]+op->y; |
1996 | sint16 nx, ny; |
1990 | int on_battleground; |
1997 | int on_battleground; |
1991 | mapstruct *m; |
1998 | mapstruct *m; |
1992 | |
1999 | |
|
|
2000 | if (op->contr->transport) tpl = op->contr->transport; |
|
|
2001 | else tpl = op; |
|
|
2002 | nx=freearr_x[dir]+tpl->x; |
|
|
2003 | ny=freearr_y[dir]+tpl->y; |
|
|
2004 | |
1993 | on_battleground = op_on_battleground(op, NULL, NULL); |
2005 | on_battleground = op_on_battleground(tpl, NULL, NULL); |
1994 | |
2006 | |
1995 | /* If braced, or can't move to the square, and it is not out of the |
2007 | /* If braced, or can't move to the square, and it is not out of the |
1996 | * map, attack it. Note order of if statement is important - don't |
2008 | * map, attack it. Note order of if statement is important - don't |
1997 | * want to be calling move_ob if braced, because move_ob will move the |
2009 | * want to be calling move_ob if braced, because move_ob will move the |
1998 | * player. This is a pretty nasty hack, because if we could |
2010 | * player. This is a pretty nasty hack, because if we could |
1999 | * move to some space, it then means that if we are braced, we should |
2011 | * move to some space, it then means that if we are braced, we should |
2000 | * do nothing at all. As it is, if we are braced, we go through |
2012 | * do nothing at all. As it is, if we are braced, we go through |
2001 | * quite a bit of processing. However, it probably is less than what |
2013 | * quite a bit of processing. However, it probably is less than what |
2002 | * move_ob uses. |
2014 | * move_ob uses. |
2003 | */ |
2015 | */ |
2004 | if ((op->contr->braced || !move_ob(op,dir,op)) && !out_of_map(op->map,nx,ny)) { |
2016 | if ((op->contr->braced || !move_ob(tpl,dir,tpl)) && !out_of_map(tpl->map,nx,ny)) { |
2005 | if (OUT_OF_REAL_MAP(op->map, nx, ny)) { |
2017 | if (OUT_OF_REAL_MAP(tpl->map, nx, ny)) { |
2006 | m = get_map_from_coord(op->map, &nx, &ny); |
2018 | m = get_map_from_coord(tpl->map, &nx, &ny); |
2007 | if (!m) return; /* Don't think this should happen */ |
2019 | if (!m) return; /* Don't think this should happen */ |
2008 | } |
2020 | } |
2009 | else m =op->map; |
2021 | else m =tpl->map; |
2010 | |
2022 | |
2011 | if ((tmp=get_map_ob(m,nx,ny))==NULL) { |
2023 | if ((tmp=get_map_ob(m,nx,ny))==NULL) { |
2012 | /* LOG(llevError,"player_move_attack: get_map_ob returns NULL, but player can not more there.\n");*/ |
2024 | /* LOG(llevError,"player_move_attack: get_map_ob returns NULL, but player can not more there.\n");*/ |
2013 | return; |
2025 | return; |
2014 | } |
2026 | } |
… | |
… | |
2052 | |
2064 | |
2053 | /* If the creature is a pet, push it even if the player is not |
2065 | /* If the creature is a pet, push it even if the player is not |
2054 | * peaceful. Our assumption is the creature is a pet if the |
2066 | * peaceful. Our assumption is the creature is a pet if the |
2055 | * player owns it and it is either friendly or unagressive. |
2067 | * player owns it and it is either friendly or unagressive. |
2056 | */ |
2068 | */ |
2057 | if ((op->type==PLAYER) && get_owner(mon)==op && |
2069 | if ((op->type==PLAYER) |
|
|
2070 | #if COZY_SERVER |
|
|
2071 | && |
|
|
2072 | ( |
|
|
2073 | (get_owner(mon) && get_owner(mon)->contr |
|
|
2074 | && same_party (get_owner(mon)->contr->party, op->contr->party)) |
|
|
2075 | || get_owner(mon) == op |
|
|
2076 | ) |
|
|
2077 | #else |
|
|
2078 | && get_owner(mon)==op |
|
|
2079 | #endif |
2058 | (QUERY_FLAG(mon,FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY))) |
2080 | && (QUERY_FLAG(mon,FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY))) |
2059 | { |
2081 | { |
2060 | /* If we're braced, we don't want to switch places with it */ |
2082 | /* If we're braced, we don't want to switch places with it */ |
2061 | if (op->contr->braced) return; |
2083 | if (op->contr->braced) return; |
2062 | play_sound_map(op->map, op->x, op->y, SOUND_PUSH_PLAYER); |
2084 | play_sound_map(tpl->map, tpl->x, tpl->y, SOUND_PUSH_PLAYER); |
2063 | (void) push_ob(mon,dir,op); |
2085 | (void) push_ob(mon,dir,op); |
2064 | if(op->contr->tmp_invis||op->hide) make_visible(op); |
2086 | if(op->contr->tmp_invis||op->hide) make_visible(op); |
2065 | return; |
2087 | return; |
2066 | } |
2088 | } |
2067 | |
2089 | |
… | |
… | |
2072 | */ |
2094 | */ |
2073 | if ((mon->type==PLAYER || mon->enemy != op) && |
2095 | if ((mon->type==PLAYER || mon->enemy != op) && |
2074 | (mon->type==PLAYER || QUERY_FLAG(mon,FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY)) && |
2096 | (mon->type==PLAYER || QUERY_FLAG(mon,FLAG_UNAGGRESSIVE) || QUERY_FLAG(mon, FLAG_FRIENDLY)) && |
2075 | (op->contr->peaceful && !on_battleground)) { |
2097 | (op->contr->peaceful && !on_battleground)) { |
2076 | if (!op->contr->braced) { |
2098 | if (!op->contr->braced) { |
2077 | play_sound_map(op->map, op->x, op->y, SOUND_PUSH_PLAYER); |
2099 | play_sound_map(tpl->map, tpl->x, tpl->y, SOUND_PUSH_PLAYER); |
2078 | (void) push_ob(mon,dir,op); |
2100 | (void) push_ob(mon,dir,op); |
2079 | } else { |
2101 | } else { |
2080 | new_draw_info(0, 0,op,"You withhold your attack"); |
2102 | new_draw_info(0, 0,op,"You withhold your attack"); |
2081 | } |
2103 | } |
2082 | if(op->contr->tmp_invis||op->hide) make_visible(op); |
2104 | if(op->contr->tmp_invis||op->hide) make_visible(op); |
… | |
… | |
2131 | } /* if player should attack something */ |
2153 | } /* if player should attack something */ |
2132 | } |
2154 | } |
2133 | |
2155 | |
2134 | int move_player(object *op,int dir) { |
2156 | int move_player(object *op,int dir) { |
2135 | int pick; |
2157 | int pick; |
|
|
2158 | object *transport = op->contr->transport; |
2136 | |
2159 | |
2137 | if(op->map == NULL || op->map->in_memory != MAP_IN_MEMORY) |
2160 | if(!transport && (op->map == NULL || op->map->in_memory != MAP_IN_MEMORY)) |
2138 | return 0; |
2161 | return 0; |
2139 | |
2162 | |
2140 | /* Sanity check: make sure dir is valid */ |
2163 | /* Sanity check: make sure dir is valid */ |
2141 | if ( ( dir < 0 ) || ( dir >= 9 ) ) { |
2164 | if ( ( dir < 0 ) || ( dir >= 9 ) ) { |
2142 | LOG( llevError, "move_player: invalid direction %d\n", dir); |
2165 | LOG( llevError, "move_player: invalid direction %d\n", dir); |
… | |
… | |
2147 | if(QUERY_FLAG(op,FLAG_CONFUSED) && dir) |
2170 | if(QUERY_FLAG(op,FLAG_CONFUSED) && dir) |
2148 | dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2); |
2171 | dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2); |
2149 | |
2172 | |
2150 | op->facing = dir; |
2173 | op->facing = dir; |
2151 | |
2174 | |
2152 | if(op->hide) do_hidden_move(op); |
2175 | if(!transport && op->hide) do_hidden_move(op); |
|
|
2176 | |
|
|
2177 | if (transport) { |
|
|
2178 | /* transport->contr is set up for the person in charge of the boat. |
|
|
2179 | * if that isn't this person, he can't steer it, etc |
|
|
2180 | */ |
|
|
2181 | if (transport->contr != op->contr) return 0; |
|
|
2182 | |
|
|
2183 | /* Transport can't move. But update dir so it at least |
|
|
2184 | * will point in the same direction if player is running. |
|
|
2185 | */ |
|
|
2186 | if (transport->speed_left < 0.0) { |
|
|
2187 | transport->direction = dir; |
|
|
2188 | op->direction = dir; |
|
|
2189 | return 0; |
|
|
2190 | } |
|
|
2191 | /* Remove transport speed. Give player just a little speed - |
|
|
2192 | * enough so that they will get an action again quickly. |
|
|
2193 | * |
|
|
2194 | */ |
|
|
2195 | transport->speed_left -= 1.0; |
|
|
2196 | if (op->speed_left < 0.0) op->speed_left = -0.01; |
|
|
2197 | |
|
|
2198 | } |
2153 | |
2199 | |
2154 | if(op->contr->fire_on) { |
2200 | if(op->contr->fire_on) { |
2155 | fire(op,dir); |
2201 | fire(op,dir); |
2156 | } |
2202 | } |
2157 | else move_player_attack(op,dir); |
2203 | else move_player_attack(op,dir); |
… | |
… | |
2169 | } |
2215 | } |
2170 | /* Update how the player looks. Use the facing, so direction may |
2216 | /* Update how the player looks. Use the facing, so direction may |
2171 | * get reset to zero. This allows for full animation capabilities |
2217 | * get reset to zero. This allows for full animation capabilities |
2172 | * for players. |
2218 | * for players. |
2173 | */ |
2219 | */ |
2174 | animate_object(op, op->facing); |
2220 | if (!transport) animate_object(op, op->facing); |
2175 | return 0; |
2221 | return 0; |
2176 | } |
2222 | } |
2177 | |
2223 | |
2178 | /* This is similar to handle_player, below, but is only used by the |
2224 | /* This is similar to handle_player, below, but is only used by the |
2179 | * new client/server stuff. |
2225 | * new client/server stuff. |
… | |
… | |
2184 | */ |
2230 | */ |
2185 | int handle_newcs_player(object *op) |
2231 | int handle_newcs_player(object *op) |
2186 | { |
2232 | { |
2187 | if (op->contr->hidden) { |
2233 | if (op->contr->hidden) { |
2188 | op->invisible = 1000; |
2234 | op->invisible = 1000; |
2189 | /* the socket code flasehs the player visible/invisible |
2235 | /* the socket code flashes the player visible/invisible |
2190 | * depending on the value if invisible, so we need to |
2236 | * depending on the value of invisible, so we need to |
2191 | * alternate it here for it to work correctly. |
2237 | * alternate it here for it to work correctly. |
2192 | */ |
2238 | */ |
2193 | if (pticks & 2) op->invisible--; |
2239 | if (pticks & 2) op->invisible--; |
2194 | } |
2240 | } |
2195 | else if(op->invisible&&!(QUERY_FLAG(op,FLAG_MAKE_INVIS))) { |
2241 | else if(op->invisible&&!(QUERY_FLAG(op,FLAG_MAKE_INVIS))) { |
… | |
… | |
2463 | } |
2509 | } |
2464 | } |
2510 | } |
2465 | |
2511 | |
2466 | /* Digestion */ |
2512 | /* Digestion */ |
2467 | if(--op->last_eat<0) { |
2513 | if(--op->last_eat<0) { |
|
|
2514 | #ifdef COZY_SERVER |
|
|
2515 | int dg = op->contr->digestion>=0 && op->contr->digestion<2 ? 2 : op->contr->digestion; |
|
|
2516 | int bonus=dg>0?dg:0, |
|
|
2517 | penalty=dg<0?-dg:0; |
|
|
2518 | #else |
2468 | int bonus=op->contr->digestion>0?op->contr->digestion:0, |
2519 | int bonus=op->contr->digestion>0?op->contr->digestion:0, |
2469 | penalty=op->contr->digestion<0?-op->contr->digestion:0; |
2520 | penalty=op->contr->digestion<0?-op->contr->digestion:0; |
|
|
2521 | #endif |
|
|
2522 | |
2470 | if(op->contr->gen_hp > 0) |
2523 | if(op->contr->gen_hp > 0) |
2471 | op->last_eat=25*(1+bonus)/(op->contr->gen_hp+penalty+1); |
2524 | op->last_eat=25*(1+bonus)/(op->contr->gen_hp+penalty+1); |
2472 | else |
2525 | else |
2473 | op->last_eat=25*(1+bonus)/(penalty +1); |
2526 | op->last_eat=25*(1+bonus)/(penalty +1); |
2474 | /* dms do not consume food */ |
2527 | /* dms do not consume food */ |
… | |
… | |
2624 | |
2677 | |
2625 | /* Basically two ways to go - remove a stat permanently, or just |
2678 | /* Basically two ways to go - remove a stat permanently, or just |
2626 | * make it depletion. This bunch of code deals with that aspect |
2679 | * make it depletion. This bunch of code deals with that aspect |
2627 | * of death. |
2680 | * of death. |
2628 | */ |
2681 | */ |
2629 | |
2682 | #ifndef COZY_SERVER |
2630 | if (settings.balanced_stat_loss) { |
2683 | if (settings.balanced_stat_loss) { |
2631 | /* If stat loss is permanent, lose one stat only. */ |
2684 | /* If stat loss is permanent, lose one stat only. */ |
2632 | /* Lower level chars don't lose as many stats because they suffer |
2685 | /* Lower level chars don't lose as many stats because they suffer |
2633 | more if they do. */ |
2686 | more if they do. */ |
2634 | /* Higher level characters can afford things such as potions of |
2687 | /* Higher level characters can afford things such as potions of |
… | |
… | |
2647 | for (z=0; z<num_stats_lose; z++) { |
2700 | for (z=0; z<num_stats_lose; z++) { |
2648 | if (settings.stat_loss_on_death) { |
2701 | if (settings.stat_loss_on_death) { |
2649 | /* Pick a random stat and take a point off it. Tell the player |
2702 | /* Pick a random stat and take a point off it. Tell the player |
2650 | * what he lost. |
2703 | * what he lost. |
2651 | */ |
2704 | */ |
2652 | i = RANDOM() % 7; |
2705 | i = RANDOM() % NUM_STATS; |
2653 | change_attr_value(&(op->stats), i,-1); |
2706 | change_attr_value(&(op->stats), i,-1); |
2654 | check_stat_bounds(&(op->stats)); |
2707 | check_stat_bounds(&(op->stats)); |
2655 | change_attr_value(&(op->contr->orig_stats), i,-1); |
2708 | change_attr_value(&(op->contr->orig_stats), i,-1); |
2656 | check_stat_bounds(&(op->contr->orig_stats)); |
2709 | check_stat_bounds(&(op->contr->orig_stats)); |
2657 | new_draw_info(NDI_UNIQUE, 0,op, lose_msg[i]); |
2710 | new_draw_info(NDI_UNIQUE, 0,op, lose_msg[i]); |
… | |
… | |
2725 | " you.", god); |
2778 | " you.", god); |
2726 | else |
2779 | else |
2727 | new_draw_info(NDI_UNIQUE, 0, op, "For a brief moment you" |
2780 | new_draw_info(NDI_UNIQUE, 0, op, "For a brief moment you" |
2728 | " feel a holy presence protecting you."); |
2781 | " feel a holy presence protecting you."); |
2729 | } |
2782 | } |
|
|
2783 | #endif |
|
|
2784 | new_draw_info(NDI_UNIQUE, 0, op, "For a brief moment you" |
|
|
2785 | " feel a holy presence protecting you from losing yourself completely."); |
2730 | |
2786 | |
2731 | /* Put a gravestone up where the character 'almost' died. List the |
2787 | /* Put a gravestone up where the character 'almost' died. List the |
2732 | * exp loss on the stone. |
2788 | * exp loss on the stone. |
2733 | */ |
2789 | */ |
2734 | tmp=arch_to_object(find_archetype("gravestone")); |
2790 | tmp=arch_to_object(find_archetype("gravestone")); |