1 /* $Id$ */
2 /* The server side of the network stuff */
3
4 /* The following is a direct excerpt from the netserver.c
5 * in the XPilot distribution. Much of it is incorrect
6 * in MAngband's case, but most of it is still correct.
7 */
8
9
10
11 /*
12 * This is the server side of the network connnection stuff.
13 *
14 * We try very hard to not let the game be disturbed by
15 * players logging in. Therefore a new connection
16 * passes through several states before it is actively
17 * playing.
18 * First we make a new connection structure available
19 * with a new socket to listen on. This socket port
20 * number is told to the client via the pack mechanism.
21 * In this state the client has to send a packet to this
22 * newly created socket with its name and playing parameters.
23 * If this succeeds the connection advances to its second state.
24 * In this second state the essential server configuration
25 * like the map and so on is transmitted to the client.
26 * If the client has acknowledged all this data then it
27 * advances to the third state, which is the
28 * ready-but-not-playing-yet state. In this state the client
29 * has some time to do its final initializations, like mapping
30 * its user interface windows and so on.
31 * When the client is ready to accept frame updates and process
32 * keyboard events then it sends the start-play packet.
33 * This play packet advances the connection state into the
34 * actively-playing state. A player structure is allocated and
35 * initialized and the other human players are told about this new player.
36 * The newly started client is told about the already playing players and
37 * play has begun.
38 * Apart from these four states there are also two intermediate states.
39 * These intermediate states are entered when the previous state
40 * has filled the reliable data buffer and the client has not
41 * acknowledged all the data yet that is in this reliable data buffer.
42 * They are so called output drain states. Not doing anything else
43 * then waiting until the buffer is empty.
44 * The difference between these two intermediate states is tricky.
45 * The second intermediate state is entered after the
46 * ready-but-not-playing-yet state and before the actively-playing state.
47 * The difference being that in this second intermediate state the client
48 * is already considered an active player by the rest of the server
49 * but should not get frame updates yet until it has acknowledged its last
50 * reliable data.
51 *
52 * Communication between the server and the clients is only done
53 * using UDP datagrams. The first client/serverized version of XPilot
54 * was using TCP only, but this was too unplayable across the Internet,
55 * because TCP is a data stream always sending the next byte.
56 * If a packet gets lost then the server has to wait for a
57 * timeout before a retransmission can occur. This is too slow
58 * for a real-time program like this game, which is more interested
59 * in recent events than in sequenced/reliable events.
60 * Therefore UDP is now used which gives more network control to the
61 * program.
62 * Because some data is considered crucial, like the names of
63 * new players and so on, there also had to be a mechanism which
64 * enabled reliable data transmission. Here this is done by creating
65 * a data stream which is piggybacked on top of the unreliable data
66 * packets. The client acknowledges this reliable data by sending
67 * its byte position in the reliable data stream. So if the client gets
68 * a new reliable data packet and it has not had this data before and
69 * there is also no data packet missing inbetween, then it advances
70 * its byte position and acknowledges this new position to the server.
71 * Otherwise it discards the packet and sends its old byte position
72 * to the server meaning that it detected a packet loss.
73 * The server maintains an acknowledgement timeout timer for each
74 * connection so that it can retransmit a reliable data packet
75 * if the acknowledgement timer expires.
76 */
77
78
79
80 #define SERVER
81
82 #include "angband.h"
83 #include "netserver.h"
84
85 #include <sys/types.h>
86 #include <sys/stat.h>
87 #ifndef WINDOWS
88 #include <sys/wait.h>
89 #include <netinet/in.h>
90 #include <sys/socket.h>
91 #include <netdb.h>
92 #endif
93 #include <errno.h>
94
95
96 /* hack to prevent the floor tile bug on windows xp and windows 2003 machines */
97 //#define FLOORTILEBUG_WORKAROUND
98
99 /* Message to send to client when kicking him out due to starvation while being idle */
100 //#define STARVING_AUTOKICK_MSG "starving auto-kick"
101 #define STARVING_AUTOKICK_MSG format("You were STARVING and idle for %ds, so the game kicked you to prevent death!", STARVE_KICK_TIMER)
102
103 /* Sanity check of client input */
104 #define bad_dir(d) ((d)<0 || (d)>9) /* used for non-targetting actions that require a direction */
105 //#define bad_dir1(d) ((d)<0 || (d)>9+1) /* used for most targetting actions */
bad_dir1(int Ind,char * dir)106 static bool bad_dir1(int Ind, char *dir) {
107 /* paranoia? */
108 if (Ind == -1) return TRUE;
109
110 if (*dir < 0 || *dir > 11) return TRUE;
111 if (*dir == 11) {
112 if (target_okay(Ind)) *dir = 5;
113 }
114 else if (*dir == 10) {
115 if (!target_okay(Ind)) return TRUE;
116 *dir = 5;
117 }
118 return FALSE;
119 }
120 #define bad_dir2(d) ((d)<128 || (d)>137) /* dir + 128; used for manual target positioning */
121 //#define bad_dir3(d) ((d)<-1 || (d)>9+1) /* used for MKEY_SCHOOL activations */
bad_dir3(int Ind,char * dir)122 static bool bad_dir3(int Ind, char *dir) {
123 /* paranoia? */
124 if (Ind == -1) return TRUE;
125
126 if (*dir < -1 || *dir > 11) return TRUE;
127 if (*dir == 11) {
128 if (target_okay(Ind)) *dir = 5;
129 }
130 else if (*dir == 10) {
131 if (!target_okay(Ind)) return TRUE;
132 *dir = 5;
133 }
134 return FALSE;
135 }
136
137
138
139 #if 0
140 static bool validstrings(char *nick, char *real, char *host);
141 #else
142 static bool validstring(char *nick);
143 #endif
144 void validatestring(char *string);
145
146 connection_t **Conn = NULL;
147 static int max_connections = 0;
148 static setup_t Setup;
149 static int (*playing_receive[256])(int ind),
150 (*login_receive[256])(int ind),
151 (*drain_receive[256])(int ind);
152 int login_in_progress;
153 static int num_logins, num_logouts;
154 static long Id;
155 int NumPlayers, NumNonAdminPlayers;
156
157
158 pid_t metapid = 0;
159 int MetaSocket = -1;
160
161 #ifdef NEW_SERVER_CONSOLE
162 int ConsoleSocket = -1;
163 #endif
164 #ifdef SERVER_GWPORT
165 int SGWSocket = -1;
166 #endif
167 #ifdef TOMENET_WORLDS
168 int WorldSocket = -1;
169 #endif
170
171
showtime(void)172 char *showtime(void)
173 {
174 time_t now;
175 struct tm *tmp;
176 static char month_names[13][4] = {
177 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
178 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
179 "Bug"
180 };
181 static char buf[80];
182 /* adding weekdays, basically just for p_printf() - C. Blue */
183 static char day_names[7][4] = {
184 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
185 };
186 time(&now);
187 tmp = localtime(&now);
188 sprintf(buf, "%02d %s (%s) %02d:%02d:%02d",
189 tmp->tm_mday, month_names[tmp->tm_mon], day_names[tmp->tm_wday],
190 tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
191 return buf;
192 }
193
194 /* added for the BBS - C. Blue */
showdate(void)195 char *showdate(void)
196 {
197 time_t now;
198 struct tm *tmp;
199 static char buf[80];
200 time(&now);
201 tmp = localtime(&now);
202 sprintf(buf, "%02d-%02d", tmp->tm_mon + 1, tmp->tm_mday);
203 return buf;
204 }
205
206 /* added for changing seasons via lua cron_24h() - C. Blue */
get_date(int * weekday,int * day,int * month,int * year)207 void get_date(int *weekday, int *day, int *month, int *year) {
208 time_t now;
209 struct tm *tmp;
210 time(&now);
211 tmp = localtime(&now);
212 *weekday = tmp->tm_wday;
213 *day = tmp->tm_mday;
214 *month = tmp->tm_mon + 1;
215 *year = tmp->tm_year + 1900;
216 }
217
add_banlist(char * account,char * ip_addy,char * hostname,int time,char * reason)218 void add_banlist(char *account, char *ip_addy, char *hostname, int time, char *reason) {
219 struct combo_ban *ptr;
220
221 if (!time) return;
222 if (!account && !ip_addy) return;
223
224 ptr = NEW(struct combo_ban);
225 ptr->next = banlist;
226
227 ptr->time = time;
228 if (reason) strcpy(ptr->reason, reason);
229 else ptr->reason[0] = 0;
230 if (hostname) {
231 strncpy(ptr->hostname, hostname, MAX_CHARS);
232 ptr->hostname[MAX_CHARS - 1] = 0;
233 } else ptr->hostname[0] = 0;
234
235 if (reason) s_printf("Banned for %d minutes ('%s'):\n", time, reason);
236 else s_printf("Banned for %d minutes:\n", time);
237 if (account) {
238 strcpy(ptr->acc, account);
239 s_printf(" Connections for %s.\n", ptr->acc, time);
240 } else ptr->acc[0] = 0;
241 if (ip_addy) {
242 strcpy(ptr->ip, ip_addy);
243 s_printf(" Connections from %s.\n", ptr->ip, time);
244 } else ptr->ip[0] = 0;
245
246 banlist = ptr;
247 }
248
249 /*
250 * Initialize the function dispatch tables for the various client
251 * connection states. Some states use the same table.
252 */
Init_receive(void)253 static void Init_receive(void)
254 {
255 int i;
256
257 for (i = 0; i < 256; i++)
258 {
259 login_receive[i] = Receive_undefined;
260 playing_receive[i] = Receive_undefined;
261 drain_receive[i] = Receive_undefined;
262 }
263
264 drain_receive[PKT_QUIT] = Receive_quit;
265 // drain_receive[PKT_ACK] = Receive_ack;
266 drain_receive[PKT_VERIFY] = Receive_discard;
267 drain_receive[PKT_PLAY] = Receive_discard;
268
269 login_receive[PKT_PLAY] = Receive_play;
270 login_receive[PKT_QUIT] = Receive_quit;
271 // login_receive[PKT_ACK] = Receive_ack;
272 login_receive[PKT_VERIFY] = Receive_discard;
273 login_receive[PKT_LOGIN] = Receive_login;
274
275 // playing_receive[PKT_ACK] = Receive_ack;
276 playing_receive[PKT_VERIFY] = Receive_discard;
277 playing_receive[PKT_QUIT] = Receive_quit;
278 playing_receive[PKT_PLAY] = Receive_play;
279 playing_receive[PKT_FILE] = Receive_file;
280
281 playing_receive[PKT_KEEPALIVE] = Receive_keepalive;
282 playing_receive[PKT_WALK] = Receive_walk;
283 playing_receive[PKT_RUN] = Receive_run;
284 playing_receive[PKT_TUNNEL] = Receive_tunnel;
285 playing_receive[PKT_AIM_WAND] = Receive_aim_wand;
286 playing_receive[PKT_DROP] = Receive_drop;
287 playing_receive[PKT_FIRE] = Receive_fire;
288 playing_receive[PKT_STAND] = Receive_stand;
289 playing_receive[PKT_DESTROY] = Receive_destroy;
290 playing_receive[PKT_LOOK] = Receive_look;
291
292 playing_receive[PKT_OPEN] = Receive_open;
293 playing_receive[PKT_QUAFF] = Receive_quaff;
294 playing_receive[PKT_READ] = Receive_read;
295 playing_receive[PKT_SEARCH] = Receive_search;
296 playing_receive[PKT_TAKE_OFF] = Receive_take_off;
297 playing_receive[PKT_TAKE_OFF_AMT] = Receive_take_off_amt;
298 playing_receive[PKT_USE] = Receive_use;
299 playing_receive[PKT_THROW] = Receive_throw;
300 playing_receive[PKT_WIELD] = Receive_wield;
301 playing_receive[PKT_OBSERVE] = Receive_observe;
302 playing_receive[PKT_ZAP] = Receive_zap;
303 playing_receive[PKT_ZAP_DIR] = Receive_zap_dir;
304 playing_receive[PKT_MIND] = Receive_mind;
305
306 playing_receive[PKT_TARGET] = Receive_target;
307 playing_receive[PKT_TARGET_FRIENDLY] = Receive_target_friendly;
308 playing_receive[PKT_INSCRIBE] = Receive_inscribe;
309 playing_receive[PKT_UNINSCRIBE] = Receive_uninscribe;
310 playing_receive[PKT_AUTOINSCRIBE] = Receive_autoinscribe;
311 playing_receive[PKT_ACTIVATE] = Receive_activate;
312 playing_receive[PKT_ACTIVATE_DIR] = Receive_activate_dir;
313 playing_receive[PKT_BASH] = Receive_bash;
314 playing_receive[PKT_DISARM] = Receive_disarm;
315 playing_receive[PKT_EAT] = Receive_eat;
316 playing_receive[PKT_FILL] = Receive_fill;
317 playing_receive[PKT_LOCATE] = Receive_locate;
318 playing_receive[PKT_MAP] = Receive_map;
319 playing_receive[PKT_SEARCH_MODE] = Receive_search_mode;
320
321 playing_receive[PKT_CLOSE] = Receive_close;
322 // playing_receive[PKT_GAIN] = Receive_gain;
323 playing_receive[PKT_DIRECTION] = Receive_direction;
324 playing_receive[PKT_GO_UP] = Receive_go_up;
325 playing_receive[PKT_GO_DOWN] = Receive_go_down;
326 playing_receive[PKT_MESSAGE] = Receive_message;
327 playing_receive[PKT_ITEM] = Receive_item;
328 playing_receive[PKT_SPELL] = Receive_spell;
329 playing_receive[PKT_PURCHASE] = Receive_purchase;
330 playing_receive[PKT_KING] = Receive_King;
331
332 playing_receive[PKT_SELL] = Receive_sell;
333 playing_receive[PKT_STORE_LEAVE] = Receive_store_leave;
334 playing_receive[PKT_STORE_CONFIRM] = Receive_store_confirm;
335 playing_receive[PKT_DROP_GOLD] = Receive_drop_gold;
336 playing_receive[PKT_REDRAW] = Receive_redraw;
337 playing_receive[PKT_REST] = Receive_rest;
338 playing_receive[PKT_SPECIAL_LINE] = Receive_special_line;
339 playing_receive[PKT_PARTY] = Receive_party;
340 playing_receive[PKT_GHOST] = Receive_ghost;
341
342 playing_receive[PKT_STEAL] = Receive_steal;
343 playing_receive[PKT_OPTIONS] = Receive_options;
344 playing_receive[PKT_SUICIDE] = Receive_suicide;
345 playing_receive[PKT_MASTER] = Receive_master;
346 playing_receive[PKT_HOUSE] = Receive_admin_house;
347
348 playing_receive[PKT_AUTOPHASE] = Receive_autophase;
349 playing_receive[PKT_SCREEN_DIM] = Receive_screen_dimensions;
350
351 playing_receive[PKT_CLEAR_BUFFER] = Receive_clear_buffer;
352 playing_receive[PKT_CLEAR_ACTIONS] = Receive_clear_actions;
353
354 playing_receive[PKT_SPIKE] = Receive_spike;
355 playing_receive[PKT_GUILD] = Receive_guild;
356 playing_receive[PKT_GUILD_CFG] = Receive_guild_config;
357
358 playing_receive[PKT_SKILL_MOD] = Receive_skill_mod;
359 playing_receive[PKT_SKILL_DEV] = Receive_skill_dev;
360 playing_receive[PKT_ACTIVATE_SKILL] = Receive_activate_skill;
361 playing_receive[PKT_RAW_KEY] = Receive_raw_key;
362 playing_receive[PKT_STORE_EXAMINE] = Receive_store_examine;
363 playing_receive[PKT_STORE_CMD] = Receive_store_command;
364 playing_receive[PKT_PING] = Receive_ping;
365
366 /* New stuff for v4.4.1 or 4.4.0d (dual-wield & co) - C. Blue */
367 playing_receive[PKT_SIP] = Receive_sip;
368 playing_receive[PKT_TELEKINESIS] = Receive_telekinesis;
369 playing_receive[PKT_BBS] = Receive_BBS;
370 playing_receive[PKT_WIELD2] = Receive_wield2;
371 playing_receive[PKT_CLOAK] = Receive_cloak;
372 playing_receive[PKT_INVENTORY_REV] = Receive_inventory_revision;
373 playing_receive[PKT_ACCOUNT_INFO] = Receive_account_info;
374 playing_receive[PKT_CHANGE_PASSWORD] = Receive_change_password;
375
376 playing_receive[PKT_FORCE_STACK] = Receive_force_stack;
377
378 playing_receive[PKT_REQUEST_KEY] = Receive_request_key;
379 playing_receive[PKT_REQUEST_NUM] = Receive_request_num;
380 playing_receive[PKT_REQUEST_STR] = Receive_request_str;
381 playing_receive[PKT_REQUEST_CFR] = Receive_request_cfr;
382 }
383
Init_setup(void)384 static int Init_setup(void) {
385 int n = 0, i;
386 char buf[1024];
387 FILE *fp;
388
389 Setup.frames_per_second = cfg.fps;
390 Setup.max_race = MAX_RACE;
391 #if 1
392 #ifdef ENABLE_MCRAFT
393 Setup.max_class = MAX_CLASS;
394 #else
395 Setup.max_class = MAX_CLASS - 1;
396 #endif
397 #else
398 Setup.max_class = MAX_CLASS;
399 #endif
400 Setup.max_trait = MAX_TRAIT;
401
402
403 Setup.motd_len = 23 * 120; /*80;*/ /* colour codes extra */
404 Setup.setup_size = sizeof(setup_t);
405
406 path_build(buf, 1024, ANGBAND_DIR_TEXT, "news.txt");
407
408 /* Open the news file */
409 fp = my_fopen(buf, "r");
410
411 if (fp) {
412 /* Dump the file into the buffer */
413 while (0 == my_fgets(fp, buf, 1024, TRUE) && n < 23) {
414 /* strncpy(&Setup.motd[n * 80], buf, 80); */
415 strncpy(&Setup.motd[n * 120], buf, 120);
416 n++;
417 }
418
419 my_fclose(fp);
420 }
421
422 /* MEGAHACK -- copy race/class names */
423 /* XXX I know this ruins the meaning of Setup... sry - Jir - */
424 for (i = 0; i < MAX_RACE; i++) {
425 if (!race_info[i].title) {
426 Setup.max_race = i;
427 break;
428 }
429 // strncpy(&Setup.race_title[i], race_info[i].title, 12);
430 // Setup.race_choice[i] = race_info[i].choice;
431 /* 1 for '\0', 4 for race_choice */
432 Setup.setup_size += strlen(race_info[i].title) + 1 + 4 + 6;
433 }
434
435 for (i = 0; i < MAX_CLASS; i++) {
436 if (!class_info[i].title) {
437 Setup.max_class = i;
438 break;
439 }
440 // strncpy(&Setup.class_title[i], class_info[i].title, 12);
441 Setup.setup_size += strlen(class_info[i].title) + 1 + 6;
442 }
443
444 for (i = 0; i < MAX_TRAIT; i++) {
445 if (!trait_info[i].title) {
446 Setup.max_trait = i;
447 break;
448 }
449 Setup.setup_size += strlen(trait_info[i].title) + 1 + 4;
450 }
451
452 return 0;
453 }
454
init_players()455 void init_players() {
456 max_connections = MAX_SELECT_FD - 24; /* 999 connections at most */
457 /* Last player is the DM Edit player ! */
458 /* As no extra connection is required, */
459 /* we need only allocate the player_type for it */
460 C_MAKE(Players, max_connections+1, player_type *);
461 }
462
463
464 /*
465 * Talk to the metaserver.
466 *
467 * This function is called on startup, on death, and when the number of players
468 * in the game changes.
469 */
Report_to_meta(int flag)470 bool Report_to_meta(int flag)
471 {
472 /* Abort if the user doesn't want to report */
473 if (!cfg.report_to_meta || cfg.runlevel < 4 || ((cfg.runlevel > 1023) && (cfg.runlevel < 2045))) {
474 return FALSE;
475 }
476
477 /* New implementation */
478 // s_printf("Reporting to meta...\n");
479 meta_report(flag);
480 return TRUE;
481 }
482
483 /* update tomenet.acc record structure to a new version - C. Blue
484 Done by opening 'tomenet.acc_old' and (over)writing 'tomenet.acc'. */
update_acc_file_version(void)485 static bool update_acc_file_version(void) {
486 FILE *fp_old, *fp;
487 struct account_old c_acc_old;
488 struct account c_acc;
489 size_t retval;
490 char buf[1024];
491 int amt = 0, total = 0;
492
493 path_build(buf, 1024, ANGBAND_DIR_SAVE, "tomenet.acc_old");
494 fp_old = fopen(buf, "rb");
495 /* No updating to do?
496 Exit here, if no 'tomenet.acc_old' file exists: */
497 if (!fp_old) return(FALSE);
498
499 s_printf("Initiating tomenet.acc update.. ");
500
501 path_build(buf, 1024, ANGBAND_DIR_SAVE, "tomenet.acc");
502 fp = fopen(buf, "wb");
503 if (!fp) {
504 s_printf("failed opening tomenet.acc.\n");
505 fclose(fp_old);
506 return(FALSE);
507 }
508
509 /* helper vars */
510 char *ptr;
511
512 while (!feof(fp_old)) {
513 retval = fread(&c_acc_old, sizeof(struct account_old), 1, fp_old);
514 if (retval == 0) break; /* EOF reached, nothing read into c_acc - mikaelh */
515 total++;
516
517 /* copy unchanged structure parts: */
518 c_acc.id = c_acc_old.id;
519 c_acc.flags = c_acc_old.flags;
520 //strcpy(c_acc.name, c_acc_old.name);
521 strcpy(c_acc.pass, c_acc_old.pass);
522 c_acc.acc_laston = c_acc_old.acc_laston;
523 c_acc.acc_laston_real = c_acc_old.acc_laston_real;
524 c_acc.cheeze = c_acc_old.cheeze;
525 c_acc.cheeze_self = c_acc_old.cheeze_self;
526 c_acc.deed_event = c_acc_old.deed_event;
527 c_acc.deed_achievement = c_acc_old.deed_achievement;
528 c_acc.guild_id = c_acc_old.guild_id;
529 c_acc.guild_dna = c_acc.guild_id ? guilds[c_acc.guild_id].dna : 0;
530
531 /* changes/additions - cumulative since 4.5.8a release time, to not break non-official servers: */
532 //1: disallow spaces at the end of account names
533 for (ptr = &c_acc_old.name[strlen(c_acc_old.name)]; ptr-- > c_acc_old.name; ) {
534 if (*ptr == ' ') *ptr = '\0';
535 else break;
536 }
537 strcpy(c_acc.name, c_acc_old.name);
538 //2: add 'name_normalised'
539 condense_name(c_acc.name_normalised, c_acc_old.name);
540
541 /* write it back */
542 if (fwrite(&c_acc, sizeof(struct account), 1, fp) < 1)
543 s_printf("failure: %s\n", feof(fp) ? "EOF" : strerror(ferror(fp)));
544
545 amt++;
546 }
547 s_printf("%d of %d records updated.\n", amt, total);
548 fclose(fp);
549 fclose(fp_old);
550
551 path_build(buf, 1024, ANGBAND_DIR_SAVE, "tomenet.acc_old");
552 remove(buf);
553
554 return(TRUE);
555 }
556
557 /* Purge deleted accounts from tomenet.acc file by rewriting it. */
purge_acc_file(void)558 bool purge_acc_file(void) {
559 FILE *fp_old, *fp;
560 struct account c_acc;
561 size_t retval;
562 char buf[1024], buf2[1024];
563 int amt = 0, total = 0;
564
565 s_printf("Initiating tomenet.acc purge.. ");
566
567 path_build(buf, 1024, ANGBAND_DIR_SAVE, "tomenet.acc");
568 fp_old = fopen(buf, "rb");
569 if (!fp_old) {
570 s_printf("failed opening tomenet.acc.\n");
571 fclose(fp_old);
572 return(FALSE);
573 }
574
575 path_build(buf2, 1024, ANGBAND_DIR_SAVE, "tomenet.acc_new");
576 fp = fopen(buf2, "wb");
577 if (!fp) {
578 s_printf("failed opening tomenet.acc_new.\n");
579 fclose(fp_old);
580 return(FALSE);
581 }
582
583 while (!feof(fp_old)) {
584 retval = fread(&c_acc, sizeof(struct account), 1, fp_old);
585 if (retval == 0) break; /* EOF reached, nothing read into c_acc - mikaelh */
586 total++;
587
588 /* Purge all deleted accounts */
589 if (c_acc.flags & ACC_DELD) {
590 amt++;
591 continue;
592 }
593
594 /* write it back */
595 if (fwrite(&c_acc, sizeof(struct account), 1, fp) < 1)
596 s_printf("failure: %s\n", feof(fp) ? "EOF" : strerror(ferror(fp)));
597 }
598 s_printf("%d of %d records purged.\n", amt, total);
599 fclose(fp);
600 fclose(fp_old);
601
602 remove(buf);
603 rename(buf2, buf);
604
605 return(TRUE);
606 }
607
608 /*
609 * Initialize the connection structures.
610 */
Setup_net_server(void)611 int Setup_net_server(void)
612 {
613 size_t size;
614
615 Init_receive();
616
617 if (Init_setup() == -1)
618 return -1;
619
620 /*
621 * The number of connections is limited by the number of bases
622 * and the max number of possible file descriptors to use in
623 * the select(2) call minus those for stdin, stdout, stderr,
624 * the contact socket, and the socket for the resolver library routines.
625 */
626
627 size = max_connections * sizeof(*Conn);
628 if ((Conn = (connection_t **) malloc(size)) == NULL)
629 quit("Cannot allocate memory for connections");
630
631 memset(Conn, 0, size);
632
633 /* Tell the metaserver that we're starting up */
634 s_printf("Report to metaserver\n");
635 Report_to_meta(META_START);
636
637 s_printf("%s\n", longVersion);
638 s_printf("Server is running version %04x\n", MY_VERSION);
639 strcpy(serverStartupTime, showtime());
640 s_printf("Current time is %s\n", serverStartupTime);
641 time(&cfg.runtime);
642 s_printf("Session startup turn is: %d\n", turn);
643 session_turn = turn;
644
645 /* Check for updating account file structure to a new version */
646 update_acc_file_version();
647
648 return 0;
649 }
650
651 /* The contact socket */
652 static int Socket;
653 static sockbuf_t ibuf;
654
655 /* The contact socket now uses TCP. This breaks backwards
656 * compatibility, but is a good thing.
657 */
658
setup_contact_socket(void)659 void setup_contact_socket(void)
660 {
661 plog(format("Create TCP socket on port %d...", cfg.game_port));
662 while ((Socket = CreateServerSocket(cfg.game_port)) == -1)
663 {
664 #ifdef WINDOWS
665 Sleep(1000);
666 #else
667 sleep(1);
668 #endif
669 }
670 plog("Set Non-Blocking...");
671 if (SetSocketNonBlocking(Socket, 1) == -1)
672 {
673 plog("Can't make contact socket non-blocking");
674 }
675 #ifdef FD_CLOEXEC
676 /* Make the socket close-on-exec if possible - mikaelh */
677 if (fcntl(Socket, F_SETFD, FD_CLOEXEC) == -1)
678 {
679 plog("Can't make contact socket close-on-exec");
680 }
681 #endif
682 if (SetSocketNoDelay(Socket, 1) == -1)
683 {
684 plog("Can't set TCP_NODELAY on the socket");
685 }
686 if (SocketLinger(Socket) == -1)
687 {
688 plog("Couldn't set SO_LINGER on the socket");
689 }
690
691 if (Sockbuf_init(&ibuf, Socket, SERVER_SEND_SIZE,
692 SOCKBUF_READ | SOCKBUF_WRITE ) == -1)
693 {
694 quit("No memory for contact buffer");
695 }
696
697 install_input(Contact, Socket, 0);
698
699 #ifdef SERVER_CONSOLE
700 /* Hack -- Install stdin an the "console" input */
701 install_input(Console, 0, 0);
702 #endif
703
704 #ifdef NEW_SERVER_CONSOLE
705 if ((ConsoleSocket = CreateServerSocket(cfg.console_port)) == -1)
706 {
707 s_printf("Couldn't create console socket\n");
708 return;
709 }
710 #ifdef FD_CLOEXEC
711 /* Make the socket close-on-exec if possible - mikaelh */
712 if (fcntl(ConsoleSocket, F_SETFD, FD_CLOEXEC) == -1)
713 {
714 plog("Can't make console socket close-on-exec");
715 }
716 #endif
717 if (SocketLinger(ConsoleSocket) == -1)
718 {
719 plog("Couldn't set SO_LINGER on the console socket");
720 }
721
722 if (!InitNewConsole(ConsoleSocket))
723 {
724 return;
725 }
726
727 /* Install the new console socket */
728 install_input(NewConsole, ConsoleSocket, 0);
729 #endif
730 #ifdef SERVER_GWPORT
731 /* evileye testing only */
732 if ((SGWSocket = CreateServerSocket(cfg.gw_port)) == -1)
733 {
734 s_printf("Couldn't create server gateway port\n");
735 return;
736 }
737 #ifdef FD_CLOEXEC
738 /* Make the socket close-on-exec if possible - mikaelh */
739 if (fcntl(SGWSocket, F_SETFD, FD_CLOEXEC) == -1)
740 {
741 plog("Can't make contact socket close-on-exec");
742 }
743 #endif
744 #if 0
745 if (SetSocketNonBlocking(SGWSocket, 1) == -1)
746 {
747 plog("Can't make GW socket non-blocking");
748 }
749 #endif
750
751 /* Install the new gateway socket */
752 install_input(SGWHit, SGWSocket, 0);
753 #endif
754 #ifdef TOMENET_WORLDS
755 world_connect(-1);
756 #endif
757 }
758
759 #ifdef TOMENET_WORLDS
world_connect(int Ind)760 void world_connect(int Ind) {
761 /* evileye testing only */
762 /* really, server should DIE if this happens */
763 if (WorldSocket != -1) {
764 if (Ind != -1) msg_print(Ind, "\377oAlready connected to the world server");
765 return;
766 }
767
768 block_timer();
769 if ((WorldSocket = CreateClientSocket(cfg.wserver, 18360)) == -1) {
770 #ifdef WIN32
771 s_printf("Unable to connect to world server %d\n", errno);
772 #else
773 s_printf("Unable to connect to world server %d %d\n", errno, sl_errno);
774 #endif
775 if (Ind != -1) msg_print(Ind, "\377rFailed to connect to the world server");
776 } else {
777 install_input(world_comm, WorldSocket, 0);
778 if (Ind != -1) msg_print(Ind, "\377gSuccessfully connected to the world server");
779 }
780 allow_timer();
781 }
782 #endif
783
Reply(char * host_addr,int fd)784 static int Reply(char *host_addr, int fd)
785 {
786 int result;
787
788 // No silly redundancy with TCP
789 if ((result = DgramWrite(fd, ibuf.buf, ibuf.len)) == -1)
790 {
791 GetSocketError(ibuf.sock);
792 }
793
794 return result;
795 }
796
797
798 /* invite only */
player_allowed(char * name)799 static bool player_allowed(char *name) {
800 FILE *sfp;
801 char buffer[80];
802 bool success = FALSE;
803 /* Hack -- allow 'guest' account */
804 /* if (!strcmp("Guest", name)) return TRUE; */
805
806 sfp = fopen("allowlist", "r");
807 if (sfp == (FILE*)NULL)
808 return TRUE;
809 else {
810 while (fgets(buffer, 80, sfp)) {
811 /* allow for \n */
812 if ((strlen(name) + 1) != strlen(buffer)) continue;
813 if (!strncmp(buffer,name, strlen(name))) {
814 success = TRUE;
815 break;
816 }
817 }
818 fclose(sfp);
819 }
820 return(success);
821 }
822
823 /* blacklist of special nicknames unavailable to players (monster names, "insanity",..) - C. Blue */
forbidden_name(char * cname)824 static bool forbidden_name(char *cname) {
825 FILE *sfp;
826 char path_buf[1024];
827 char buffer[80], name[80];
828 bool success = FALSE;
829 int i = 0;
830
831 /* All bad names must be specified in lower-case */
832 do name[i] = tolower(cname[i]);
833 while (cname[i++]);
834
835
836 /* Hack -- allow 'guest' account */
837 /* if (!strcmp("Guest", name)) return FALSE; */
838
839 /* Note: Character names always start upper-case, so some of these
840 aren't really needed on most file systems (semi-paranoia). */
841 /* Hardcode some critically important ones */
842 if (!strcmp(name, "server")) return TRUE; /* server save file is stored in same folder as player save files */
843 if (!strcmp(name, "server.new")) return TRUE; /* server save file is stored in same folder as player save files */
844 if (!strcmp(name, "server.old")) return TRUE; /* server save file is stored in same folder as player save files */
845 if (!strncmp(name, "server", 6) && name[6] >= '0' && name[6] <= '9') return TRUE; /* prepare for multiple partial server save files */
846 if (strstr(name, "guild") && strstr(name, ".data")) return TRUE; /* moved guild hall save files to save folder, from data folder */
847 if (strlen(name) >= 5 && name[0] == 's' && name[1] == 'a' && name[2] == 'v' && name[3] == 'e' &&
848 name[4] >= '0' && name[4] <= '9') return TRUE; /* backup save file folders, save00..saveNN */
849 if (!strcmp(name, "estate")) return TRUE; /* for new 'estate' folder that backs up houses. */
850 if (!strcmp(name, "quests")) return TRUE; /* dedicated quest state server save file */
851 if (!strcmp(name, "quests.new")) return TRUE; /* dedicated quest state server save file */
852 if (!strcmp(name, "quests.old")) return TRUE; /* dedicated quest state server save file */
853
854 /* account file management */
855 if (!strcmp(name, "tomenet.acc")) return TRUE;
856 if (!strcmp(name, "tomenet.acc_old")) return TRUE;
857 if (!strcmp(name, "accedit")) return TRUE;
858
859 if (!strncmp(name, "save", 4) && name[4] >= '0' && name[4] <= '9') return TRUE; /* paranoia - backup folders "saveX..." */
860 if (!strncmp(name, "estate", 6)) return TRUE; /* paranoia - house contents backup folder for server resets */
861
862 /* special death causes */
863 if (!strcmp(name, "insanity")) return TRUE;
864 if (!strcmp(name, "divine wrath")) return TRUE;
865 #ifdef ENABLE_MAIA
866 if (!strcmp(name, "indecisiveness")) return TRUE;
867 #endif
868 if (!strcmp(name, "indetermination")) return TRUE;
869
870 /* Hardcode some not so important ones */
871 if (!strcmp(name, "tbot")) return TRUE; /* Sandman's internal chat bot */
872 if (!strcmp(name, "8ball")) return TRUE; /* Sandman's internal chat bot */
873 /* For logging chat relayed from IRC */
874 if (!strcmp(name, "irc")) return TRUE;
875
876
877 path_build(path_buf, 1024, ANGBAND_DIR_CONFIG, "badnames.txt");
878
879 sfp = fopen(path_buf, "r");
880 if (sfp == (FILE*) NULL)
881 return FALSE;
882 else {
883 while (fgets(buffer, 80, sfp)) {
884 /* allow for \n */
885 if ((strlen(name) + 1) != strlen(buffer)) continue;
886 if (!strncmp(buffer,name, strlen(name))) {
887 success = TRUE;
888 break;
889 }
890 }
891 fclose(sfp);
892 }
893 return(success);
894 }
895
Trim_name(char * nick_name)896 static void Trim_name(char *nick_name)
897 {
898 char *ptr;
899 /* spaces at the beginning are impossible thanks to Check_names */
900 /* remove spaces at the end */
901 for (ptr = &nick_name[strlen(nick_name)]; ptr-- > nick_name; ) {
902 if (isspace(*ptr)) *ptr = '\0';
903 else break;
904 }
905 /* remove special chars that are used for parsing purpose */
906 for (ptr = &nick_name[strlen(nick_name)]; ptr-- > nick_name; ) {
907 if (!((*ptr >= 'A' && *ptr <= 'Z') ||
908 (*ptr >= 'a' && *ptr <= 'z') ||
909 (*ptr >= '0' && *ptr <= '9') ||
910 strchr(" .,-'&_$%~#<>|", *ptr))) /* chars allowed for character name, */
911 *ptr = '_'; /* but they become _ in savefile name */
912 }
913 }
914
915 /* verify that account, user, host name are valid,
916 and that we're resuming from the same IP address if we're resuming */
Check_names(char * nick_name,char * real_name,char * host_name,char * addr,bool check_for_resume)917 static int Check_names(char *nick_name, char *real_name, char *host_name, char *addr, bool check_for_resume) {
918 player_type *p_ptr = NULL;
919 connection_t *connp = NULL;
920 int i;
921
922 if (real_name[0] == 0 || host_name[0] == 0) return E_INVAL;
923 if (nick_name[0] < 'A' || nick_name[0] > 'Z') return E_LETTER;
924 if (strchr(nick_name, ':')) return E_INVAL;
925
926 if (check_for_resume) {
927 for (i = 1; i < NumPlayers + 1; i++) {
928 if (Players[i]->conn != NOT_CONNECTED ) {
929 p_ptr = Players[i];
930 /*
931 * FIXME: p_ptr->name is character name while nick_name is
932 * account name, so this check always fail. Evileye? :)
933 */
934 if (strcasecmp(p_ptr->name, nick_name) == 0) {
935 /*plog(format("%s %s", Players[i]->name, nick_name));*/
936
937 /* The following code allows you to "override" an
938 * existing connection by connecting again -Crimson */
939
940 /* XXX Hack -- since the password is not read until later, to
941 * authorize the "hijacking" of an existing connection,
942 * we check to see if the username and hostname are
943 * identical. Note that it may be possobile to spoof this,
944 * kicking someone off. This is a quick hack that should
945 * be replaced with proper password checking.
946 */
947 /* XXX another Hack -- don't allow to resume connection if
948 * in 'character edit' mode - Jir -
949 */
950
951 /* resume connection at this point is not compatible
952 with multicharacter accounts */
953 if (!strcasecmp(p_ptr->realname, real_name) &&
954 //!strcasecmp(p_ptr->accountname, acc_name) && --not needed, can't access nick_name from different account
955 !strcasecmp(p_ptr->addr, addr) && cfg.runlevel != 1024) {
956 printf("%s %s\n", p_ptr->realname, p_ptr->addr);
957 Destroy_connection(p_ptr->conn, "resume connection");
958 }
959 else return E_IN_USE;
960 }
961
962 /* All restrictions on the number of allowed players from one IP have
963 * been removed at this time. -APD
964 *
965 * Restored after the advent of Tcp/IP, becuase there is
966 * no longer any good reason to allow them. --Crimson
967
968 if (!strcasecmp(Players[i]->realname, real_name) &&
969 !strcasecmp(Players[i]->addr, addr) &&
970 strcasecmp(Players[i]->realname, cfg_admin_wizard) &&
971 strcasecmp(Players[i]->realname, cfg_dungeon_master)) {
972 return E_TWO_PLAYERS;
973 }
974 */
975 }
976 }
977 /* new, fix timing exploit that allows multi-login, part 1/2 (resuming) */
978 for (i = 0; i < max_connections; i++) {
979 connp = Conn[i];
980 if (!connp || connp->state == CONN_FREE) continue;// != CONN_LOGIN
981 if (!connp->c_name) continue;//hasn't chosen a character to login with yet?
982 if (strcasecmp(connp->c_name, nick_name)) continue;
983 //if (strcasecmp(connp->nick, acc_name)) continue; --not needed, can't access nick_name from different account
984 if (!strcasecmp(connp->real, real_name) &&
985 !strcasecmp(connp->addr, addr) && cfg.runlevel != 1024) {
986 printf("%s %s\n", connp->real, connp->addr);
987 Destroy_connection(i, "resume connection");
988 }
989 else return E_IN_USE;
990 }
991 }
992
993 return SUCCESS;
994 }
995 /* new, fix timing exploit that allows multi-login, part 2/2 (non-resuming) */
check_multi_exploit(char * acc,char * nick)996 bool check_multi_exploit(char *acc, char *nick) {
997 connection_t *connp = NULL;
998 int i;
999
1000 for (i = 0; i < max_connections; i++) {
1001 connp = Conn[i];
1002 if (!connp || connp->state == CONN_FREE) continue;// != CONN_LOGIN
1003 if (!connp->c_name) continue;//hasn't chosen a character to login with yet?
1004 if (!strcasecmp(connp->c_name, nick)) continue; //this case is instead handled by part 1/2: resume connection!
1005 if (strcasecmp(connp->nick, acc)) continue;
1006 s_printf("check_multi_exploit=TRUE\n");
1007 return TRUE;
1008 }
1009 return FALSE;
1010 }
1011
1012 #if 0
1013 static void Console(int fd, int arg)
1014 {
1015 char buf[1024];
1016 int i;
1017
1018 /* See what we got */
1019 /* this code added by thaler, 6/28/97 */
1020 fgets(buf, 1024, stdin);
1021 if (buf[ strlen(buf)-1 ] == '\n')
1022 buf[ strlen(buf)-1 ] = '\0';
1023
1024 for (i = 0; i < strlen(buf) && buf[i] != ' '; i++)
1025 {
1026 /* Capitalize each letter until we hit a space */
1027 buf[i] = toupper(buf[i]);
1028 }
1029
1030 /* Process our input */
1031 if (!strncmp(buf, "HELLO", 5))
1032 s_printf("Hello. How are you?\n");
1033
1034 if (!strncmp(buf, "SHUTDOWN", 8))
1035 {
1036 shutdown_server();
1037 }
1038
1039
1040 if (!strncmp(buf, "STATUS", 6))
1041 {
1042 s_printf("There %s %d %s.\n", (NumPlayers != 1 ? "are" : "is"), NumPlayers, (NumPlayers != 1 ? "players" : "player"));
1043
1044 if (NumPlayers > 0)
1045 {
1046 s_printf("%s:\n", (NumPlayers > 1 ? "They are" : "He is"));
1047 for (i = 1; i < NumPlayers + 1; i++)
1048 s_printf("\t%s\n", Players[i]->name);
1049 }
1050 }
1051
1052 if (!strncmp(buf, "MESSAGE", 7))
1053 {
1054 /* Send message to all players */
1055 for (i = 1; i <= NumPlayers; i++)
1056 msg_format(i, "[Server Admin] %s", &buf[8]);
1057
1058 /* Acknowledge */
1059 s_printf("Message sent.\n");
1060 }
1061
1062 if (!strncmp(buf, "KELDON", 6))
1063 {
1064 /* Whatever I need at the moment */
1065 }
1066 }
1067 #endif // if 0
1068
Contact(int fd,int arg)1069 static void Contact(int fd, int arg) {
1070 int bytes, login_port, newsock;
1071 u16b version = 0;
1072 unsigned magic;
1073 unsigned short port;
1074 char ch,
1075 real_name[MAX_CHARS],
1076 nick_name[MAX_CHARS],
1077 host_name[MAX_CHARS],
1078 host_addr[24],
1079 reply_to, status;
1080 version_type version_ext;
1081
1082 /* Create a TCP socket for communication with whoever contacted us */
1083 /* Hack -- check if this data has arrived on the contact socket or not.
1084 * If it has, then we have not created a connection with the client yet,
1085 * and so we must do so.
1086 */
1087
1088 if (fd == Socket) {
1089 if ((newsock = SocketAccept(fd)) == -1)
1090 quit("Couldn't accept game TCP connection.\n");
1091 install_input(Contact, newsock, 2);
1092 return;
1093 }
1094
1095 /*
1096 * Someone connected to us, now try and decipher the message
1097 */
1098 Sockbuf_clear(&ibuf);
1099 if ((bytes = DgramReceiveAny(fd, ibuf.buf, ibuf.size)) <= 8) {
1100 /* If 0 bytes have been sent than the client has probably closed
1101 * the connection
1102 */
1103 if (bytes == 0) {
1104 /* evileye - still in contact input, so close the socket here */
1105 /* Dont tell me it is ugly. I know ;( */
1106 /* Sched should do accepts and closes */
1107 close(fd);
1108 /*end evileye*/
1109 remove_input(fd);
1110 }
1111 else if (bytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN && errno != EINTR) {
1112 /* Clear the error condition for the contact socket */
1113 GetSocketError(fd);
1114 }
1115 return;
1116 }
1117 ibuf.len = bytes;
1118
1119 #ifdef WINDOWS
1120 /* Get the IP address of the client, without using the broken DgramLastAddr() */
1121 struct sockaddr_in sin;
1122 int len = sizeof(sin);
1123 if (getpeername(fd, (struct sockaddr *) &sin, &len) >= 0) {
1124 u32b addr = ntohl(sin.sin_addr.s_addr);
1125 strnfmt(host_addr, sizeof(host_addr), "%d.%d.%d.%d", (byte)(addr>>24),
1126 (byte)(addr>>16), (byte)(addr>>8), (byte)addr);
1127 }
1128 #else
1129 strcpy(host_addr, DgramLastaddr(fd));
1130 if (errno == ENOTCONN) { /* will be "0.0.0.0" probably */
1131 s_printf("Lost connection from unknown peer\n");
1132 close(fd);
1133 remove_input(fd);
1134 return;
1135 }
1136 #endif
1137
1138 /*if (Check_address(host_addr)) return;*/
1139
1140 if (Packet_scanf(&ibuf, "%u", &magic) <= 0) {
1141 plog(format("Incompatible packet from %s", host_addr));
1142 return;
1143 }
1144
1145 if (Packet_scanf(&ibuf, "%s%hu%c", real_name, &port, &ch) <= 0) {
1146 plog(format("Incomplete packet from %s", host_addr));
1147 return;
1148 }
1149 reply_to = (ch & 0xFF);
1150
1151 port = DgramLastport(fd);
1152
1153 if (Packet_scanf(&ibuf, "%s%s%hu", nick_name, host_name, &version) <= 0) {
1154 plog(format("Incomplete login from %s", host_addr));
1155 return;
1156 }
1157 if (version == 0xFFFFU) {
1158 /* Extended version support */
1159 if (Packet_scanf(&ibuf, "%d%d%d%d%d%d", &version_ext.major, &version_ext.minor, &version_ext.patch, &version_ext.extra, &version_ext.branch, &version_ext.build) <= 0) {
1160 plog(format("Incomplete extended version from %s", host_addr));
1161 return;
1162 }
1163
1164 /* Hack: Clients > 4.4.8.1.0.0 also send their binary type
1165 (OS they were compiled for), useful for MinGW weirdness
1166 in the future, like the LUA crash bug - C. Blue */
1167 if (is_older_than(&version_ext, 4, 4, 9, 2, 0, 0)) {
1168 version_ext.os = version_ext.build / 1000;
1169 version_ext.build %= 1000;
1170 } else {
1171 /* Use millions as of 4.4.9.2 (449b) - mikaelh */
1172 version_ext.os = version_ext.build / 1000000;
1173 version_ext.build %= 1000000;
1174 }
1175 } else {
1176 version_ext.major = version >> 12;
1177 version_ext.minor = (version >> 8) & 0xF;
1178 version_ext.patch = (version >> 4) & 0xF;
1179 version_ext.extra = version & 0xF;
1180 version_ext.branch = 0;
1181 version_ext.build = 0;
1182 }
1183
1184 //what does this stuff do?
1185 nick_name[sizeof(nick_name) - 1] = '\0';
1186 host_name[sizeof(host_name) - 1] = '\0';
1187
1188 /* server-side limit checks */
1189 nick_name[ACCOUNTNAME_LEN - 1] = '\0';
1190 real_name[REALNAME_LEN - 1] = '\0';
1191 host_name[HOSTNAME_LEN - 1] = '\0';
1192
1193 #if 1
1194 s_printf("Received contact from %s:%d.\n", host_name, port);
1195 s_printf("Address: %s.\n", host_addr);
1196 s_printf("Info: real_name %s, port %hu, nick %s, host %s, version %hu\n", real_name, port, nick_name, host_name, version);
1197 #endif
1198
1199 /* Replace all weird chars - mikaelh */
1200 validatestring(real_name);
1201 validatestring(host_name);
1202
1203 status = Enter_player(real_name, nick_name, host_addr, host_name,
1204 &version_ext, port, &login_port, fd);
1205
1206 #if DEBUG_LEVEL > 0
1207 if (status && status != E_NEED_INFO)
1208 s_printf("%s: Connection refused(%d).. %s=%s@%s (%s/%d)\n", showtime(),
1209 status, nick_name, real_name, host_name, host_addr, port);
1210 #endif // DEBUG_LEVEL
1211
1212 Sockbuf_clear(&ibuf);
1213
1214 /* s_printf("Sending login port %d, status %d.\n", login_port, status); */
1215
1216 if (is_newer_than(&version_ext, 4, 4, 1, 5, 0, 0)) {
1217 /* Hack - Send server version too - mikaelh */
1218 Packet_printf(&ibuf, "%c%c%d%d", reply_to, status, login_port, CHAR_CREATION_FLAGS | 0x02);
1219 Packet_printf(&ibuf, "%d%d%d%d%d%d", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_EXTRA, VERSION_BRANCH, VERSION_BUILD);
1220 }
1221 else {
1222 Packet_printf(&ibuf, "%c%c%d%d", reply_to, status, login_port, CHAR_CREATION_FLAGS);
1223 }
1224
1225 /* -- DGDGDGDG it would be NEAT to have classes sent to the cleint at conenciton, sadly Im too clumpsy at network code ..
1226 for (i = 0; i < MAX_CLASS; i++)
1227 {
1228 Packet_printf(&ibuf, "%c%s", i, class_info[i].title);
1229 }
1230 */
1231 Reply(host_addr, fd);
1232 }
1233
Enter_player(char * real,char * nick,char * addr,char * host,version_type * version,int port,int * login_port,int fd)1234 static int Enter_player(char *real, char *nick, char *addr, char *host,
1235 version_type *version, int port, int *login_port, int fd)
1236 {
1237 //int status;
1238
1239 *login_port = 0;
1240
1241 #if 0
1242 if(!validstrings(nick, real, host))
1243 #else
1244 /* Only check the account name for weird chars - mikaelh */
1245 if(!validstring(nick))
1246 #endif
1247 return E_INVAL;
1248
1249 if (NumPlayers >= max_connections)
1250 return E_GAME_FULL;
1251
1252 #if 0 /* This would pass in the account name rather than the
1253 player's character name. Also, we must *always* allow
1254 a second account login - it may be a subsequent resume.
1255 We can check duplicate account use on player entry
1256 (PKT_LOGIN) */
1257 if ((status = Check_names(nick, real, host, addr, TRUE)) != SUCCESS)
1258 {
1259 /*s_printf("Check_names failed with result %d.\n", status);*/
1260 return status;
1261 }
1262 #endif
1263
1264 #if 0
1265 if (version < MY_VERSION)
1266 return E_VERSION_OLD;
1267 if (version > MY_VERSION)
1268 return E_VERSION_UNKNOWN;
1269 #else
1270 /* Extended version support */
1271 if (is_older_than(version, MIN_VERSION_MAJOR, MIN_VERSION_MINOR, MIN_VERSION_PATCH, MIN_VERSION_EXTRA, 0, 0)) {
1272 return E_VERSION_OLD;
1273 } else if (is_newer_than(version, MAX_VERSION_MAJOR, MAX_VERSION_MINOR, MAX_VERSION_PATCH, MAX_VERSION_EXTRA, 0, INT_MAX)) {
1274 return E_VERSION_UNKNOWN;
1275 }
1276 #endif
1277
1278 if (!player_allowed(nick)) return E_INVITE;
1279 if (in_banlist(nick, addr, NULL, NULL)) return(E_BANNED);
1280
1281 *login_port = Setup_connection(real, nick, addr, host, version, fd);
1282 if (*login_port == -1) return E_SOCKET;
1283
1284 return SUCCESS;
1285 }
1286
1287
Conn_set_state(connection_t * connp,int state,int drain_state)1288 static void Conn_set_state(connection_t *connp, int state, int drain_state)
1289 {
1290 static int num_conn_busy;
1291 static int num_conn_playing;
1292
1293 if ((connp->state & (CONN_PLAYING | CONN_READY)) != 0)
1294 num_conn_playing--;
1295 else if (connp->state == CONN_FREE)
1296 num_conn_busy++;
1297
1298 connp->state = state;
1299 connp->drain_state = drain_state;
1300 connp->start = turn;
1301
1302 if (connp->state == CONN_PLAYING)
1303 {
1304 num_conn_playing++;
1305 connp->timeout = IDLE_TIMEOUT;
1306 }
1307 else if (connp->state == CONN_READY)
1308 {
1309 num_conn_playing++;
1310 connp->timeout = READY_TIMEOUT;
1311 }
1312 else if (connp->state == CONN_LOGIN)
1313 connp->timeout = LOGIN_TIMEOUT;
1314 else if (connp->state == CONN_SETUP)
1315 connp->timeout = SETUP_TIMEOUT;
1316 else if (connp->state == CONN_LISTENING)
1317 connp->timeout = LISTEN_TIMEOUT;
1318 else if (connp->state == CONN_FREE)
1319 {
1320 num_conn_busy--;
1321 connp->timeout = IDLE_TIMEOUT;
1322 }
1323 login_in_progress = num_conn_busy - num_conn_playing;
1324 }
1325
1326
1327 /*
1328 * Delete a player's information and save his game
1329 */
Delete_player(int Ind)1330 static void Delete_player(int Ind)
1331 {
1332 player_type *p_ptr = Players[Ind];
1333 int i;
1334 inventory_change_type *inv_change;
1335
1336 /* terminate mindcrafter charm effect */
1337 do_mstopcharm(Ind);
1338
1339 /* Be paranoid */
1340 cave_type **zcave;
1341 if ((zcave = getcave(&p_ptr->wpos)))
1342 {
1343 /* There's nobody on this space anymore */
1344 zcave[p_ptr->py][p_ptr->px].m_idx = 0;
1345
1346 /* Forget his lite and viewing area */
1347 forget_lite(Ind);
1348 forget_view(Ind);
1349
1350 /* Show everyone his disappearance */
1351 everyone_lite_spot(&p_ptr->wpos, p_ptr->py, p_ptr->px);
1352 }
1353
1354 /* If (s)he was in a game team, remove him/her - mikaelh */
1355 if (p_ptr->team != 0)
1356 {
1357 teams[p_ptr->team - 1]--;
1358 p_ptr->team = 0;
1359 }
1360
1361 /* Also remove hostility if (s)he was blood bonded - mikaelh */
1362 if (p_ptr->blood_bond)
1363 {
1364 #if 0
1365 remove_hostility(Ind, lookup_player_name(p_ptr->blood_bond));
1366
1367 i = find_player(p_ptr->blood_bond);
1368 if (i)
1369 {
1370 remove_hostility(i, p_ptr->name);
1371 Players[i]->blood_bond = 0;
1372 }
1373
1374 p_ptr->blood_bond = 0;
1375 #else
1376 player_list_type *pl_ptr, *tmp;
1377 pl_ptr = p_ptr->blood_bond;
1378
1379 while (pl_ptr)
1380 {
1381 /* Remove hostility */
1382 remove_hostility(Ind, lookup_player_name(pl_ptr->id));
1383
1384 i = find_player(pl_ptr->id);
1385 if (i)
1386 {
1387 /* Remove hostility and blood bond from the other player */
1388 remove_hostility(i, p_ptr->name);
1389 remove_blood_bond(i, Ind);
1390 }
1391
1392 tmp = pl_ptr;
1393 pl_ptr = pl_ptr->next;
1394 FREE(tmp, player_list_type);
1395 }
1396
1397 /* The list is gone now */
1398 p_ptr->blood_bond = NULL;
1399 #endif
1400 }
1401
1402 /* Remove ignores - mikaelh */
1403 #if 0
1404 if (p_ptr->ignore)
1405 {
1406 hostile_type *h_ptr, *tmp;
1407
1408 h_ptr = p_ptr->ignore;
1409
1410 while (h_ptr)
1411 {
1412 tmp = h_ptr;
1413 h_ptr = h_ptr->next;
1414 FREE(tmp, hostile_type);
1415 }
1416 }
1417 #else
1418 /* Make use of the new player_list_free */
1419 player_list_free(p_ptr->ignore);
1420 #endif
1421
1422 /* Remove him from everyone's afk_noticed if he was AFK */
1423 if (p_ptr->afk)
1424 for (i = 1; i <= NumPlayers; i++)
1425 player_list_del(&Players[i]->afk_noticed, p_ptr->id);
1426
1427 /* Free afk_noticed - mikaelh */
1428 player_list_free(p_ptr->afk_noticed);
1429
1430 /* Free inventory changes - mikaelh */
1431 inv_change = p_ptr->inventory_changes;
1432 while (inv_change) {
1433 inventory_change_type *free_change = inv_change;
1434 inv_change = inv_change->next;
1435 KILL(free_change, inventory_change_type);
1436 }
1437 p_ptr->inventory_changes = NULL;
1438
1439 /* Try to save his character */
1440 save_player(Ind);
1441
1442 /* If he was actively playing, tell everyone that he's left */
1443 /* handle the cfg_secret_dungeon_master option */
1444 if (p_ptr->alive && !p_ptr->death) {
1445 if (!p_ptr->admin_dm || !cfg.secret_dungeon_master) {
1446 cptr title = "";
1447 if (p_ptr->total_winner) {
1448 if (p_ptr->mode & (MODE_HARD | MODE_NO_GHOST)) {
1449 title = (p_ptr->male)?"Emperor ":((!strcmp(p_ptr->name,"Tina"))?"Tiny ":"Empress ");
1450 } else {
1451 title = (p_ptr->male)?"King ":"Queen ";
1452 }
1453 }
1454 if (p_ptr->admin_dm) title = (p_ptr->male)?"Dungeon Master ":"Dungeon Mistress ";
1455 if (p_ptr->admin_wiz) title = "Dungeon Wizard ";
1456
1457 #ifdef TOMENET_WORLDS /* idea: maybe use the 'quiet' flag as 'dungeon master' flag instead? */
1458 world_player(p_ptr->id, p_ptr->name, FALSE, TRUE); /* last flag is 'quiet' mode -> no public msg */
1459 #endif
1460
1461 for (i = 1; i < NumPlayers + 1; i++)
1462 {
1463 if (Players[i]->conn == NOT_CONNECTED)
1464 continue;
1465
1466 /* Don't tell him about himself */
1467 if (i == Ind) continue;
1468
1469 /* Send a little message */
1470 msg_format(i, "\374\377%c%s%s has left the game.", COLOUR_SERVER, title, p_ptr->name);
1471 }
1472 #ifdef TOMENET_WORLDS
1473 if (cfg.worldd_pleave) world_msg(format("\374\377%c%s%s has left the game.", COLOUR_SERVER, title, p_ptr->name));
1474 #endif
1475 } else {
1476 cptr title = "";
1477 if (p_ptr->admin_dm) title = (p_ptr->male)?"Dungeon Master ":"Dungeon Mistress ";
1478 if (p_ptr->admin_wiz) title = "Dungeon Wizard ";
1479 #if 0 /* Don't show admins in the list!! Reenable this when 'quiet' flag got reworked into 'dm' flag or sth. */
1480 #ifdef TOMENET_WORLDS
1481 world_player(p_ptr->id, p_ptr->name, FALSE, TRUE); /* last flag is 'quiet' mode -> no public msg */
1482 #endif
1483 #endif
1484 for (i = 1; i < NumPlayers + 1; i++) {
1485 if (Players[i]->conn == NOT_CONNECTED)
1486 continue;
1487 if (!is_admin(Players[i]))
1488 continue;
1489
1490 /* Don't tell him about himself */
1491 if (i == Ind) continue;
1492
1493 /* Send a little message */
1494 msg_format(i, "\374\377%c%s%s has left the game.", COLOUR_SERVER, title, p_ptr->name);
1495 /* missing TOMENET_WORLDS relay here :/ (currently no way to send to 'foreign' admins only) - C. Blue */
1496 }
1497 }
1498 }
1499
1500 #ifdef AUCTION_SYSTEM
1501 /* Save his/her money in the hash table */
1502 clockin(Ind, 5);
1503 #endif
1504
1505 if (p_ptr->esp_link_type && p_ptr->esp_link) {
1506 /* This is the last chance to get out!!! */
1507 int Ind2 = find_player(p_ptr->esp_link);
1508 if (Ind2) end_mind(Ind2, TRUE);
1509 }
1510
1511
1512 /* Swap entry number 'Ind' with the last one */
1513 /* Also, update the "player_index" on the cave grids */
1514 if (Ind != NumPlayers) {
1515 cave_type **zcave;
1516 worldpos *wpos = &Players[NumPlayers]->wpos;
1517 p_ptr = Players[NumPlayers];
1518 if ((zcave = getcave(&p_ptr->wpos)))
1519 zcave[p_ptr->py][p_ptr->px].m_idx = 0 - Ind;
1520 Players[NumPlayers] = Players[Ind];
1521 Players[Ind] = p_ptr;
1522 cave_midx_debug(wpos, p_ptr->py, p_ptr->px, -Ind);
1523 p_ptr = Players[NumPlayers];
1524 }
1525
1526 if (Conn[Players[Ind]->conn]->id != -1)
1527 GetInd[Conn[Players[Ind]->conn]->id] = Ind;
1528 if (Conn[Players[NumPlayers]->conn]->id != -1)
1529 GetInd[Conn[Players[NumPlayers]->conn]->id] = NumPlayers;
1530
1531 Players[Ind]->Ind = Ind;
1532
1533 /* Recalculate player-player visibility */
1534 update_players();
1535
1536 if (!is_admin(p_ptr)) NumNonAdminPlayers--;
1537
1538 if (p_ptr) {
1539 if (p_ptr->inventory)
1540 C_FREE(p_ptr->inventory, INVEN_TOTAL, object_type);
1541 if (p_ptr->inventory_copy)
1542 C_FREE(p_ptr->inventory_copy, INVEN_TOTAL, object_type);
1543
1544 KILL(Players[NumPlayers], player_type);
1545 }
1546
1547 NumPlayers--;
1548
1549 /* Update Morgoth eventually if the player was on his level */
1550 check_Morgoth(0);
1551
1552 /* Tell the metaserver about the loss of a player */
1553 Report_to_meta(META_UPDATE);
1554 }
1555
1556
1557 /*
1558 * Cleanup a connection. The client may not know yet that it is thrown out of
1559 * the game so we send it a quit packet if our connection to it has not already
1560 * closed. If our connection to it has been closed, then connp->w.sock will
1561 * be set to -1.
1562 */
Destroy_connection(int ind,char * reason_orig)1563 bool Destroy_connection(int ind, char *reason_orig)
1564 {
1565 connection_t *connp = Conn[ind];
1566 int id, len, sock;
1567 char pkt[MAX_CHARS];
1568 char *reason;
1569 int i, player = 0;
1570 char traffic[50+1];
1571 player_type *p_ptr = NULL;
1572
1573 /* reason was probably made using format() which uses a static buffer so copy it - mikaelh */
1574 reason = (char*)string_make(reason_orig);
1575
1576 kill_xfers(ind); /* don't waste time sending to a dead
1577 connection ( or crash! ) */
1578
1579 if (!connp || connp->state == CONN_FREE) {
1580 errno = 0;
1581 plog(format("Cannot destroy empty connection (\"%s\")", reason));
1582 string_free(reason);
1583 return FALSE;
1584 }
1585
1586 if (connp->id != -1) {
1587 exec_lua(0, format("player_leaves(%d, %d, \"%/s\", \"%s\")", GetInd[connp->id], connp->id, connp->c_name, showtime()));
1588
1589 /* in case winners CAN hold arts as long as they don't leave the floor (default): */
1590 //lua_strip_true_arts_from_present_player(GetInd[connp->id], int mode)
1591 } else
1592 exec_lua(0, format("player_leaves(%d, %d, \"%/s\", \"%s\")", 0, connp->id, connp->c_name, showtime()));
1593
1594 sock = connp->w.sock;
1595 if (sock != -1) remove_input(sock);
1596
1597 strncpy(&pkt[1], reason, sizeof(pkt) - 3);
1598 pkt[sizeof(pkt) - 2] = '\0';
1599 pkt[0] = PKT_QUIT;
1600 len = strlen(pkt) + 2;
1601 pkt[len - 1] = PKT_END;
1602 pkt[len] = '\0';
1603 /*len++;*/
1604
1605 if (sock != -1) {
1606 #if 1 // sorry evileye, removing it causes SIGPIPE to the client
1607
1608 if (DgramWrite(sock, pkt, len) != len) {
1609 GetSocketError(sock);
1610 //maybe remove this one too? Or have its error be cleared too? - C. Blue
1611 // DgramWrite(sock, pkt, len);
1612 }
1613 #endif
1614 }
1615
1616 if (connp->id != -1) {
1617 player = GetInd[connp->id];
1618 p_ptr = Players[player];
1619 }
1620 if (p_ptr) {
1621 s_printf("%s: Goodbye %s(%s)=%s@%s (\"%s\") (Ind=%d,ind=%d;wpos=%d,%d,%d;xy=%d,%d)\n",
1622 showtime(),
1623 connp->c_name ? connp->c_name : "",
1624 connp->nick ? connp->nick : "",
1625 connp->real ? connp->real : "",
1626 connp->host ? connp->host : "",
1627 reason, player, ind,
1628 p_ptr->wpos.wx, p_ptr->wpos.wy, p_ptr->wpos.wz,
1629 p_ptr->px, p_ptr->py);
1630 clockin(player, 7); /* Remember his wpos -- should be redundant with clockin() call in dungeon.c:process_player_change_wpos() */
1631 } else
1632 s_printf("%s: Goodbye %s(%s)=%s@%s (\"%s\") (Ind=%d,ind=%d;wpos=-,-,-;xy=-,-)\n",
1633 showtime(),
1634 connp->c_name ? connp->c_name : "",
1635 connp->nick ? connp->nick : "",
1636 connp->real ? connp->real : "",
1637 connp->host ? connp->host : "",
1638 reason, player, ind);
1639
1640 Conn_set_state(connp, CONN_FREE, CONN_FREE);
1641
1642 if (connp->id != -1) {
1643 id = connp->id;
1644 connp->id = -1;
1645 /*
1646 Players[GetInd[id]]->conn = NOT_CONNECTED;
1647 */
1648 Delete_player(GetInd[id]);
1649 }
1650
1651 exec_lua(0, format("player_has_left(%d, %d, \"%/s\", \"%s\")", player, connp->id, connp->c_name, showtime()));
1652 if (NumPlayers == 0) exec_lua(0, format("last_player_has_left(%d, %d, \"%/s\", \"%s\")", player, connp->id, connp->c_name, showtime()));
1653 strcpy(traffic, "");
1654 for (i = 1; (i <= NumPlayers) && (i < 50); i++)
1655 if (!(i % 5)) strcat(traffic, "* "); else strcat(traffic, "*");
1656 p_printf("%s - %03d %s\n", showtime(), NumPlayers, traffic);
1657
1658 if (connp->real != NULL) free(connp->real);
1659 if (connp->nick != NULL) free(connp->nick);
1660 if (connp->addr != NULL) free(connp->addr);
1661 if (connp->host != NULL) free(connp->host);
1662 if (connp->c_name != NULL) free(connp->c_name);
1663 Sockbuf_cleanup(&connp->w);
1664 Sockbuf_cleanup(&connp->r);
1665 Sockbuf_cleanup(&connp->c);
1666 Sockbuf_cleanup(&connp->q);
1667 memset(connp, 0, sizeof(*connp));
1668
1669 /* Free the connection_t structure - mikaelh */
1670 KILL(Conn[ind], connection_t);
1671 connp = NULL;
1672
1673 num_logouts++;
1674
1675 if (sock != -1) DgramClose(sock);
1676
1677 string_free(reason);
1678
1679 return TRUE;
1680 }
1681
Check_connection(char * real,char * nick,char * addr)1682 int Check_connection(char *real, char *nick, char *addr)
1683 {
1684 int i;
1685 connection_t *connp;
1686
1687 for (i = 0; i < max_connections; i++)
1688 {
1689 connp = Conn[i];
1690 if (connp && connp->state == CONN_LISTENING)
1691 if (strcasecmp(connp->nick, nick) == 0)
1692 {
1693 if (!strcmp(real, connp->real)
1694 && !strcmp(addr, connp->addr))
1695 return connp->my_port;
1696 return -1;
1697 }
1698 }
1699 return -1;
1700 }
1701
1702
1703 /*
1704 * A client has requested a playing connection with this server.
1705 * See if we have room for one more player and if his name is not
1706 * already in use by some other player. Because the confirmation
1707 * may get lost we are willing to send it another time if the
1708 * client connection is still in the CONN_LISTENING state.
1709 */
Setup_connection(char * real,char * nick,char * addr,char * host,version_type * version,int fd)1710 int Setup_connection(char *real, char *nick, char *addr, char *host,
1711 version_type *version, int fd)
1712 {
1713 int i, free_conn_index = max_connections, my_port, sock;
1714 connection_t *connp;
1715
1716 for (i = 0; i < max_connections; i++)
1717 {
1718 connp = Conn[i];
1719 if (!connp || connp->state == CONN_FREE)
1720 {
1721 if (free_conn_index == max_connections)
1722 free_conn_index = i;
1723 continue;
1724 }
1725
1726 /* Do not deny access here, or we cannot *ever*
1727 resume or allow multiple connections from
1728 a single account. */
1729 #if 0
1730 if (strcasecmp(connp->nick, nick) == 0)
1731 {
1732 if (connp->state == CONN_LISTENING
1733 && strcmp(real, connp->real) == 0
1734 && version == connp->version)
1735 return connp->my_port;
1736 else return -1;
1737 }
1738 #endif
1739 }
1740
1741 if (free_conn_index >= max_connections)
1742 {
1743 s_printf("Full house for %s(%s)@%s\n", real, nick, host);
1744 return -1;
1745 }
1746
1747 /* Allocate the connection_t structure - mikaelh */
1748 MAKE(Conn[free_conn_index], connection_t);
1749
1750 connp = Conn[free_conn_index];
1751
1752 if (connp == NULL)
1753 {
1754 plog("Not enough memory for connection");
1755 Destroy_connection(free_conn_index, "Server is out of memory.");
1756 return -1;
1757 }
1758
1759 // A TCP connection already exists with the client, use it.
1760 sock = fd;
1761
1762 if ((my_port = GetPortNum(sock)) == 0)
1763 {
1764 plog("Cannot get port from socket");
1765 DgramClose(sock);
1766 return -1;
1767 }
1768 if (SetSocketNonBlocking(sock, 1) == -1)
1769 {
1770 plog("Cannot make client socket non-blocking");
1771 DgramClose(sock);
1772 return -1;
1773 }
1774 if (SocketLinger(sock) == -1)
1775 {
1776 plog("Couldn't set SO_LINGER on the socket");
1777 }
1778 if (SetSocketReceiveBufferSize(sock, SERVER_RECV_SIZE + 256) == -1)
1779 plog(format("Cannot set receive buffer size to %d", SERVER_RECV_SIZE + 256));
1780 if (SetSocketSendBufferSize(sock, SERVER_SEND_SIZE + 256) == -1)
1781 plog(format("Cannot set send buffer size to %d", SERVER_SEND_SIZE + 256));
1782
1783 Sockbuf_init(&connp->w, sock, SERVER_SEND_SIZE, SOCKBUF_WRITE);
1784 Sockbuf_init(&connp->r, sock, SERVER_RECV_SIZE, SOCKBUF_WRITE | SOCKBUF_READ);
1785 Sockbuf_init(&connp->c, -1, MAX_SOCKBUF_SIZE, SOCKBUF_WRITE | SOCKBUF_READ | SOCKBUF_LOCK);
1786 Sockbuf_init(&connp->q, -1, MAX_SOCKBUF_SIZE, SOCKBUF_WRITE | SOCKBUF_READ | SOCKBUF_LOCK);
1787
1788 connp->my_port = my_port;
1789 connp->real = strdup(real);
1790 connp->nick = strdup(nick);
1791 connp->addr = strdup(addr);
1792 connp->host = strdup(host);
1793 #if 0
1794 connp->version = version;
1795 #else
1796 /* Extended version support */
1797 memcpy(&connp->version, version, sizeof(version_type));
1798 #endif
1799 connp->start = turn;
1800 connp->magic = rand() + my_port + sock + turn;
1801 connp->id = -1;
1802 connp->timeout = LISTEN_TIMEOUT;
1803 /* - not used - mikaelh
1804 connp->reliable_offset = 0;
1805 connp->reliable_unsent = 0;
1806 connp->last_send_loops = 0;
1807 connp->retransmit_at_loop = 0;
1808 connp->rtt_retransmit = DEFAULT_RETRANSMIT;
1809 connp->rtt_smoothed = 0;
1810 connp->rtt_dev = 0;
1811 connp->rtt_timeouts = 0;
1812 */
1813 connp->acks = 0;
1814 connp->setup = 0;
1815 connp->password_verified = FALSE;
1816 Conn_set_state(connp, CONN_LISTENING, CONN_FREE);
1817 if (connp->w.buf == NULL || connp->r.buf == NULL || connp->c.buf == NULL
1818 || connp->q.buf == NULL || connp->real == NULL || connp->nick == NULL
1819 || connp->addr == NULL || connp->host == NULL)
1820 {
1821 plog("Not enough memory for connection");
1822 Destroy_connection(free_conn_index, "Server is out of memory.");
1823 return -1;
1824 }
1825
1826 // Remove the contact input handler
1827 remove_input(sock);
1828 // Install the game input handler
1829 install_input(Handle_input, sock, free_conn_index);
1830
1831 return my_port;
1832 }
1833
Handle_setup(int ind)1834 static int Handle_setup(int ind)
1835 {
1836 connection_t *connp = Conn[ind];
1837 char *buf;
1838 int n, len, i, j;
1839 char b1, b2, b3, b4, b5, b6;
1840
1841 if (connp->state != CONN_SETUP) {
1842 Destroy_connection(ind, "not setup");
1843 return -1;
1844 }
1845
1846 if (connp->setup == 0) {
1847 if (is_newer_than(&connp->version, 4, 4, 5, 10, 0, 0))
1848 n = Packet_printf(&connp->c, "%d%hd%c%c%c%d",
1849 Setup.motd_len, Setup.frames_per_second, Setup.max_race, Setup.max_class, Setup.max_trait, Setup.setup_size);
1850 else
1851 n = Packet_printf(&connp->c, "%d%hd%c%c%d",
1852 Setup.motd_len, Setup.frames_per_second, Setup.max_race, Setup.max_class, Setup.setup_size);
1853
1854 if (n <= 0) {
1855 Destroy_connection(ind, "Setup 0 write error");
1856 return -1;
1857 }
1858
1859 for (i = 0; i < Setup.max_race; i++) {
1860 // Packet_printf(&ibuf, "%c%s", i, class_info[i].title);
1861 b1 = race_info[i].r_adj[0]+50;
1862 b2 = race_info[i].r_adj[1]+50;
1863 b3 = race_info[i].r_adj[2]+50;
1864 b4 = race_info[i].r_adj[3]+50;
1865 b5 = race_info[i].r_adj[4]+50;
1866 b6 = race_info[i].r_adj[5]+50;
1867 Packet_printf(&connp->c, "%c%c%c%c%c%c%s%d", b1, b2, b3, b4, b5, b6, race_info[i].title, race_info[i].choice);
1868 }
1869
1870 for (i = 0; i < Setup.max_class; i++) {
1871 // Packet_printf(&ibuf, "%c%s", i, class_info[i].title);
1872 b1 = class_info[i].c_adj[0]+50;
1873 b2 = class_info[i].c_adj[1]+50;
1874 b3 = class_info[i].c_adj[2]+50;
1875 b4 = class_info[i].c_adj[3]+50;
1876 b5 = class_info[i].c_adj[4]+50;
1877 b6 = class_info[i].c_adj[5]+50;
1878 Packet_printf(&connp->c, "%c%c%c%c%c%c%s", b1, b2, b3, b4, b5, b6, class_info[i].title);
1879 if (is_newer_than(&connp->version, 4, 4, 3, 1, 0, 0))
1880 for (j = 0; j < 6; j++)
1881 Packet_printf(&connp->c, "%c", class_info[i].min_recommend[j]);
1882 }
1883
1884 if (is_newer_than(&connp->version, 4, 4, 5, 10, 0, 0))
1885 for (i = 0; i < Setup.max_trait; i++)
1886 Packet_printf(&connp->c, "%s%d", trait_info[i].title, trait_info[i].choice);
1887
1888 connp->setup = (char *) &Setup.motd[0] - (char *) &Setup;
1889 connp->setup = 0;
1890 }
1891 /* else if (connp->setup < Setup.setup_size) */
1892 else if (connp->setup < Setup.motd_len) {
1893 if (connp->c.len > 0) {
1894 /* If there is still unacked reliable data test for acks. */
1895 Handle_input(-1, ind);
1896 if (connp->state == CONN_FREE)
1897 return -1;
1898 }
1899 }
1900 /* if (connp->setup < Setup.setup_size) */
1901 if (connp->setup < Setup.motd_len) {
1902 len = MIN(connp->c.size, 4096) - connp->c.len;
1903 if (len <= 0) {
1904 /* Wait for acknowledgement of previously transmitted data. */
1905 return 0;
1906 }
1907 /*
1908 if (len > Setup.setup_size - connp->setup)
1909 len = Setup.setup_size - connp->setup;
1910 */
1911
1912 if (len>Setup.motd_len-connp->setup) {
1913 len = Setup.motd_len - connp->setup;
1914 len = Setup.motd_len;
1915 }
1916
1917 /* buf = (char *) &Setup; */
1918 buf = (char *) &Setup.motd[0];
1919 if (Sockbuf_write(&connp->c, &buf[connp->setup], len) != len) {
1920 Destroy_connection(ind, "sockbuf write setup error");
1921 return -1;
1922 }
1923 connp->setup += len;
1924 if (len >= 512)
1925 connp->start += (len * cfg.fps) / (8 * 512) + 1;
1926 }
1927
1928 /* if (connp->setup >= Setup.setup_size) */
1929 if (connp->setup >= Setup.motd_len)
1930 //Conn_set_state(connp, CONN_DRAIN, CONN_LOGIN);
1931 Conn_set_state(connp, CONN_LOGIN, CONN_LOGIN);
1932
1933 return 0;
1934 }
1935
1936 /*
1937 * No spaces/strange characters in the account name,
1938 * real name or hostname.
1939 */
1940 #if 0
1941 static bool validstrings(char *nick, char *real, char *host) {
1942 int i;
1943 int rval = 1;
1944
1945 for (i = 0; nick[i]; i++) {
1946 if (nick[i] < 32 || nick[i] > 'z') {
1947 nick[i] = '\0';
1948 rval = 0;
1949 }
1950 }
1951 for (i = 0; real[i]; i++) {
1952 if (real[i] < 32 || real[i] > 'z') {
1953 real[i] = '\0';
1954 rval = 0;
1955 }
1956 }
1957 for (i = 0; host[i]; i++) {
1958 if (host[i] < 32 || host[i] > 'z') {
1959 host[i] = '\0';
1960 rval = 0;
1961 }
1962 }
1963 return(rval);
1964 }
1965 #else
validstring(char * nick)1966 static bool validstring(char *nick) {
1967 int i, rval = 1;
1968
1969 for (i = 0; nick[i]; i++) {
1970 if (nick[i] < 32 || nick[i] > 'z') {
1971 nick[i] = '\0';
1972 rval = 0;
1973 }
1974 }
1975
1976 return(rval);
1977 }
1978 #endif
1979
1980 /*
1981 * Replace all weird chars with underscores
1982 * Alternate to validstrings() - mikaelh
1983 */
validatestring(char * string)1984 void validatestring(char *string) {
1985 int i;
1986
1987 for (i = 0; string[i]; i++) {
1988 if (string[i] < 32 || string[i] > 'z') {
1989 string[i] = '_';
1990 }
1991 }
1992 }
1993
1994 /*
1995 * Handle a connection that is in the listening state.
1996 */
Handle_listening(int ind)1997 static int Handle_listening(int ind)
1998 {
1999 connection_t *connp = Conn[ind];
2000 unsigned char type;
2001 int n, oldlen;
2002 char nick[MAX_CHARS], real[MAX_CHARS], pass[MAX_CHARS];
2003 version_type *version = &connp->version;
2004
2005 if (connp->state != CONN_LISTENING)
2006 {
2007 Destroy_connection(ind, "not listening");
2008 return -1;
2009 }
2010 errno = 0;
2011
2012 /* Some data has arrived on the socket. Read this data into r.buf.
2013 */
2014 oldlen = connp->r.len;
2015 n = Sockbuf_read(&connp->r);
2016 if (n - oldlen <= 0)
2017 {
2018 if (n == 0)
2019 {
2020 /* Hack -- set sock to -1 so destroy connection doesn't
2021 * try to inform the client about its destruction
2022 */
2023 remove_input(connp->w.sock);
2024 connp->w.sock = -1;
2025 Destroy_connection(ind, "TCP connection closed");
2026 }
2027 /* It's already Dead, Jim.
2028 else
2029 Destroy_connection(ind, "read first packet error");
2030 */
2031 return -1;
2032 }
2033 connp->his_port = DgramLastport(connp->r.sock);
2034
2035 /* Do a sanity check and read in the some basic player information. */
2036 /* XXX reason messages here are not transmitted to the client! - Jir - */
2037 if (connp->r.ptr[0] != PKT_VERIFY)
2038 {
2039 Send_reply(ind, PKT_VERIFY, PKT_FAILURE);
2040 Send_reliable(ind);
2041 Destroy_connection(ind, "not connecting");
2042 return -1;
2043 }
2044
2045 if ((n = Packet_scanf(&connp->r, "%c%s%s%s", &type, real, nick, pass)) <= 0)
2046 {
2047 Send_reply(ind, PKT_VERIFY, PKT_FAILURE);
2048 Send_reliable(ind);
2049 Destroy_connection(ind, "verify broken");
2050 return -1;
2051 }
2052
2053 /*
2054 * It's quite doubtful if it's 2654 bytes, since MAX_R_IDX and MAX_K_IDX
2055 * etc are much bigger than before; however, let's follow the saying
2056 * 'Never touch what works' ;) - Jir -
2057 */
2058
2059 /* Log the players connection */
2060 s_printf("%s: Welcome %s=%s@%s (%s/%d) (NP=%d,ind=%d)", showtime(), connp->nick,
2061 connp->real, connp->host, connp->addr, connp->his_port, NumPlayers, ind);
2062 #if 0
2063 if (connp->version != MY_VERSION)
2064 s_printf(" (version %04x)", connp->version);
2065 #else
2066 /* Extended version support */
2067 s_printf(" (version %d.%d.%d.%d branch %d build %d, os %d)", version->major, version->minor, version->patch, version->extra, version->branch, version->build, version->os);
2068 #endif
2069 s_printf("\n");
2070
2071 if (strcmp(real, connp->real))
2072 {
2073 s_printf("Client verified incorrectly (%s, %s)(%s, %s)\n",
2074 real, nick, connp->real, connp->nick);
2075 Send_reply(ind, PKT_VERIFY, PKT_FAILURE);
2076 Send_reliable(ind);
2077 Destroy_connection(ind, "verify incorrect");
2078 return -1;
2079 }
2080
2081 /* Set his character info */
2082 connp->pass = strdup(pass);
2083
2084 Sockbuf_clear(&connp->w);
2085 if (Send_reply(ind, PKT_VERIFY, PKT_SUCCESS) == -1
2086 || Packet_printf(&connp->c, "%c%u", PKT_MAGIC, connp->magic) <= 0
2087 || Send_reliable(ind) <= 0)
2088 {
2089 Destroy_connection(ind, "confirm failed");
2090 return -1;
2091 }
2092
2093 Conn_set_state(connp, CONN_SETUP, CONN_SETUP);
2094
2095 return -1;
2096 }
2097
2098 /*
2099 * Sync the named options from the array of options.
2100 *
2101 * This is a crappy way of doing things....
2102 */
2103 /* see client_opts */
sync_options(int Ind,bool * options)2104 static void sync_options(int Ind, bool *options) {
2105 player_type *p_ptr = Players[Ind];
2106
2107 bool tmp;
2108 int i;
2109
2110 /* Do the dirty work */
2111 if (is_older_than(&p_ptr->version, 4, 5, 8, 2, 0, 0)) {
2112 p_ptr->rogue_like_commands = options[0];
2113
2114 if (is_older_than(&p_ptr->version, 4, 4, 8, 7, 0, 0)) /* which effectively means < 4.4.9 */
2115 p_ptr->warn_unique_credit = FALSE;
2116 else
2117 p_ptr->warn_unique_credit = options[1];
2118
2119 if (is_older_than(&p_ptr->version, 4, 4, 8, 2, 0, 0))
2120 p_ptr->newbie_hints = TRUE;
2121 else {
2122 tmp = p_ptr->newbie_hints;
2123 p_ptr->newbie_hints = options[3];
2124
2125 /* disable some or all newbie hints */
2126 if (!p_ptr->newbie_hints) disable_specific_warnings(p_ptr);
2127 else if (!tmp) msg_print(Ind, "\374\377yEnabling newbie hints requires you to exit and log in again.");
2128 }
2129
2130 p_ptr->use_old_target = options[4];
2131 p_ptr->always_pickup = options[5];
2132 p_ptr->stack_force_notes = options[8];
2133 p_ptr->stack_force_costs = options[9];
2134 if (!is_newer_than(&p_ptr->version, 4, 5, 2, 0, 0, 0))
2135 p_ptr->font_map_solid_walls = FALSE;
2136 else {
2137 tmp = p_ptr->font_map_solid_walls;
2138 if ((p_ptr->font_map_solid_walls = options[13]) != tmp) p_ptr->redraw |= PR_MAP;
2139 }
2140 p_ptr->find_ignore_stairs = options[16];
2141 p_ptr->find_ignore_doors = options[17];
2142 p_ptr->find_cut = options[18];
2143 p_ptr->find_examine = options[19];
2144 p_ptr->disturb_move = options[20];
2145 p_ptr->disturb_near = options[21];
2146 p_ptr->disturb_panel = options[22];
2147 p_ptr->disturb_state = options[23];
2148 p_ptr->disturb_minor = options[24];
2149 p_ptr->disturb_other = options[25];
2150 p_ptr->alert_hitpoints = options[26];
2151 p_ptr->alert_afk_dam = options[27];
2152 p_ptr->auto_afk = options[28];
2153 p_ptr->newb_suicide = options[29];
2154 p_ptr->stack_allow_items = options[30];
2155 p_ptr->stack_allow_wands = options[31];
2156
2157 tmp = p_ptr->view_perma_grids;
2158 if ((p_ptr->view_perma_grids = options[34]) != tmp) p_ptr->redraw |= PR_MAP;
2159 tmp = p_ptr->view_torch_grids;
2160 if ((p_ptr->view_torch_grids = options[35]) != tmp) p_ptr->redraw |= PR_MAP;
2161 tmp = p_ptr->view_reduce_lite;
2162 if ((p_ptr->view_reduce_lite = options[44]) != tmp) p_ptr->redraw |= PR_MAP;
2163 tmp = p_ptr->view_reduce_view;
2164 if ((p_ptr->view_reduce_view = options[45]) != tmp) p_ptr->redraw |= PR_MAP;
2165
2166 p_ptr->safe_float = options[46];
2167
2168 if (is_older_than(&p_ptr->version, 4, 4, 8, 4, 0, 0))
2169 p_ptr->censor_swearing = TRUE;
2170 else
2171 p_ptr->censor_swearing = options[53];
2172
2173 if (!is_newer_than(&p_ptr->version, 4, 5, 2, 0, 0, 0))
2174 p_ptr->view_animated_lite = FALSE;
2175 else {
2176 tmp = p_ptr->view_animated_lite;
2177 if ((p_ptr->view_animated_lite = options[52]) != tmp) p_ptr->redraw |= PR_MAP;
2178 }
2179 if (is_older_than(&p_ptr->version, 4, 5, 2, 0, 0, 0))
2180 p_ptr->view_shade_walls = options[57];
2181 else {
2182 tmp = p_ptr->view_shade_walls;
2183 if ((p_ptr->view_shade_walls = options[55]) != tmp) p_ptr->redraw |= PR_MAP;
2184 }
2185 tmp = p_ptr->view_lamp_floor;
2186 if ((p_ptr->view_lamp_floor = options[56]) != tmp) p_ptr->redraw |= PR_MAP;
2187 tmp = p_ptr->view_shade_floor;
2188 if ((p_ptr->view_shade_floor = options[57]) != tmp) p_ptr->redraw |= PR_MAP;
2189 tmp = p_ptr->wall_lighting;
2190 if ((p_ptr->wall_lighting = options[58]) != tmp) p_ptr->redraw |= PR_MAP;
2191 tmp = p_ptr->floor_lighting;
2192 if ((p_ptr->floor_lighting = options[59]) != tmp) p_ptr->redraw |= PR_MAP;
2193
2194 p_ptr->easy_open = options[60];
2195 p_ptr->easy_disarm = options[61];
2196 p_ptr->easy_tunnel = options[62];
2197 // p_ptr->auto_destroy = options[63];
2198 p_ptr->clear_inscr = options[63];
2199 p_ptr->auto_inscribe = options[64];
2200 if (!is_newer_than(&p_ptr->version, 4, 5, 7, 2, 0, 0)) {
2201 p_ptr->taciturn_messages = options[65];
2202 p_ptr->last_words = options[66];
2203 } else {
2204 bool vlf = p_ptr->view_lite_extra;
2205 p_ptr->last_words = TRUE;
2206 p_ptr->taciturn_messages = options[66];
2207 p_ptr->view_lite_extra = options[65];
2208 if (vlf != p_ptr->view_lite_extra) p_ptr->redraw |= PR_MAP;
2209 }
2210
2211 p_ptr->limit_chat = options[67];
2212
2213 tmp = p_ptr->depth_in_feet;
2214 if ((p_ptr->depth_in_feet = options[7]) != tmp)
2215 p_ptr->redraw |= PR_DEPTH;
2216
2217 p_ptr->auto_target = options[69];
2218 p_ptr->autooff_retaliator = options[70];
2219 p_ptr->wide_scroll_margin = options[71];
2220 p_ptr->always_repeat = options[6];
2221 p_ptr->fail_no_melee = options[72];
2222
2223 /* in case we toggled linear_stats: */
2224 p_ptr->redraw |= (PR_STATS);
2225
2226 tmp = p_ptr->short_item_names;
2227 if ((p_ptr->short_item_names = options[77]) != tmp) {
2228 /* update inventory */
2229 for (i = 0; i < INVEN_WIELD; i++)
2230 WIPE(&p_ptr->inventory_copy[i], object_type);
2231 p_ptr->window |= PW_INVEN;
2232 }
2233
2234 // bool speak_unique;
2235
2236 p_ptr->uniques_alive = options[32];
2237 p_ptr->overview_startup = options[33];
2238 p_ptr->page_on_privmsg = options[40];
2239 p_ptr->page_on_afk_privmsg = options[41];
2240 p_ptr->auto_untag = options[42];
2241 /* hack: if client doesn't know player_list options yet then assume full list (old) */
2242 if (is_older_than(&p_ptr->version, 4, 4, 7, 1, 0, 0)) {
2243 p_ptr->player_list = FALSE;
2244 p_ptr->player_list2 = FALSE;
2245 } else {
2246 p_ptr->player_list = options[50];
2247 p_ptr->player_list2 = options[51];
2248 }
2249 p_ptr->half_sfx_attack = options[86];
2250 p_ptr->cut_sfx_attack = options[87];
2251
2252 if (is_older_than(&p_ptr->version, 4, 5, 5, 0, 0, 1)) {
2253 p_ptr->sfx_combat = TRUE;
2254 p_ptr->sfx_magicattack = TRUE;
2255 p_ptr->sfx_defense = TRUE;
2256 p_ptr->sfx_monsterattack = TRUE;
2257 p_ptr->sfx_shriek = TRUE;
2258 p_ptr->sfx_store = FALSE;
2259 p_ptr->sfx_house_quiet = TRUE;
2260 p_ptr->sfx_house = TRUE;
2261 p_ptr->no_weather = FALSE;
2262 p_ptr->hilite_player = FALSE;
2263 p_ptr->alert_mana = FALSE;
2264
2265 p_ptr->alert_offpanel_dam = FALSE;
2266 p_ptr->idle_starve_kick = TRUE;
2267 p_ptr->view_lamp_walls = p_ptr->view_lamp_floor;//was the same option so far, now split up
2268 } else {
2269 bool sfx_house_quiet = p_ptr->sfx_house_quiet, sfx_house = p_ptr->sfx_house;
2270 p_ptr->sfx_combat = !options[47];
2271 p_ptr->sfx_magicattack = !options[48];
2272 p_ptr->sfx_defense = !options[49];
2273 p_ptr->sfx_monsterattack = !options[93];
2274 p_ptr->sfx_shriek = !options[94];
2275 p_ptr->sfx_store = !options[96];
2276 p_ptr->sfx_house_quiet = options[97];
2277 p_ptr->sfx_house = !options[98];
2278 if (p_ptr->sfx_house != sfx_house || p_ptr->sfx_house_quiet != sfx_house_quiet) {
2279 if (p_ptr->grid_house) {
2280 if (!p_ptr->sfx_house) Send_sfx_volume(Ind, 0, 0);
2281 else if (p_ptr->sfx_house_quiet) Send_sfx_volume(Ind, p_ptr->sound_ambient == SFX_AMBIENT_FIREPLACE ? 100 : GRID_SFX_REDUCTION, GRID_SFX_REDUCTION);
2282 else Send_sfx_volume(Ind, 100, 100);
2283 }
2284 }
2285 #ifdef CLIENT_SIDE_WEATHER
2286 if (options[99] && !p_ptr->no_weather) {
2287 /* update his client-side weather */
2288 player_weather(Ind, TRUE, TRUE, TRUE);
2289 p_ptr->no_weather = TRUE;
2290 } else p_ptr->no_weather = options[99];
2291 #endif
2292 p_ptr->hilite_player = options[100];
2293 if (p_ptr->pclass == CLASS_WARRIOR || p_ptr->pclass == CLASS_ARCHER) p_ptr->alert_mana = FALSE;
2294 else p_ptr->alert_mana = options[101];
2295 p_ptr->exp_bar = options[103];//just for tracking this feature's popularity =P
2296 p_ptr->consistent_players = options[104];
2297 p_ptr->flash_self = options[105] ? 0 : -1;
2298
2299 if (is_older_than(&p_ptr->version, 4, 5, 8, 2, 0, 0)) {
2300 p_ptr->alert_offpanel_dam = FALSE;
2301 p_ptr->idle_starve_kick = TRUE;
2302 p_ptr->view_lamp_walls = p_ptr->view_lamp_floor;//was the same option so far, now split up
2303 } else {
2304 p_ptr->alert_offpanel_dam = options[106];
2305 p_ptr->idle_starve_kick = options[107];
2306 tmp = p_ptr->view_lamp_walls;
2307 if ((p_ptr->view_lamp_walls = options[3]) != tmp) p_ptr->redraw |= PR_MAP;
2308 }
2309 }
2310 } else { /* 4.5.8.2+ (after 4.5.8a release) */
2311 bool vlf = p_ptr->view_lite_extra;
2312 bool sfx_house_quiet = p_ptr->sfx_house_quiet, sfx_house = p_ptr->sfx_house;
2313
2314 /* unmutable options :D */
2315 p_ptr->last_words = TRUE;
2316
2317 //page 1
2318
2319 p_ptr->rogue_like_commands = options[0];
2320 tmp = p_ptr->newbie_hints;
2321 p_ptr->newbie_hints = options[1];
2322 /* disable some or all newbie hints */
2323 if (!p_ptr->newbie_hints) disable_specific_warnings(p_ptr);
2324 else if (!tmp) msg_print(Ind, "\374\377yEnabling newbie hints requires you to exit and log in again.");
2325 p_ptr->censor_swearing = options[2];
2326
2327 p_ptr->page_on_privmsg = options[5];
2328 p_ptr->page_on_afk_privmsg = options[6];
2329
2330 tmp = p_ptr->font_map_solid_walls;
2331 if ((p_ptr->font_map_solid_walls = options[8]) != tmp) p_ptr->redraw |= PR_MAP;
2332 tmp = p_ptr->view_animated_lite;
2333 if ((p_ptr->view_animated_lite = options[9]) != tmp) p_ptr->redraw |= PR_MAP;
2334
2335 tmp = p_ptr->wall_lighting;
2336 if ((p_ptr->wall_lighting = options[10]) != tmp) p_ptr->redraw |= PR_MAP;
2337 tmp = p_ptr->view_lamp_walls;
2338 if ((p_ptr->view_lamp_walls = options[11]) != tmp) p_ptr->redraw |= PR_MAP;
2339 tmp = p_ptr->view_shade_walls;
2340 if ((p_ptr->view_shade_walls = options[12]) != tmp) p_ptr->redraw |= PR_MAP;
2341
2342 tmp = p_ptr->floor_lighting;
2343 if ((p_ptr->floor_lighting = options[13]) != tmp) p_ptr->redraw |= PR_MAP;
2344 tmp = p_ptr->view_lamp_floor;
2345 if ((p_ptr->view_lamp_floor = options[14]) != tmp) p_ptr->redraw |= PR_MAP;
2346 tmp = p_ptr->view_shade_floor;
2347 if ((p_ptr->view_shade_floor = options[15]) != tmp) p_ptr->redraw |= PR_MAP;
2348 p_ptr->view_lite_extra = options[16];
2349 if (vlf != p_ptr->view_lite_extra) p_ptr->redraw |= PR_MAP;
2350
2351 p_ptr->alert_hitpoints = options[17];
2352 if (p_ptr->pclass == CLASS_WARRIOR || p_ptr->pclass == CLASS_ARCHER) p_ptr->alert_mana = FALSE;
2353 else p_ptr->alert_mana = options[18];
2354 p_ptr->alert_afk_dam = options[19];
2355 p_ptr->alert_offpanel_dam = options[20];
2356 p_ptr->exp_bar = options[21];//just for tracking this feature's popularity =P
2357
2358 //page 2
2359
2360 p_ptr->uniques_alive = options[22];
2361 p_ptr->warn_unique_credit = options[23];
2362 p_ptr->limit_chat = options[24];
2363 p_ptr->no_afk_msg = options[25];
2364 p_ptr->overview_startup = options[26];
2365
2366 /* in case we toggled linear_stats: */
2367 p_ptr->redraw |= (PR_STATS);
2368 //..other client-side only stuff..
2369
2370 tmp = p_ptr->depth_in_feet;
2371 if ((p_ptr->depth_in_feet = options[31]) != tmp) p_ptr->redraw |= PR_DEPTH;
2372 p_ptr->newb_suicide = options[32];
2373
2374 tmp = p_ptr->short_item_names;
2375 if ((p_ptr->short_item_names = options[36]) != tmp) {
2376 /* update inventory */
2377 for (i = 0; i < INVEN_WIELD; i++)
2378 WIPE(&p_ptr->inventory_copy[i], object_type);
2379 p_ptr->window |= PW_INVEN;
2380 }
2381
2382 p_ptr->taciturn_messages = options[39];
2383
2384 #ifdef CLIENT_SIDE_WEATHER
2385 if (options[41] && !p_ptr->no_weather) {
2386 /* update his client-side weather */
2387 player_weather(Ind, TRUE, TRUE, TRUE);
2388 p_ptr->no_weather = TRUE;
2389 } else p_ptr->no_weather = options[41];
2390 #endif
2391 p_ptr->player_list = options[42];
2392 p_ptr->player_list2 = options[43];
2393
2394 //page 3
2395
2396 p_ptr->flash_self = options[44] ? 0 : -1;
2397 p_ptr->hilite_player = options[45];
2398 p_ptr->consistent_players = options[46];
2399
2400 //page 4
2401
2402 p_ptr->auto_afk = options[50];
2403 p_ptr->idle_starve_kick = options[51];
2404 p_ptr->safe_float = options[52];
2405
2406 // p_ptr->auto_destroy = options[];
2407 p_ptr->auto_untag = options[54];
2408 p_ptr->clear_inscr = options[55];
2409 p_ptr->auto_inscribe = options[56];
2410 p_ptr->stack_force_notes = options[57];
2411 p_ptr->stack_force_costs = options[58];
2412 p_ptr->stack_allow_items = options[59];
2413 p_ptr->stack_allow_wands = options[60];
2414
2415 p_ptr->always_repeat = options[62];
2416 p_ptr->always_pickup = options[63];
2417 p_ptr->use_old_target = options[64];
2418 p_ptr->autooff_retaliator = options[65];
2419 p_ptr->fail_no_melee = options[66];
2420 p_ptr->wide_scroll_margin = options[67];
2421 p_ptr->auto_target = options[68];
2422
2423 //page 5
2424
2425 p_ptr->find_ignore_stairs = options[71];
2426 p_ptr->find_ignore_doors = options[72];
2427 p_ptr->find_cut = options[73];
2428 p_ptr->find_examine = options[74];
2429 p_ptr->disturb_move = options[75];
2430 p_ptr->disturb_near = options[76];
2431 p_ptr->disturb_panel = options[77];
2432 p_ptr->disturb_state = options[78];
2433 p_ptr->disturb_minor = options[79];
2434 p_ptr->disturb_other = options[80];
2435 tmp = p_ptr->view_perma_grids;
2436 if ((p_ptr->view_perma_grids = options[81]) != tmp) p_ptr->redraw |= PR_MAP;
2437 tmp = p_ptr->view_torch_grids;
2438 if ((p_ptr->view_torch_grids = options[82]) != tmp) p_ptr->redraw |= PR_MAP;
2439 tmp = p_ptr->view_reduce_lite;
2440 if ((p_ptr->view_reduce_lite = options[83]) != tmp) p_ptr->redraw |= PR_MAP;
2441 tmp = p_ptr->view_reduce_view;
2442 if ((p_ptr->view_reduce_view = options[84]) != tmp) p_ptr->redraw |= PR_MAP;
2443 p_ptr->easy_open = options[85];
2444 p_ptr->easy_disarm = options[86];
2445 p_ptr->easy_tunnel = options[87];
2446
2447 //page 6
2448
2449 // bool speak_unique;
2450 p_ptr->sfx_combat = !options[93];
2451 p_ptr->sfx_magicattack = !options[94];
2452 p_ptr->sfx_defense = !options[95];
2453 p_ptr->half_sfx_attack = options[96];
2454 p_ptr->cut_sfx_attack = options[97];
2455 p_ptr->sfx_monsterattack = !options[103];
2456 p_ptr->sfx_shriek = !options[104];
2457 p_ptr->sfx_store = !options[105];
2458 p_ptr->sfx_house_quiet = options[106];
2459 p_ptr->sfx_house = !options[107];
2460
2461 if (p_ptr->sfx_house != sfx_house ||
2462 p_ptr->sfx_house_quiet != sfx_house_quiet) {
2463 if (p_ptr->grid_house) {
2464 if (!p_ptr->sfx_house) Send_sfx_volume(Ind, 0, 0);
2465 else if (p_ptr->sfx_house_quiet) Send_sfx_volume(Ind, p_ptr->sound_ambient == SFX_AMBIENT_FIREPLACE ? 100 : GRID_SFX_REDUCTION, GRID_SFX_REDUCTION);
2466 else Send_sfx_volume(Ind, 100, 100);
2467 }
2468 }
2469 }
2470 }
2471
2472 /*
2473 * A client has requested to start active play.
2474 * See if we can allocate a player structure for it
2475 * and if this succeeds update the player information
2476 * to all connected players.
2477 */
Handle_login(int ind)2478 static int Handle_login(int ind)
2479 {
2480 connection_t *connp = Conn[ind];
2481 player_type *p_ptr = NULL;
2482 object_type forge, *o_ptr = &forge;
2483 int i, j;
2484 bool options[OPT_MAX], greeting;
2485 char namebuf1[80], namebuf2[80], o_name[ONAME_LEN];
2486 cptr title = "";
2487 char traffic[50+1];
2488 bool newly_created_msg = FALSE;
2489
2490 if (Id >= MAX_ID) {
2491 errno = 0;
2492 plog(format("Id too big (%d)", Id));
2493 return -1;
2494 }
2495
2496 /* This will cause problems for account/char with same name */
2497 #if 0
2498 for (i = 1; i < NumPlayers + 1; i++) {
2499 if (strcasecmp(Players[i]->name, connp->nick) == 0) {
2500 errno = 0;
2501 plog(format("Name already in use %s", connp->nick));
2502 return -1;
2503 }
2504 }
2505 #endif
2506
2507 if (!player_birth(NumPlayers + 1, ind, connp)) {
2508 /* Failed, connection destroyed */
2509 Destroy_connection(ind, "not login");
2510 return -1;
2511 }
2512 p_ptr = Players[NumPlayers + 1];
2513 p_ptr->Ind = NumPlayers + 1;
2514 strcpy(p_ptr->realname, connp->real);
2515 strncpy(p_ptr->hostname, connp->host, 25); /* cap ridiculously long hostnames - C. Blue */
2516 strcpy(p_ptr->accountname, connp->nick);
2517 strcpy(p_ptr->addr, connp->addr);
2518 p_ptr->version = connp->version; /* this actually copies the extended version structure */
2519 p_ptr->v_unknown = is_newer_than(&p_ptr->version, VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_EXTRA, VERSION_BRANCH, !VERSION_BUILD ? 1 : VERSION_BUILD); /* +1: account for 'test' client! */
2520 p_ptr->v_test_latest = is_same_as(&p_ptr->version, VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_EXTRA, VERSION_BRANCH, !VERSION_BUILD ? 1 : VERSION_BUILD);
2521 p_ptr->v_test = !p_ptr->v_unknown && is_newer_than(&p_ptr->version, VERSION_MAJOR_LATEST, VERSION_MINOR_LATEST, VERSION_PATCH_LATEST, VERSION_EXTRA_LATEST, VERSION_BRANCH_LATEST, VERSION_BUILD_LATEST);
2522 p_ptr->v_outdated = !is_newer_than(&p_ptr->version, VERSION_MAJOR_OUTDATED, VERSION_MINOR_OUTDATED, VERSION_PATCH_OUTDATED, VERSION_EXTRA_OUTDATED, VERSION_BRANCH_OUTDATED, VERSION_BUILD_OUTDATED);
2523 p_ptr->v_latest = is_same_as(&p_ptr->version, VERSION_MAJOR_LATEST, VERSION_MINOR_LATEST, VERSION_PATCH_LATEST, VERSION_EXTRA_LATEST, VERSION_BRANCH_LATEST, VERSION_BUILD_LATEST);
2524 p_ptr->audio_sfx = connp->audio_sfx;
2525 p_ptr->audio_mus = connp->audio_mus;
2526
2527 /* Copy the client preferences to the player struct */
2528 for (i = 0; i < OPT_MAX; i++)
2529 options[i] = connp->Client_setup.options[i];
2530
2531 for (i = 0; i < TV_MAX; i++) {
2532 int j;
2533
2534 if (!connp->Client_setup.u_attr[i] &&
2535 !connp->Client_setup.u_char[i])
2536 continue;
2537
2538 /* XXX not max_k_idx, since client doesn't know the value */
2539 for (j = 0; j < MAX_K_IDX; j++) {
2540 if (k_info[j].tval == i) {
2541 p_ptr->d_attr[j] = connp->Client_setup.u_attr[i];
2542 p_ptr->d_char[j] = connp->Client_setup.u_char[i];
2543 }
2544 }
2545 }
2546
2547 for (i = 0; i < MAX_F_IDX; i++) {
2548 /* Hacking the no-floor bug for loth/bree tower/gondo city -C. Blue */
2549 p_ptr->f_attr[i] = connp->Client_setup.f_attr[i];
2550 p_ptr->f_char[i] = connp->Client_setup.f_char[i];
2551 #ifndef FLOORTILEBUG_WORKAROUND
2552 if (!p_ptr->f_attr[i]) p_ptr->f_attr[i] = f_info[i].z_attr;
2553 if (!p_ptr->f_char[i]
2554 || p_ptr->f_char[i] == 31) /* workaround for people who are still using old font-win.prf files with floor tile /31 mapping glitch */
2555 p_ptr->f_char[i] = f_info[i].z_char;
2556 #else /*now all tiles are bright white and never dimmed.*/
2557 p_ptr->f_attr[i] = f_info[i].z_attr;
2558 p_ptr->f_char[i] = f_info[i].z_char;
2559 #endif
2560 /* local, hacked copy: for font_map_solid_walls */
2561 p_ptr->f_char_solid[i] = f_info[i].z_char;
2562 p_ptr->f_attr_solid[i] = f_info[i].z_attr;
2563
2564 }
2565 /* modify solid walls of local copy for font_map_solid_walls */
2566 if (p_ptr->version.os == OS_WIN32) {
2567 p_ptr->f_char_solid[50] = 127; //magma, 8
2568 p_ptr->f_char_solid[52] = 127;
2569 p_ptr->f_char_solid[51] = 127; //quartz, 9
2570 p_ptr->f_attr_solid[51] = 9;
2571 p_ptr->f_char_solid[53] = 127;
2572 p_ptr->f_attr_solid[53] = 9;
2573
2574 p_ptr->f_char_solid[54] = 1; //specialty: magma with treasure (diamond ascii)
2575 p_ptr->f_char_solid[55] = 1; //specialty: quartz with treasure (diamond ascii)
2576
2577 p_ptr->f_char_solid[56] = 127; //granite, 2
2578 p_ptr->f_char_solid[57] = 127;
2579 p_ptr->f_char_solid[58] = 127;
2580 p_ptr->f_char_solid[59] = 127; //perma vaults, 1
2581 p_ptr->f_char_solid[60] = 127;
2582 p_ptr->f_char_solid[61] = 127;
2583 p_ptr->f_char_solid[62] = 127;
2584 p_ptr->f_char_solid[63] = 127;
2585 p_ptr->f_char_solid[26] = 127; //perma houses, 1
2586 p_ptr->f_char_solid[28] = 127;
2587 p_ptr->f_char_solid[75] = 127;
2588 p_ptr->f_char_solid[76] = 127;
2589 p_ptr->f_char_solid[77] = 127;
2590 p_ptr->f_char_solid[78] = 127;
2591 p_ptr->f_char_solid[95] = 127; //ice wall
2592 p_ptr->f_char_solid[98] = 127; //sand wall
2593 p_ptr->f_char_solid[99] = 127;
2594
2595 p_ptr->f_char_solid[100] = 1; //specialty: sand wall with treasure (diamond ascii)
2596
2597 p_ptr->f_char_solid[177] = 127;
2598 p_ptr->f_char_solid[188] = 127;
2599 p_ptr->f_char_solid[189] = 127;
2600 p_ptr->f_char_solid[190] = 127; //house roofs, 11
2601 p_ptr->f_char_solid[191] = 127;
2602 p_ptr->f_char_solid[193] = 127; //house roofs, 4
2603 p_ptr->f_char_solid[194] = 127;
2604 } else {
2605 /* assume OS_X11 -- does this work on OSX/GCU too? */
2606 p_ptr->f_char_solid[50] = 2; //magma, 8
2607 p_ptr->f_char_solid[52] = 2;
2608 p_ptr->f_char_solid[51] = 2; //quartz, 9
2609 p_ptr->f_attr_solid[51] = 9;
2610 p_ptr->f_char_solid[53] = 2;
2611 p_ptr->f_attr_solid[53] = 9;
2612
2613 p_ptr->f_char_solid[54] = 1; //specialty: magma with treasure (diamond ascii)
2614 p_ptr->f_char_solid[55] = 1; //specialty: quartz with treasure (diamond ascii)
2615
2616 p_ptr->f_char_solid[56] = 2; //granite, 2
2617 p_ptr->f_char_solid[57] = 2;
2618 p_ptr->f_char_solid[58] = 2;
2619 p_ptr->f_char_solid[59] = 2; //perma vaults, 1
2620 p_ptr->f_char_solid[60] = 2;
2621 p_ptr->f_char_solid[61] = 2;
2622 p_ptr->f_char_solid[62] = 2;
2623 p_ptr->f_char_solid[63] = 2;
2624 p_ptr->f_char_solid[26] = 2; //perma houses, 1
2625 p_ptr->f_char_solid[28] = 2;
2626 p_ptr->f_char_solid[75] = 2;
2627 p_ptr->f_char_solid[76] = 2;
2628 p_ptr->f_char_solid[77] = 2;
2629 p_ptr->f_char_solid[78] = 2;
2630 p_ptr->f_char_solid[95] = 2; //ice walls
2631 p_ptr->f_char_solid[98] = 2; //sand wall
2632 p_ptr->f_char_solid[99] = 2;
2633
2634 p_ptr->f_char_solid[100] = 1; //specialty: sand wall with treasure (diamond ascii)
2635
2636 p_ptr->f_char_solid[177] = 2;
2637 p_ptr->f_char_solid[188] = 2;
2638 p_ptr->f_char_solid[189] = 2;
2639 p_ptr->f_char_solid[190] = 2; //house roofs, 11
2640 p_ptr->f_char_solid[191] = 2;
2641 p_ptr->f_char_solid[193] = 2; //house roofs, 4
2642 p_ptr->f_char_solid[194] = 2;
2643 }
2644
2645 for (i = 0; i < MAX_K_IDX; i++) {
2646 p_ptr->k_attr[i] = connp->Client_setup.k_attr[i];
2647 p_ptr->k_char[i] = connp->Client_setup.k_char[i];
2648
2649 if (!p_ptr->k_attr[i]) p_ptr->k_attr[i] = k_info[i].x_attr;
2650 if (!p_ptr->k_char[i]) p_ptr->k_char[i] = k_info[i].x_char;
2651
2652 #if 1
2653 if (!p_ptr->d_attr[i]) p_ptr->d_attr[i] = k_info[i].d_attr;
2654 if (!p_ptr->d_char[i]) p_ptr->d_char[i] = k_info[i].d_char;
2655 #else
2656 if (!p_ptr->k_attr[i]) p_ptr->d_attr[i] = k_info[i].d_attr;
2657 if (!p_ptr->k_char[i]) p_ptr->d_char[i] = k_info[i].d_char;
2658 #endif // 0
2659 }
2660
2661 /* Hack -- acquire a flag for ego-monsters - Jir - */
2662 p_ptr->use_r_gfx = FALSE;
2663
2664 for (i = 0; i < MAX_R_IDX; i++) {
2665 p_ptr->r_attr[i] = connp->Client_setup.r_attr[i];
2666 p_ptr->r_char[i] = connp->Client_setup.r_char[i];
2667
2668 if (!p_ptr->r_attr[i]) p_ptr->r_attr[i] = r_info[i].x_attr;
2669 else p_ptr->use_r_gfx = TRUE;
2670
2671 if (!p_ptr->r_char[i]) p_ptr->r_char[i] = r_info[i].x_char;
2672 else p_ptr->use_r_gfx = TRUE;
2673 }
2674
2675 sync_options(NumPlayers + 1, options);
2676
2677 GetInd[Id] = NumPlayers + 1;
2678
2679 NumPlayers++;
2680 if (!is_admin(p_ptr)) NumNonAdminPlayers++;
2681 if (NumNonAdminPlayers > MaxSimultaneousPlayers) {
2682 MaxSimultaneousPlayers = NumPlayers;
2683 if (MaxSimultaneousPlayers > 15) s_printf("SimultaneousPlayers (above 15): %d\n", MaxSimultaneousPlayers);
2684 }
2685 connp->id = Id++;
2686
2687 //Conn_set_state(connp, CONN_READY, CONN_PLAYING);
2688 Conn_set_state(connp, CONN_PLAYING, CONN_PLAYING);
2689
2690 if (Send_reply(ind, PKT_PLAY, PKT_SUCCESS) <= 0) {
2691 plog("Cannot send play reply");
2692 return -1;
2693 }
2694
2695 /* Send party/guild information */
2696 Send_party(NumPlayers, FALSE, FALSE);
2697 /* Guild timed out meanwhile? (Leaderless for too long) */
2698 if (p_ptr->guild &&
2699 (!guilds[p_ptr->guild].members || guilds[p_ptr->guild].dna != p_ptr->guild_dna)) {
2700 p_ptr->guild = 0;
2701 clockin(NumPlayers, 3);
2702 }
2703 Send_guild(NumPlayers, FALSE, FALSE);
2704 Send_guild_config(p_ptr->guild);
2705
2706 /* Hack -- terminate the data stream sent to the client */
2707 if (Packet_printf(&connp->c, "%c", PKT_END) <= 0) {
2708 Destroy_connection(p_ptr->conn, "write error");
2709 return -1;
2710 }
2711
2712 if (Send_reliable(ind) == -1) {
2713 Destroy_connection(ind, "Couldn't send reliable data");
2714 return -1;
2715 }
2716
2717 num_logins++;
2718
2719 save_server_info();
2720
2721 /* Execute custom script if player joins the server */
2722 if (first_player_joined) {
2723 first_player_joined = FALSE;
2724 exec_lua(NumPlayers, format("first_player_has_joined(%d, %d, \"%/s\", \"%s\")", NumPlayers, p_ptr->id, p_ptr->name, showtime()));
2725 }
2726 if (NumPlayers == 1) exec_lua(NumPlayers, format("player_has_joined_empty_server(%d, %d, \"%/s\", \"%s\")", NumPlayers, p_ptr->id, p_ptr->name, showtime()));
2727 exec_lua(NumPlayers, format("player_has_joined(%d, %d, \"%/s\", \"%s\")", NumPlayers, p_ptr->id, p_ptr->name, showtime()));
2728 strcpy(traffic, "");
2729 for (i = 1; (i <= NumPlayers) && (i < 50); i++)
2730 if (!(i % 5)) strcat(traffic, "* "); else strcat(traffic, "*");
2731 p_printf("%s + %03d %s\n", showtime(), NumPlayers, traffic);
2732
2733 /* Initialize his mimic spells. - C. Blue
2734 Note: This is actually done earlier in time via calc_body_bonus(),
2735 but at that point, the connection is not yet ready to receive spell info. */
2736 calc_body_spells(NumPlayers);
2737
2738 /* check pending notes to this player -C. Blue */
2739 for (i = 0; i < MAX_ADMINNOTES; i++) {
2740 if (strcmp(admin_note[i], "")) {
2741 msg_format(NumPlayers, "\377sMotD: %s", admin_note[i]);
2742 }
2743 }
2744 for (i = 0; i < MAX_NOTES; i++) {
2745 strcpy(namebuf1, priv_note_target[i]);
2746 strcpy(namebuf2, connp->nick);
2747 j = 0; while(namebuf1[j]) { namebuf1[j] = tolower(namebuf1[j]); j++; }
2748 j = 0; while(namebuf2[j]) { namebuf2[j] = tolower(namebuf2[j]); j++; }
2749 // if (!strcmp(priv_note_target[i], p_ptr->name)) { /* <- sent to a character name */
2750 // if (!strcmp(priv_note_target[i], connp->nick)) { /* <- sent to an account name */
2751 if (!strcmp(namebuf1, namebuf2)) { /* <- sent to an account name, case-independant */
2752 msg_format(NumPlayers, "\374\377RNote from %s: %s", priv_note_sender[i], priv_note[i]);
2753 strcpy(priv_note_sender[i], "");
2754 strcpy(priv_note_target[i], "");
2755 strcpy(priv_note[i], "");
2756 }
2757 }
2758 if (p_ptr->party) for (i = 0; i < MAX_PARTYNOTES; i++) {
2759 if (!strcmp(party_note_target[i], parties[p_ptr->party].name)) {
2760 if (strcmp(party_note[i], ""))
2761 msg_format(NumPlayers, "\374\377bParty Note: %s", party_note[i]);
2762 break;
2763 }
2764 }
2765 if (p_ptr->guild) for (i = 0; i < MAX_GUILDNOTES; i++) {
2766 if (!strcmp(guild_note_target[i], guilds[p_ptr->guild].name)) {
2767 if (strcmp(guild_note[i], ""))
2768 msg_format(NumPlayers, "\374\377bGuild Note: %s", guild_note[i]);
2769 break;
2770 }
2771 }
2772 if (server_warning[0]) msg_format(NumPlayers, "\374\377R*** Note: %s ***", server_warning);
2773
2774 /* Warn the player if some of his/her characters are about to expire */
2775 account_checkexpiry(NumPlayers);
2776
2777 #ifndef ARCADE_SERVER
2778 /* Brand-new players get super-short instructions presented here: */
2779 greeting = !(acc_get_flags(p_ptr->accountname) & ACC_GREETED);
2780 if (p_ptr->inval || greeting) {
2781 s_printf("GREETING: %s\n", p_ptr->name);
2782
2783 /* no bloody noob ever seems to read this how2run thingy.. (p_ptr->warning_welcome) */
2784 msg_print(NumPlayers, "\374\377y ");
2785 msg_print(NumPlayers, "\374\377y *** Welcome to Tomenet! You can chat with \377R:\377y key. Say hello :) ***");
2786 msg_print(NumPlayers, "\374\377y To run fast, use \377oSHIFT+direction\377y keys (\377oNUMLOCK\377y must be OFF)");
2787 if (p_ptr->warning_wield == 0)
2788 msg_print(NumPlayers, "\374\377y Before you move out, press \377ow\377y to equip your weapon and armour!");
2789 else
2790 msg_print(NumPlayers, "\374\377y Before you move out, press \377ow\377y to equip your starting items!");
2791 msg_print(NumPlayers, "\374\377y ");
2792 // msg_print(NumPlayers, "\377RTurn off \377oNUMLOCK\377R and hit \377oSHIFT+numkeys\377R to run (move quickly).");
2793 // msg_print(NumPlayers, "\377RHit '\377o?\377R' key for help. Hit '\377o:\377R' to chat. Hit '\377o@\377R' to see who is online.");
2794 // msg_print(NumPlayers, "\377R<< Welcome to TomeNET! >>");
2795
2796 /* Play audio greeting too! - C. Blue */
2797 if (greeting) { /* only the very 1st time, might become annoying */
2798 s_printf("GREETING_AUDIO: %s\n", p_ptr->name);
2799 sound(NumPlayers, "greeting", NULL, SFX_TYPE_MISC, FALSE);
2800
2801 acc_set_flags(p_ptr->accountname, ACC_GREETED, TRUE);
2802 }
2803 }
2804 /* Notify all online admins about an invalid player having joined, so they may validate him */
2805 if (p_ptr->inval) for (i = 1; i < NumPlayers + 1; i++) {
2806 if (Players[i]->conn == NOT_CONNECTED) continue;
2807 if (!is_admin(Players[i])) continue;
2808 msg_format(i, "\374\377R(Admin) Invalid account \"%s\", host: \"%s\"", p_ptr->accountname, p_ptr->hostname);
2809 if (!Players[i]->paging) Players[i]->paging = 2;
2810 }
2811
2812 /* warning_rest only occurs once per account */
2813 if (acc_get_flags(p_ptr->accountname) & ACC_WARN_REST) p_ptr->warning_rest = 3;
2814 #else
2815 /* no greeting */
2816 greeting = FALSE;
2817
2818 /* auto-validate */
2819 if (acc_get_flags(p_ptr->accountname) & ACC_TRIAL)
2820 validate(p_ptr->accountname);
2821 #endif
2822
2823 #if 1
2824 /* Give a more visible message about outdated client usage - C. Blue */
2825 if (!is_newer_than(&p_ptr->version, VERSION_MAJOR_OUTDATED, VERSION_MINOR_OUTDATED, VERSION_PATCH_OUTDATED, VERSION_EXTRA_OUTDATED, VERSION_BRANCH_OUTDATED, VERSION_BUILD_OUTDATED)) {
2826 msg_print(NumPlayers, "\374\377y --- Your client is outdated! Get newest one from www.tomenet.eu ---");
2827 } else if (is_older_than(&p_ptr->version, VERSION_MAJOR_LATEST, VERSION_MINOR_LATEST, VERSION_PATCH_LATEST, VERSION_EXTRA_LATEST, VERSION_BRANCH_LATEST, VERSION_BUILD_LATEST)) {
2828 msg_print(NumPlayers, "\374\377D --- Your client is NOT the latest version, it's not 'outdated' though. ---");
2829 }
2830 #endif
2831 #if 0
2832 if (p_ptr->audio_mus == 49) /* problem: cannot take into account if the player purposefully removed some songs */
2833 msg_print(NumPlayers, "\374\377D --- Your music pack is outdated. ---");
2834 else if (p_ptr->audio_mus == 55 || p_ptr->audio_mus == 56) /* problem: cannot take into account if the player purposefully removed some songs */
2835 msg_print(NumPlayers, "\374\377D --- Your music pack is outdated. ---");
2836 #else
2837 /* In 4.5.7 we can now distinguish (client-side) between disabled and unavailable audio */
2838 if (p_ptr->audio_sfx > 3 && p_ptr->audio_sfx < __audio_sfx_max) msg_print(NumPlayers, "\374\377D --- Warning: Your sound pack is outdated! ---");
2839 if (p_ptr->audio_mus && p_ptr->audio_mus < __audio_mus_max) msg_print(NumPlayers, "\374\377D --- Warning: Your music pack is outdated! ---");
2840 #endif
2841
2842 /* Admin messages */
2843 if (p_ptr->admin_dm)
2844 switch (cfg.runlevel) {
2845 case 2051:
2846 msg_print(NumPlayers, "\377y* XtremelyLow-server-shutdown command pending *");
2847 break;
2848 case 2048:
2849 msg_print(NumPlayers, "\377y* Empty-server-shutdown command pending *");
2850 break;
2851 case 2047:
2852 msg_print(NumPlayers, "\377y* Low-server-shutdown command pending *");
2853 break;
2854 case 2046:
2855 msg_print(NumPlayers, "\377y* VeryLow-server-shutdown command pending *");
2856 break;
2857 case 2045:
2858 msg_print(NumPlayers, "\377y* None-server-shutdown command pending *");
2859 break;
2860 case 2044:
2861 msg_print(NumPlayers, "\377y* ActiveVeryLow-server-shutdown command pending *");
2862 break;
2863 case 2043:
2864 msg_print(NumPlayers, "\377y* Recall-server-shutdown command pending *");
2865 break;
2866 case 2042:
2867 msg_print(NumPlayers, "\377y* Recall-server-termination command pending *");
2868 break;
2869 }
2870
2871 if (cfg.runlevel == 2043 || cfg.runlevel == 2042) {
2872 if (shutdown_recall_timer >= 120)
2873 msg_format(NumPlayers, "\374\377I*** \377RServer shutdown in %d minutes (auto-recall). \377I***", shutdown_recall_timer / 60);
2874 else
2875 msg_format(NumPlayers, "\374\377I*** \377RServer shutdown in %d seconds (auto-recall). \377I***", shutdown_recall_timer);
2876 }
2877
2878 if (p_ptr->xorder_id) {
2879 for (i = 0; i < MAX_XORDERS; i++) {
2880 if (xorders[i].id == p_ptr->xorder_id) {
2881 msg_format(NumPlayers, "\377oYour order to exterminate \377y%d \377g%s\377o (level %d) is still valid.",
2882 p_ptr->xorder_num, r_name + r_info[xorders[i].type].name, r_info[xorders[i].type].level);
2883 break;
2884 }
2885 }
2886 }
2887
2888 if(!(p_ptr->mode & MODE_NO_GHOST) &&
2889 !(p_ptr->mode & MODE_EVERLASTING) &&
2890 !(p_ptr->mode & MODE_PVP) &&
2891 !cfg.no_ghost && cfg.lifes)
2892 {
2893 #if 0
2894 /* if total_winner char was loaded from old save game that
2895 didn't reduce his/her lifes to 1 on winning, do that now: */
2896 if (p_ptr->total_winner && (p_ptr->lives > 1+1)) {
2897 msg_print(NumPlayers, "\377yTake care! As a winner, you have no more resurrections left!");
2898 p_ptr->lives = 1+1;
2899 }
2900 #endif
2901 if (p_ptr->lives-1 == 1)
2902 msg_print(NumPlayers, "\377GYou have no more resurrections left!");
2903 else
2904 msg_format(NumPlayers, "\377GYou have %d resurrections left.", p_ptr->lives-1-1);
2905 }
2906
2907 /* for PvP mode chars */
2908 if (p_ptr->free_mimic) msg_format(NumPlayers, "\377GYou have %d free mimicry transformation left.", p_ptr->free_mimic);
2909
2910 /* receive previously buffered global-event-contender-deed from other character of her/his account */
2911 for (i = 0; i < MAX_CONTENDER_BUFFERS; i++) {
2912 if (ge_contender_buffer_ID[i] == p_ptr->account) {
2913 ge_contender_buffer_ID[i] = 0;
2914 i = lookup_kind(TV_PARCHMENT, ge_contender_buffer_deed[i]);
2915 invcopy(o_ptr, i);
2916 o_ptr->number = 1;
2917 object_aware(NumPlayers, o_ptr);
2918 object_known(o_ptr);
2919 o_ptr->discount = 0;
2920 o_ptr->level = 0;
2921 o_ptr->ident |= ID_MENTAL;
2922 inven_carry(NumPlayers, o_ptr);
2923 msg_print(NumPlayers, "\377GAs a former contender in an event, you have received a deed!");
2924 }
2925 }
2926 /* receive previously buffered achievement deed (pvp) from other character of her/his account */
2927 for (i = 0; i < MAX_ACHIEVEMENT_BUFFERS; i++) {
2928 if (achievement_buffer_ID[i] == p_ptr->account) {
2929 switch (achievement_buffer_deed[i]) {
2930 case SV_DEED_PVP_MAX: /* this one is transferrable to non-pvp char */
2931 break;
2932 case SV_DEED_PVP_MID:
2933 case SV_DEED_PVP_MASS:
2934 if (!(p_ptr->mode & MODE_PVP)) continue;
2935 break;
2936 }
2937 achievement_buffer_ID[i] = 0;
2938 i = lookup_kind(TV_PARCHMENT, achievement_buffer_deed[i]);
2939 invcopy(o_ptr, i);
2940 o_ptr->number = 1;
2941 object_aware(NumPlayers, o_ptr);
2942 object_known(o_ptr);
2943 o_ptr->discount = 0;
2944 o_ptr->level = 0;
2945 o_ptr->ident |= ID_MENTAL;
2946 inven_carry(NumPlayers, o_ptr);
2947 msg_print(NumPlayers, "\377GFor your achievements, you have received a deed!");
2948 }
2949 }
2950
2951 /* Sold something in his player store while he wasn't logged on? */
2952 if (acc_get_flags(p_ptr->accountname) & ACC_WARN_SALE) {
2953 acc_set_flags(p_ptr->accountname, ACC_WARN_SALE, FALSE);
2954 msg_print(NumPlayers, "\374\377yA store of yours has sold something meanwhile!");
2955 }
2956
2957 #if 1 /* hm, too much spam? - but usually you'd get this notification anyway, if logged in a bit earlier.. */
2958 #define GE_FINAL_ANNOUNCEMENT 300 /* keep consistent with xtra1.c */
2959 for (i = 0; i < MAX_GLOBAL_EVENTS; i++)
2960 if ((global_event[i].getype != GE_NONE) && (global_event[i].hidden == FALSE || is_admin(p_ptr))) {
2961 int time_left = global_event[i].announcement_time - ((turn - global_event[i].start_turn) / cfg.fps);
2962 /* Event is not in announcement phase anymore? */
2963 if (time_left <= 0) continue;
2964 /* Final announcement has not yet been made? */
2965 if (global_event[i].announcement_time * cfg.fps -
2966 (turn - global_event[i].start_turn - global_event[i].paused_turns) //<- 'elapsed_time'
2967 >= GE_FINAL_ANNOUNCEMENT * cfg.fps)
2968 continue;
2969 #if 0
2970 msg_format(Ind, " \377U%d\377W) '%s' recruits for %d more minutes.",
2971 i + 1, global_event[i].title, (global_event[i].announcement_time - ((turn - global_event[i].start_turn) / cfg.fps)) / 60);
2972 #else
2973 if (time_left >= 120) msg_format(NumPlayers, "\374\377W[%s (\377U%d\377W) starts in %d minutes]", global_event[i].title, i + 1, time_left / 60);
2974 else msg_format(NumPlayers, "\374\377W[%s (%d) starts in %d seconds!]", global_event[i].title, i + 1, time_left);
2975 #endif
2976 }
2977 #endif
2978
2979 /* display some warnings if an item will severely conflict with Martial Arts skill */
2980 if (get_skill(p_ptr, SKILL_MARTIAL_ARTS)) {
2981 bool warn_takeoff = FALSE;
2982
2983 if (!p_ptr->warning_ma_weapon &&
2984 (p_ptr->inventory[INVEN_WIELD].k_idx ||
2985 is_weapon(p_ptr->inventory[INVEN_ARM].tval) || /* for dual-wielders */
2986 #ifndef ENABLE_MA_BOOMERANG
2987 p_ptr->inventory[INVEN_BOW].k_idx)) {
2988 #else
2989 p_ptr->inventory[INVEN_BOW].tval == TV_BOW)) {
2990 #endif
2991 #ifndef ENABLE_MA_BOOMERANG
2992 msg_print(NumPlayers, "\374\377RWarning: Using any sort of weapon renders Martial Arts skill effectless.");
2993 #else
2994 msg_print(NumPlayers, "\374\377RWarning: Using any melee weapon or bow renders Martial Arts skill effectless.");
2995 #endif
2996 warn_takeoff = TRUE;
2997
2998 /* might find esp-weapon at non-low levels, so stop spamming this warning then */
2999 if (p_ptr->lev >= 15) p_ptr->warning_ma_weapon = 1;
3000 }
3001 if (!p_ptr->warning_ma_shield &&
3002 p_ptr->inventory[INVEN_ARM].k_idx) {
3003 msg_print(NumPlayers, "\374\377RWarning: Using a shield will prevent Martial Arts combat styles.");
3004 warn_takeoff = TRUE;
3005
3006 /* might find esp-shield at non-low levels, so stop spamming this warning then */
3007 if (p_ptr->lev >= 15) p_ptr->warning_ma_shield = 1;
3008 }
3009 if (warn_takeoff) msg_print(NumPlayers, "\374\377R Press 't' key to take off your weapons or shield.");
3010 }
3011
3012 /* automatically re-add him to the guild of his last character? */
3013 namebuf1[0] = '\0'; //abuse namebuf1
3014 if ((i = acc_get_guild(p_ptr->accountname))) {
3015 #if 1
3016 if (p_ptr->newly_created) {
3017 #else /* add char if it's level 1 */
3018 if (p_ptr->lev == 1) {
3019 #endif
3020 /* within time limit [20 minutes]? */
3021 time_t now = time(&now);
3022 #if 0 /* add char if it's within 20 min */
3023 if (now - lookup_player_laston(p_ptr->id) <= 60 * 20 && /* always true, since char was newly created! gotta use acc_laston or just ignore */
3024 #else
3025 if (
3026 #endif
3027 guilds[i].members /* guild still exists? */
3028 && guilds[i].dna == acc_get_guild_dna(p_ptr->accountname)) { /* and is still the SAME guild? */
3029 /* auto-re-add him to the guild */
3030 if (guild_auto_add(NumPlayers, i, namebuf1)) {
3031 /* also restore his 'adder' status if he was one */
3032 if ((acc_get_flags(p_ptr->accountname) & ACC_GUILD_ADDER)) {
3033 #ifdef GUILD_ADDERS_LIST
3034 /* check for vacant adder slot */
3035 for (i = 0; i < 5; i++)
3036 if (guilds[p_ptr->guild].adder[i][0] == '\0') break;
3037 /* success? */
3038 if (i != 5) {
3039 strcpy(guilds[p_ptr->guild].adder[i], p_ptr->name);
3040 p_ptr->guild_flags |= PGF_ADDER;
3041 }
3042 }
3043 #else
3044 p_ptr->guild_flags |= PGF_ADDER;
3045 }
3046 #endif
3047 }
3048 }
3049 }
3050 acc_set_guild(p_ptr->accountname, 0);
3051 acc_set_flags(p_ptr->accountname, ACC_GUILD_ADDER, FALSE);
3052 }
3053
3054 #ifdef GUILD_ADDERS_LIST
3055 /* Erase his PGF_ADDER flag if he's been removed from the adder list. */
3056 if ((p_ptr->guild_flags & PGF_ADDER)) {
3057 for (i = 0; i < 5; i++)
3058 if (streq(guilds[p_ptr->guild].adder[i], p_ptr->name)) break;
3059 if (i == 5) {
3060 p_ptr->guild_flags &= ~PGF_ADDER;
3061 msg_format(NumPlayers, "\374\377%cYour authorization to add others to the guild has been \377rretracted\377%c.", COLOUR_CHAT_GUILD, COLOUR_CHAT_GUILD);
3062 }
3063 }
3064 #endif
3065
3066 if (p_ptr->IDDC_logscum) msg_print(NumPlayers, "\377RThis floor has become stale, take a staircase to move on!");
3067
3068 /* some one-time hints and other stuff after char creation in player_birth() */
3069 if (p_ptr->newly_created) {
3070 p_ptr->newly_created = FALSE;
3071
3072 /* hints */
3073 newly_created_msg = TRUE;
3074 if (p_ptr->mode & MODE_PVP) {
3075 msg_print(NumPlayers, "\377yType \"/pvp\" into chat to enter the pvp arena, and again to leave it.");
3076
3077 if (p_ptr->inval) {
3078 msg_print(NumPlayers, "\374\377RNOTE: 'PvP mode' is a special type of gameplay. NOT recommended for beginners!");
3079 msg_print(NumPlayers, "\374\377R If you didn't choose PvP mode on purpose, press \377oSHIFT+q\377R to start over.");
3080 }
3081 }
3082
3083 /* pre-know certain special items without need for ID */
3084 #ifdef PLAYER_STORES
3085 p_ptr->obj_aware[lookup_kind(TV_SCROLL, SV_SCROLL_CHEQUE)] = TRUE;
3086 #endif
3087 #ifdef NEW_WILDERNESS_MAP_SCROLLS
3088 p_ptr->obj_aware[lookup_kind(TV_SCROLL, SV_SCROLL_WILDERNESS_MAP)] = TRUE;
3089 #endif
3090 }
3091
3092 #ifdef ENABLE_DRACONIAN_TRAITS
3093 if (p_ptr->prace == RACE_DRACONIAN && !p_ptr->ptrait) {
3094 msg_print(NumPlayers, "\377oDraconians now have specific 'traits'. You do not have one yet!");
3095 msg_print(NumPlayers, "\377o Press '\377R:\377o' key to chat and enter the command \377R/trait\377o to get one.");
3096 }
3097 #endif
3098
3099 #ifdef FLUENT_ARTIFACT_RESETS
3100 for (i = 0; i < INVEN_TOTAL; i++) {
3101 if (!p_ptr->inventory[i].k_idx) continue;
3102 j = p_ptr->inventory[i].name1;
3103 if (!j || j == ART_RANDART) continue;
3104 if (!(p_ptr->inventory[i].ident & ID_MENTAL)) continue;
3105 if (a_info[j].timeout <= 0 || a_info[j].timeout > FLUENT_ARTIFACT_WARNING || cfg.persistent_artifacts) continue;
3106 object_desc(NumPlayers, o_name, &p_ptr->inventory[i], TRUE, 128);
3107 msg_format(NumPlayers, "\374\377RYour %s will vanish soon!", o_name);
3108 }
3109 if (p_ptr->fluent_artifact_reset == TRUE) {
3110 msg_print(NumPlayers, "\374\377ROne or more true artifacts have bidden you farewell!");
3111 p_ptr->fluent_artifact_reset = FALSE;
3112 }
3113 #endif
3114
3115 /* Check Morgoth, if player had saved a level where he was generated */
3116 check_Morgoth(NumPlayers);
3117
3118 /* Initialise his temporary quest helper information */
3119 quest_check_player_location(NumPlayers);
3120
3121 #if defined(DUNGEON_VISIT_BONUS) || defined(ALLOW_NR_CROSS_PARTIES) || defined(ALLOW_NR_CROSS_ITEMS)
3122 wpcopy(&Players[NumPlayers]->wpos_old, &p_ptr->wpos);
3123 #endif
3124
3125 #ifdef CLIENT_SIDE_WEATHER
3126 /* update his client-side weather */
3127 player_weather(NumPlayers, TRUE, TRUE, TRUE);
3128 #endif
3129
3130 #ifdef AUCTION_SYSTEM
3131 auction_player_joined(NumPlayers);
3132 #endif
3133
3134 #ifdef USE_SOUND_2010
3135 /* Initialize his background music */
3136 p_ptr->music_current = -1; //hack-init: since 0 is used too..
3137 p_ptr->musicalt_current = -1;
3138 p_ptr->sound_ambient = -1; //hack-init: since 0 is used too..
3139 p_ptr->music_monster = -1; //hack-init: since 0 is used too.. (boss-specific music)
3140
3141 /* Keep music quiet for a moment to allow player to hear the introduction speech? */
3142 if (greeting && p_ptr->audio_mus > 0 && p_ptr->audio_sfx >= 2) /* speech is event #2 in unmodified sounds.cfg */
3143 p_ptr->music_start = 20; /* wait for this # of turns until starting the music */
3144 else
3145 handle_music(NumPlayers); /* start music normally (instantly) */
3146
3147 /* Don't skip the first attack sfx (in case player enabled half_sfx_attack or cut_sfx_attack) */
3148 p_ptr->count_cut_sfx_attack = 500;
3149 #endif
3150
3151 /* Note: p_ptr->sound_ambient must be initialised to -1 before calling this. */
3152 grid_affects_player(NumPlayers);
3153
3154 #ifdef USE_SOUND_2010
3155 /* Note: This must come after grid_affects_players() has been called initially. */
3156 handle_ambient_sfx(NumPlayers, &(getcave(&p_ptr->wpos)[p_ptr->py][p_ptr->px]), &p_ptr->wpos, FALSE);
3157 #endif
3158
3159 /* Initialize the client's unique list;
3160 it will become further updated each time he kills another unique */
3161 for (i = 0; i < MAX_R_IDX; i++)
3162 if (r_info[i].flags1 & RF1_UNIQUE)
3163 Send_unique_monster(NumPlayers, i);
3164
3165 #if 0 /* not here, but below instead. Or admins will be shown in the list! */
3166 #ifdef TOMENET_WORLDS
3167 world_player(p_ptr->id, p_ptr->name, TRUE, TRUE); /* last flag is 'quiet' mode -> no public msg */
3168 #endif
3169 #endif
3170
3171
3172 /* Prepare title for possibly telling others about our new player (or admin) */
3173 title = "";
3174 if (p_ptr->admin_dm) title = (p_ptr->male) ? "Dungeon Master " : "Dungeon Mistress ";
3175 else if (p_ptr->admin_wiz) title = "Dungeon Wizard ";
3176 else if (p_ptr->total_winner) {
3177 if (p_ptr->mode & (MODE_HARD | MODE_NO_GHOST)) {
3178 title = (p_ptr->male)?"Emperor ":((!strcmp(p_ptr->name,"Tina"))?"Tiny ":"Empress ");
3179 } else {
3180 title = (p_ptr->male) ? "King " : "Queen ";
3181 }
3182 }
3183
3184 /* Handle the cfg_secret_dungeon_master option: Only tell other admins. */
3185 if (p_ptr->admin_dm && (cfg.secret_dungeon_master)) {
3186 /* Tell other secret dungeon masters about our new player */
3187 for (i = 1; i < NumPlayers; i++) {
3188 if (Players[i]->conn == NOT_CONNECTED) continue;
3189 if (!is_admin(Players[i])) continue;
3190
3191 if (newly_created_msg) {
3192 if (p_ptr->fruit_bat)
3193 msg_format(i, "\374\377%c%s%s flaps %s wings into the world.", COLOUR_SERVER, title, p_ptr->name, (p_ptr->male?"his":"her"));
3194 else
3195 msg_format(i, "\374\377%c%s%s sets foot into the world.", COLOUR_SERVER, title, p_ptr->name);
3196 } else
3197 msg_format(i, "\374\377%c%s%s has entered the game.", COLOUR_SERVER, title, p_ptr->name);
3198 if (namebuf1[0] && Players[i]->guild == p_ptr->guild) msg_print(i, namebuf1);
3199 }
3200 return 0;
3201 }
3202
3203 #ifdef TOMENET_WORLDS
3204 world_player(p_ptr->id, p_ptr->name, TRUE, TRUE); /* last flag is 'quiet' mode -> no public msg */
3205 #endif
3206
3207 /* Tell everyone about our new player */
3208 for (i = 1; i < NumPlayers; i++) {
3209 if (Players[i]->conn == NOT_CONNECTED) continue;
3210 if (newly_created_msg) {
3211 if (p_ptr->fruit_bat)
3212 msg_format(i, "\374\377%c%s%s flaps %s wings into the world.", COLOUR_SERVER, title, p_ptr->name, (p_ptr->male?"his":"her"));
3213 else
3214 msg_format(i, "\374\377%c%s%s sets foot into the world.", COLOUR_SERVER, title, p_ptr->name);
3215 } else
3216 msg_format(i, "\374\377%c%s%s has entered the game.", COLOUR_SERVER, title, p_ptr->name);
3217
3218 /* print notification message about guild-auto-add now */
3219 if (namebuf1[0] && Players[i]->guild == p_ptr->guild) msg_print(i, namebuf1);
3220 }
3221
3222 #ifdef TOMENET_WORLDS
3223 if (cfg.worldd_pjoin) {
3224 if (newly_created_msg) {
3225 if (p_ptr->fruit_bat)
3226 world_msg(format("\374\377%c%s%s flaps %s wings into the world.", COLOUR_SERVER, title, p_ptr->name, (p_ptr->male?"his":"her")));
3227 else
3228 world_msg(format("\374\377%c%s%s sets foot into the world.", COLOUR_SERVER, title, p_ptr->name));
3229 } else
3230 world_msg(format("\374\377%c%s%s has entered the game.", COLOUR_SERVER, title, p_ptr->name));
3231 }
3232 #endif
3233
3234 /* Tell the meta server about the new player */
3235 Report_to_meta(META_UPDATE);
3236
3237 return 0;
3238 }
3239
3240 /* wrapper function for local 'Conn' - C. Blue */
3241 int is_inactive(int Ind) {
3242 if (Conn[Players[Ind]->conn]->inactive_keepalive)
3243 return (Conn[Players[Ind]->conn]->inactive_keepalive);
3244 else
3245 return (Conn[Players[Ind]->conn]->inactive_ping / 2);
3246 }
3247
3248 /* Actually execute commands from the client command queue */
3249 void process_pending_commands(int ind)
3250 {
3251 connection_t *connp = Conn[ind];
3252 player_type *p_ptr = NULL;
3253 int player = -1, type, result, (**receive_tbl)(int ind) = playing_receive, old_energy = 0;
3254 int num_players_start = NumPlayers; // Hack to see if we have quit in this function
3255
3256 // Hack -- take any pending commands from the command que connp->q
3257 // and move them to connp->r, where the Receive functions get their
3258 // data from.
3259 Sockbuf_clear(&connp->r);
3260 if (connp->q.len > 0)
3261 {
3262 if (Sockbuf_write(&connp->r, connp->q.ptr, connp->q.len) != connp->q.len)
3263 {
3264 errno = 0;
3265 Destroy_connection(ind, "Can't copy queued data to buffer");
3266 return;
3267 }
3268 //connp->q.ptr += connp->q.len;
3269 //Sockbuf_advance(&connp->q, connp->q.ptr - connp->q.buf);
3270 Sockbuf_clear(&connp->q);
3271 }
3272
3273 // If we have no commands to execute return
3274 if (connp->r.len <= 0)
3275 return;
3276
3277 // Get the player pointer
3278 if (connp->id != -1)
3279 {
3280 player = GetInd[connp->id];
3281 p_ptr = Players[player];
3282 }
3283 // Hack -- if our player id has not been set then assume that Receive_play
3284 // should be called.
3285 else
3286 {
3287 Receive_play(ind);
3288 return;
3289 }
3290
3291 // Attempt to execute every pending command. Any command that fails due
3292 // to lack of energy will be put into the queue for next turn by the
3293 // respective receive function.
3294
3295 //while ( (p_ptr->energy >= level_speed(p_ptr->dun_depth)) &&
3296 //while ( (connp->state == CONN_PLAYING ? p_ptr->energy >= level_speed(p_ptr->dun_depth) : 1) &&
3297 //while ( (connp->state == CONN_PLAYING ? p_ptr->energy >= level_speed(p_ptr->dun_depth) : 1) &&
3298 while ((connp->r.ptr < connp->r.buf + connp->r.len))
3299 {
3300 char *foo = connp->r.ptr;
3301 type = (connp->r.ptr[0] & 0xFF);
3302 if (type != PKT_KEEPALIVE && type != PKT_PING)
3303 {
3304 connp->inactive_keepalive = 0;
3305 connp->inactive_ping = 0;
3306 if (connp->id != -1) p_ptr->idle = 0;
3307 }
3308 result = (*receive_tbl[type])(ind);
3309
3310 /* Check that the player wasn't disconnected - mikaelh */
3311 if (!Conn[ind]) {
3312 return;
3313 }
3314
3315 /* See 'p_ptr->requires_energy' below in 'result == 0' clause. */
3316 if (p_ptr != NULL && p_ptr->conn != NOT_CONNECTED)
3317 p_ptr->requires_energy = (result == 0);
3318
3319 /* Check whether the socket buffer has advanced */
3320 if (connp->r.ptr == foo) {
3321 /* Return code 0 means that there wasn't enough data in the socket buffer */
3322 if (result == 0) {
3323 /* Move the remaining data to the queue buffer - mikaelh */
3324 int len = connp->r.len - (connp->r.ptr - connp->r.buf);
3325 if (Sockbuf_write(&connp->q, connp->r.ptr, len) != len)
3326 {
3327 errno = 0;
3328 Destroy_connection(ind, "Can't copy data to queue");
3329 return;
3330 }
3331 }
3332
3333 /* Clear the buffer to avoid getting stuck in a loop */
3334 Sockbuf_clear(&connp->r);
3335 break;
3336 }
3337 if (connp->state == CONN_PLAYING)
3338 {
3339 connp->start = turn;
3340 }
3341 if (result == -1) {
3342 return;
3343 }
3344
3345 // We didn't have enough energy to execute an important command.
3346 if (result == 0) {
3347 /* New: Since fire-till-kill is now allowed to begin at <= 1
3348 energy (see dungeon.c, process_player_end()), we need this
3349 to avoid getting 'locked up' in shooting_till_kill. - C. Blue */
3350 //done above already p_ptr->requires_energy = TRUE;
3351
3352 /* Hack -- if we tried to do something while resting, wake us up.
3353 */
3354 if (p_ptr->resting) disturb(player, 0, 0);
3355
3356 /* If we didn't have enough energy to execute this
3357 * command, in order to ensure that our important
3358 * commands execute in the proper order, stop
3359 * processing any commands that require energy. We
3360 * assume that any commands that don't require energy
3361 * (such as quitting, or talking) should be executed
3362 * ASAP.
3363 */
3364 /* Mega-Hack -- save our old energy and set our energy
3365 * to 0. This will allow us to execute "out of game"
3366 * actions such as talking while we wait for enough
3367 * energy to execute our next queued in game action.
3368 */
3369 if (p_ptr->energy) {
3370 old_energy = p_ptr->energy;
3371 p_ptr->energy = 0;
3372 }
3373 }
3374
3375 /* Queue all remaining packets now */
3376 if (result == 3)
3377 {
3378 int len = connp->r.len - (connp->r.ptr - connp->r.buf);
3379 if (Sockbuf_write(&connp->q, connp->r.ptr, len) != len)
3380 {
3381 errno = 0;
3382 Destroy_connection(ind, "Can't copy data to queue");
3383 return;
3384 }
3385 Sockbuf_clear(&connp->r);
3386
3387 break;
3388 }
3389 }
3390 /* Restore our energy if neccecary. */
3391
3392 /* Make sure that the player structure hasn't been deallocated in this
3393 * time due to a quit request. Hack -- to do this we check if the number
3394 * of players has changed while this loop has been executing. This would be
3395 * a BAD thing to do if we ever went multithreaded.
3396 */
3397 if (NumPlayers == num_players_start)
3398 if (!p_ptr->energy) p_ptr->energy = old_energy;
3399 }
3400
3401 /*
3402 * Process a client packet.
3403 * The client may be in one of several states,
3404 * therefore we use function dispatch tables for easy processing.
3405 * Some functions may process requests from clients being
3406 * in different states.
3407 * The behavior of this function has been changed somewhat. New commands are now
3408 * put into a command queue, where they will be executed later.
3409 */
3410 void Handle_input(int fd, int arg)
3411 {
3412 int ind = arg, player = -1, old_numplayers = NumPlayers;
3413 connection_t *connp = Conn[ind];
3414 player_type *p_ptr = NULL;
3415 //int type, result, (**receive_tbl)(int ind);
3416 //int (**receive_tbl)(int ind);
3417
3418 /* Check that the pointer is valid - mikaelh */
3419 if (!connp) return;
3420
3421 if (connp->state & (CONN_PLAYING | CONN_READY))
3422 ;//receive_tbl = &playing_receive[0];
3423 else if (connp->state & (CONN_LOGIN/* | CONN_SETUP */))
3424 #if 0
3425 receive_tbl = &login_receive[0];
3426 #else
3427 {
3428 //receive_tbl = &login_receive[0];
3429 Receive_play(ind);
3430 return;
3431 }
3432 #endif
3433 else if (connp->state & (CONN_DRAIN/* | CONN_SETUP */))
3434 ;//receive_tbl = &drain_receive[0];
3435 else if (connp->state == CONN_LISTENING) {
3436 Handle_listening(ind);
3437 return;
3438 } else if (connp->state == CONN_SETUP) {
3439 Handle_setup(ind);
3440 return;
3441 } else {
3442 if (connp->state != CONN_FREE)
3443 Destroy_connection(ind, "not input");
3444 return;
3445 }
3446
3447 #if 0
3448 /* Clear connp->r, which will be our new queue */
3449 Sockbuf_clear(&connp->r);
3450
3451 /* Put any old commands at the beginning of the new queue we are reading into */
3452 if (connp->q.len > 0) {
3453 if (connp->r.ptr > connp->r.buf)
3454 Sockbuf_advance(&connp->r, connp->r.ptr - connp->r.buf);
3455 if (Sockbuf_write(&connp->r, connp->q.ptr, connp->q.len) != connp->q.len) {
3456 errno = 0;
3457 Destroy_connection(ind, "Can't copy queued data to buffer");
3458 return;
3459 }
3460
3461 connp->q.ptr += connp->q.len;
3462 Sockbuf_advance(&connp->q, connp->q.ptr - connp->q.buf);
3463 }
3464 Sockbuf_clear(&connp->q);
3465 #endif
3466
3467 if (connp->id != -1) {
3468 player = GetInd[connp->id];
3469 p_ptr = Players[player];
3470 }
3471
3472 /* Mega-Hack */
3473 if (p_ptr && p_ptr->new_level_flag) return;
3474
3475 // Reset the buffer we are reading into
3476 Sockbuf_clear(&connp->r);
3477
3478 // Read in the data
3479 if (Sockbuf_read(&connp->r) <= 0) {
3480 // Check to make sure that an EAGAIN error didn't occur. Sometimes on
3481 // Linux when receiving a lot of traffic EAGAIN will occur on recv and
3482 // Sockbuf_read will return 0.
3483 if (errno != EAGAIN) {
3484 // If this happens, the the client has probably closed his TCP connection.
3485 do_quit(ind, 0);
3486 }
3487
3488 //Destroy_connection(ind, "input error");
3489 return;
3490 }
3491
3492 // Add this new data to the command queue
3493 if (Sockbuf_write(&connp->q, connp->r.ptr, connp->r.len) != connp->r.len) {
3494 errno = 0;
3495 Destroy_connection(ind, "Can't copy queued data to buffer");
3496 return;
3497 }
3498
3499 // Execute any new commands immediately if possible
3500 // Don't process commands when marked for death - mikaelh
3501 if (!p_ptr || !p_ptr->death) process_pending_commands(ind);
3502
3503 /* Check that the player wasn't disconnected - mikaelh */
3504 if (!Conn[ind]) return;
3505
3506 /* Experimental hack -- to reduce perceived latency, flush our network
3507 * info right now so the player sees the results of his actions as soon
3508 * as possobile. Everyone else will see him move at most one game turn
3509 * later, which is usually < 100 ms.
3510 */
3511
3512 /* Hack -- don't update the player info if the number of players since
3513 * the beginning of this function call has changed, which might indicate
3514 * that our player has left the game.
3515 */
3516 if ((old_numplayers == NumPlayers) && (connp->state == CONN_PLAYING)) {
3517 // Update the players display if neccecary and possobile
3518 if (p_ptr) {
3519 /* Notice stuff */
3520 if (p_ptr->notice) notice_stuff(player);
3521
3522 /* Update stuff */
3523 if (p_ptr->update) update_stuff(player);
3524
3525 /* Redraw stuff */
3526 if (p_ptr->redraw) redraw_stuff(player);
3527
3528 /* Window stuff */
3529 if (p_ptr->window) window_stuff(player);
3530 }
3531 }
3532
3533 if (connp->c.len > 0) {
3534 if (Packet_printf(&connp->c, "%c", PKT_END) <= 0) {
3535 Destroy_connection(ind, "write error");
3536 return;
3537 }
3538 Send_reliable(ind);
3539 }
3540
3541 // Sockbuf_clear(&connp->r);
3542 }
3543
3544 // This function is used for sending data to clients who do not yet have
3545 // Player structures allocated, and for timing out players who have been
3546 // idle for a while.
3547 int Net_input(void)
3548 {
3549 int i, ind, num_reliable = 0, input_reliable[MAX_SELECT_FD];
3550 connection_t *connp;
3551 char msg[MSG_LEN];
3552
3553 for (i = 0; i < max_connections; i++)
3554 {
3555 connp = Conn[i];
3556
3557 if (!connp || connp->state == CONN_FREE)
3558 continue;
3559 if (connp->timeout && (connp->start + connp->timeout * cfg.fps < turn))
3560 {
3561 if (connp->state & (CONN_PLAYING | CONN_READY))
3562 {
3563 /* sprintf(msg, "%s mysteriously disappeared!",
3564 connp->nick);
3565 Set_message(msg); */
3566 }
3567 sprintf(msg, "timeout %02x", connp->state);
3568 Destroy_connection(i, msg);
3569
3570 #if 0
3571 /* Very VERY bad hack :/ - C. Blue */
3572 save_game_panic();
3573 #endif
3574
3575 continue;
3576 }
3577
3578 // Make sure that the player we are looking at is not already in the
3579 // game. If he is already in the game then we will send him data
3580 // in the function Net_input.
3581 if (connp->id != -1) continue;
3582
3583 /* if (connp->r.len > 0)
3584 Sockbuf_clear(&connp->r); */
3585
3586 #if 0
3587 if (connp->state != CONN_PLAYING)
3588 {
3589 #endif
3590 input_reliable[num_reliable++] = i;
3591 if (connp->state == CONN_SETUP )
3592 {
3593 Handle_setup(i);
3594 continue;
3595 }
3596 #if 0
3597 }
3598 #endif
3599 }
3600
3601 /* Do GW timeout checks */
3602 SGWTimeout();
3603
3604 for (i = 0; i < num_reliable; i++)
3605 {
3606 ind = input_reliable[i];
3607 connp = Conn[ind];
3608 if (connp->state & (CONN_DRAIN | CONN_READY | CONN_SETUP
3609 | CONN_LOGIN | CONN_PLAYING))
3610 {
3611 if (connp->c.len > 0)
3612 if (Send_reliable(ind) == -1)
3613 continue;
3614 }
3615 }
3616
3617 if (num_logins | num_logouts)
3618 num_logins = num_logouts = 0;
3619
3620 return login_in_progress;
3621 }
3622
3623 int Net_output(void)
3624 {
3625 int i;
3626 connection_t *connp;
3627 player_type *p_ptr = NULL;
3628
3629 for (i = 1; i <= NumPlayers; i++)
3630 {
3631 p_ptr = Players[i];
3632
3633 if (p_ptr->conn == NOT_CONNECTED) continue;
3634
3635 if (p_ptr->new_level_flag) continue;
3636
3637 connp = Conn[p_ptr->conn];
3638
3639 /* XXX XXX XXX Mega-Hack -- Redraw player's spot every time */
3640 /* This keeps the network connection "active" even if nothing is */
3641 /* happening -- KLJ */
3642 /* This has been changed to happen less often, operating at close to 3
3643 * times a second to keep the BGP routing tables happy.
3644 * I had originally changed this to about once every 2 seconds,
3645 * but apparently it was doing bad things, as the inactivity in the UDP
3646 * stream was causing us to loose priority in the routing tables.
3647 * Thanks to Crimson for explaining this. -APD
3648 */
3649
3650 /* to keep a good UDP connection, send data that requests a response
3651 * every 1/4 of a second
3652 */
3653
3654 /* Hack -- add the index to our turn, so we don't send all the players
3655 * reliable data simultaniously. This should hopefully "spread out"
3656 * the incoming data a little so it doesn't all happen in a semi-
3657 * synchronized way.
3658 */
3659
3660 /*
3661 Can't coment this out, it updates things like food
3662 and stores.
3663 Still have to worry about routing with TCP :)
3664 -- Crimson
3665 --- But STill buggy, so off for now.
3666 if (!((turn + i) % 8))
3667 {
3668 lite_spot(i, p_ptr->py, p_ptr->px);
3669 }
3670 */
3671
3672 /* otherwise, send normal data if there is any */
3673 //else
3674 //{
3675 // Tell the client that this is the end
3676 //
3677 // If we have any data to send to the client, terminate it
3678 // and send it to the client.
3679 if (connp->c.len > 0)
3680 {
3681 if (Packet_printf(&connp->c, "%c", PKT_END) <= 0)
3682 {
3683 Destroy_connection(p_ptr->conn, "write error");
3684 continue;
3685 }
3686 Send_reliable(p_ptr->conn);
3687 }
3688 // Flush the output buffers
3689 // if (Sockbuf_flush(&connp->w) == -1)
3690 // return -1;
3691 //}
3692
3693 //Sockbuf_clear(&connp->w);
3694 }
3695
3696 /* Every fifteen seconds, update the info sent to the metaserver */
3697 if (!(turn % (15 * cfg.fps)))
3698 Report_to_meta(META_UPDATE);
3699
3700 return 1;
3701 }
3702
3703 int Net_output1(int Ind)
3704 {
3705 connection_t *connp;
3706 player_type *p_ptr = NULL;
3707
3708 p_ptr = Players[Ind];
3709 if (p_ptr->conn == NOT_CONNECTED) return 0;
3710 if (p_ptr->new_level_flag) return 2;
3711 connp = Conn[p_ptr->conn];
3712
3713 if (connp->c.len > 0)
3714 {
3715 if (Packet_printf(&connp->c, "%c", PKT_END) <= 0) {
3716 Destroy_connection(p_ptr->conn, "write error");
3717 return 3;
3718 } else {
3719 Send_reliable(p_ptr->conn);
3720 }
3721 }
3722 return 1;
3723 }
3724
3725 /*
3726 * Send a reply to a special client request.
3727 * Not used consistently everywhere.
3728 * It could be used to setup some form of reliable
3729 * communication from the client to the server.
3730 */
3731 int Send_reply(int ind, int replyto, int result)
3732 {
3733 connection_t *connp = Conn[ind];
3734 int n;
3735
3736 n = Packet_printf(&connp->c, "%c%c%c", PKT_REPLY, replyto, result);
3737 if (n == -1)
3738 {
3739 Destroy_connection(ind, "write error");
3740 return -1;
3741 }
3742
3743 return n;
3744 }
3745
3746 int Send_leave(int ind, int id)
3747 {
3748 connection_t *connp = Conn[ind];
3749
3750 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
3751 {
3752 errno = 0;
3753 plog(format("Connection not ready for leave info (%d,%d)",
3754 connp->state, connp->id));
3755 return 0;
3756 }
3757 return Packet_printf(&connp->c, "%c%hd", PKT_LEAVE, id);
3758 }
3759
3760 // Actually quit. This was seperated as a hack to allow us to
3761 // "quit" when a quit packet has not been received, such as when
3762 // our TCP connection is severed. The tellclient argument
3763 // specifies whether or not we should try to send data to the
3764 // client informing it about the quit event.
3765 void do_quit(int ind, bool tellclient)
3766 {
3767 int player = -1;
3768 player_type *p_ptr = NULL;
3769 connection_t * connp = Conn[ind];
3770
3771 if (connp->id != -1) {
3772 player = GetInd[connp->id];
3773 p_ptr = Players[player];
3774 }
3775 if (!tellclient) {
3776 /* Close the socket */
3777 close(connp->w.sock);
3778
3779 /* No more packets from a player who is quitting */
3780 remove_input(connp->w.sock);
3781
3782 /* Disable all output and input to and from this player */
3783 connp->w.sock = -1;
3784 }
3785
3786 /* If we are close to the center of town, exit quickly. */
3787 if (connp->id == -1 ||
3788 isdungeontown(&p_ptr->wpos) ||
3789 (istownarea(&p_ptr->wpos, MAX_TOWNAREA) && !(sector00separation && in_sector00(&p_ptr->wpos)))) {
3790 Destroy_connection(ind, "client quit");
3791 }
3792 // Otherwise wait for the timeout
3793 else exec_lua(NumPlayers, format("player_leaves_timeout(%d, %d, \"%/s\", \"%s\")", NumPlayers, p_ptr->id, p_ptr->name, showtime()));
3794 }
3795
3796
3797 static int Receive_quit(int ind) {
3798 int n;
3799 connection_t *connp = Conn[ind];
3800 char ch;
3801
3802 if ((n = Packet_scanf(&connp->r, "%c", &ch)) != 1) {
3803 errno = 0;
3804 Destroy_connection(ind, "receive error in quit");
3805 return -1;
3806 }
3807
3808 do_quit(ind, 0);
3809
3810 return 1;
3811 }
3812
3813 static int Receive_login(int ind) {
3814 connection_t *connp = Conn[ind], *connp2 = NULL;
3815 //unsigned char ch;
3816 int i, n, res;
3817 char choice[MAX_CHARS], loc[MAX_CHARS];
3818 struct account *l_acc;
3819 struct worldpos wpos;
3820
3821 n = Sockbuf_read(&connp->r);
3822 if (n == 0 && !(errno == EAGAIN || errno == EWOULDBLOCK)) {
3823 /* avoid SIGPIPE in zero read - it was closed */
3824 close(connp->w.sock);
3825 remove_input(connp->w.sock);
3826 connp->w.sock = -1;
3827 Destroy_connection(ind, "disconnect in login");
3828 return(-1);
3829 }
3830
3831 if ((n = Packet_scanf(&connp->r, "%s", choice)) != 1) {
3832 errno = 0;
3833 printf("%d\n", n);
3834 plog("Failed reading login packet");
3835 Destroy_connection(ind, "receive error in login");
3836 return -1;
3837 }
3838
3839 if (strlen(choice) == 0) { /* we have entered an account name */
3840 u32b p_id;
3841 bool censor_swearing_tmp = censor_swearing;
3842 char tmp_name[ACCOUNTNAME_LEN], tmp_name2[ACCOUNTNAME_LEN];
3843 char tmp_name_wide[MAX_CHARS_WIDE];
3844 struct account *acc;
3845
3846 /* security check: a bugged client might try to send the character name, but allows an 'empty' name!
3847 Here, the server would think that 'choice' being empty is signaling a different login stage.
3848 However, if the client was really trying to send an (empty) character name, at least connp->pass
3849 would be 0x0 at this point, causing the server to segfault! - C. Blue */
3850 if (!connp->pass ||//<-important check
3851 !connp->nick || !connp->real || !connp->host || !connp->addr) {//<-just paranoia checks
3852 Destroy_connection(ind, "Unexpected login error. Please contact an administrator.");
3853 return(-1);
3854 }
3855
3856 /* remove disallowed chars and spaces at the end */
3857 Trim_name(connp->nick);
3858
3859 /* Check if player tries to create an account of the same name as
3860 an already existing character - give an error message.
3861 (Mostly for new feat 'privmsg to account name' - C. Blue) */
3862 if ((p_id = lookup_player_id(connp->nick))) { /* character name identical to this account name already exists? */
3863 /* That character doesn't belong to our account? Forbid creating an account of this name then. */
3864 if (lookup_accountname(p_id) && //<- avoid panic save if tomenet.acc file has been deleted for some reason. NOTE: Missing tomenet.acc still causes *problems*, so don't do that.
3865 strcmp(lookup_accountname(p_id), connp->nick)) {
3866 /* However, if our account already exists then allow it to continue existing. */
3867 if (!(acc = Admin_GetAccount(connp->nick))) {
3868 Destroy_connection(ind, "Name already in use.");
3869 Sockbuf_flush(&connp->w);
3870 return(0);
3871 }
3872 KILL(acc, struct account);
3873 }
3874 }
3875
3876 /* check if player tries to use one of the temporarily reserved character names as this account name */
3877 for (i = 0; i < MAX_RESERVED_NAMES; i++) {
3878 if (!reserved_name_character[i][0]) break;
3879
3880 /* new: also for 'similar' names that don't belong to us */
3881 condense_name(tmp_name, reserved_name_character[i]);
3882 condense_name(tmp_name2, connp->nick);
3883 if (!strcmp(tmp_name, tmp_name2) &&
3884 strcmp(reserved_name_account[i], connp->nick)) {
3885 Destroy_connection(ind, "Name already in use.");
3886 return(-0);
3887 }
3888
3889 if (strcmp(reserved_name_character[i], connp->nick)) continue;
3890
3891 if (!strcmp(reserved_name_account[i], connp->nick)) {
3892 reserved_name_character[i][0] = '\0'; //clear reservation
3893 break;
3894 }
3895
3896 Destroy_connection(ind, "Name already in use.");
3897 return(-0);
3898 }
3899
3900 /* Check if a too similar name already exists --
3901 must be called before GetAccount() is called, because that function
3902 imprints the condensed name onto a newly created account.
3903 Don't prevent already existing accounts from logging in though. */
3904 if (!(acc = Admin_GetAccount(connp->nick)) && lookup_similar_account(connp->nick, NULL)) {
3905 Destroy_connection(ind, "A too similar name is already in use. Check lower/upper case.");
3906 return -1;
3907 }
3908 KILL(acc, struct account);
3909
3910 if (!connp->nick[0]) {
3911 Destroy_connection(ind, "You need to enter an account name and password!");
3912 return -1;
3913 }
3914 if (!connp->pass[0]) {
3915 Destroy_connection(ind, "You must enter a password too!");
3916 return -1;
3917 }
3918
3919 if ((res = Check_names(connp->nick, connp->real, connp->host, connp->addr, FALSE)) != SUCCESS) {
3920 if (res == E_LETTER)
3921 Destroy_connection(ind, "Your accountname must start on a letter (A-Z).");
3922 else
3923 Destroy_connection(ind, "Your accountname, username or hostname contains invalid characters");
3924 return(-1);
3925 }
3926
3927 /* Check for forbidden names (swearing).
3928 Note: This overrides 'censor_swearing' and is always on! */
3929 censor_swearing = censor_swearing_identity;
3930 /* Check account name for swearing.. */
3931 strcpy(tmp_name, connp->nick);
3932 if (handle_censor(tmp_name)) {
3933 censor_swearing = censor_swearing_tmp;
3934 Destroy_connection(ind, "This account name is not available. Please choose a different name.");
3935 return(-1);
3936 }
3937 #if 1 /* Check hostname too for swearing? */
3938 strcpy(tmp_name_wide, connp->host);
3939 if (handle_censor(tmp_name_wide)) {
3940 censor_swearing = censor_swearing_tmp;
3941 Destroy_connection(ind, format("Your host name is '%s' which is deemed offensive. Please change it.", connp->host));
3942 return(-1);
3943 }
3944 #endif
3945 /* (Note: since 'real' name is always replaced by "PLAYER", we don't need to check that one for swearing.) */
3946 /* Switch back to normal swearing checking. */
3947 censor_swearing = censor_swearing_tmp;
3948
3949 /* Password obfuscation introduced in pre-4.4.1a client or 4.4.1.1 */
3950 if (connp->pass && is_newer_than(&connp->version, 4, 4, 1, 0, 0, 0)) {
3951 /* Use memfrob for the password - mikaelh */
3952 my_memfrob(connp->pass, strlen(connp->pass));
3953 }
3954
3955 if (connp->pass && (l_acc = GetAccount(connp->nick, connp->pass, FALSE))) {
3956 int *id_list;
3957 byte tmpm;
3958 char colour_sequence[3];
3959 /* server flags to tell the client more about us - just informational purpose: */
3960 u32b sflags3 = 0x0, sflags2 = 0x0, sflags1 = 0x0, sflags0 = 0x0;
3961 /* flag array 0: server type flags
3962 flag array 1: features offered by server/client mode (special screen layout for showing party stats maybe (TODO//unused))
3963 flag array 2: temporary lua testing flags for experimental features
3964 flag array 3: unused
3965 */
3966
3967 /* Set server type flags */
3968 #ifdef RPG_SERVER
3969 sflags0 |= SFLG0_RPG;
3970 if (l_acc->flags & ACC_ADMIN) sflags0 |= SFLG0_RPG_ADMIN; /* Allow multiple chars per account for admins! */
3971 #endif
3972 #ifdef FUN_SERVER
3973 sflags0 |= SFLG0_FUN;
3974 #endif
3975 #ifdef PARTY_SERVER
3976 sflags0 |= SFLG0_PARTY;
3977 #endif
3978 #ifdef ARCADE_SERVER
3979 sflags0 |= SFLG0_ARCADE;
3980 #endif
3981 #ifdef TEST_SERVER
3982 sflags0 |= SFLG0_TEST;
3983 #endif
3984 #ifndef RPG_SERVER /* not implemented for RPG SERVER atm */
3985 #ifdef ALLOW_DED_IDDC_MODE
3986 sflags0 |= SFLG0_DED_IDDC;
3987 #endif
3988 #ifdef ALLOW_DED_PVP_MODE
3989 sflags0 |= SFLG0_DED_PVP;
3990 #endif
3991 #endif
3992 #ifdef NO_PK
3993 sflags0 |= SFLG0_NO_PK;
3994 #endif
3995
3996 /* Set available-feature / client mode flags */
3997 #ifdef BIG_MAP
3998 sflags1 |= SFLG1_BIG_MAP;
3999 #endif
4000
4001 #ifdef NEW_SHIELDS_NO_AC
4002 sflags1 |= SFLG1_NEW_SHIELDS_NO_AC;
4003 #endif
4004
4005 /* Set temporary flags */
4006 sflags2 = sflags_TEMP;
4007
4008 /* Set XXX flags */
4009
4010 /* Send all flags! */
4011 Packet_printf(&connp->c, "%c%d%d%d%d", PKT_SERVERDETAILS, sflags3, sflags2, sflags1, sflags0);
4012
4013 connp->password_verified = TRUE;
4014 free(connp->pass);
4015 connp->pass = NULL;
4016 n = player_id_list(&id_list, l_acc->id);
4017 /* Display all account characters here */
4018 for (i = 0; i < n; i++) {
4019 u16b ptype = lookup_player_type(id_list[i]);
4020
4021 /* do not change protocol here */
4022 tmpm = lookup_player_mode(id_list[i]);
4023 if (tmpm & MODE_EVERLASTING) strcpy(colour_sequence, "\377B");
4024 else if (tmpm & MODE_PVP) strcpy(colour_sequence, format("\377%c", COLOUR_MODE_PVP));
4025 else if (tmpm & MODE_NO_GHOST) strcpy(colour_sequence, "\377D");
4026 else if (tmpm & MODE_HARD) strcpy(colour_sequence, "\377s");
4027 else strcpy(colour_sequence, "\377W");
4028
4029 /* look up character's current location */
4030 wpos = lookup_player_wpos(id_list[i]);
4031 /* note: we don't receive options yet, so we don't know about 'depth_in_feet' */
4032 //sprintf(loc, "On lv %d in (%d,%d)", wpos.wz, wpos.wx, wpos.wy);
4033 //sprintf(loc, "on %dft in (%d,%d)", wpos.wz * 50, wpos.wx, wpos.wy);//..so we just assume 'ft' notation
4034 sprintf(loc, "in (%d,%d) on %dft", wpos.wx, wpos.wy, wpos.wz * 50);//..so we just assume 'ft' notation
4035
4036 if (is_newer_than(&connp->version, 4, 5, 7, 0, 0, 0))
4037 Packet_printf(&connp->c, "%c%hd%s%s%hd%hd%hd%s", PKT_LOGIN, tmpm, colour_sequence, lookup_player_name(id_list[i]), lookup_player_level(id_list[i]), ptype&0xff , ptype>>8, loc);
4038 else if (is_newer_than(&connp->version, 4, 4, 9, 2, 0, 0))
4039 Packet_printf(&connp->c, "%c%hd%s%s%hd%hd%hd", PKT_LOGIN, tmpm, colour_sequence, lookup_player_name(id_list[i]), lookup_player_level(id_list[i]), ptype&0xff , ptype>>8);
4040 else
4041 Packet_printf(&connp->c, "%c%s%s%hd%hd%hd", PKT_LOGIN, colour_sequence, lookup_player_name(id_list[i]), lookup_player_level(id_list[i]), ptype&0xff , ptype>>8);
4042 }
4043 if (is_newer_than(&connp->version, 4, 5, 7, 0, 0, 0))
4044 Packet_printf(&connp->c, "%c%hd%s%s%hd%hd%hd%s", PKT_LOGIN, 0, "", "", 0, 0 , 0, "");
4045 else if (is_newer_than(&connp->version, 4, 4, 9, 2, 0, 0))
4046 Packet_printf(&connp->c, "%c%hd%s%s%hd%hd%hd", PKT_LOGIN, 0, "", "", 0, 0, 0);
4047 else
4048 Packet_printf(&connp->c, "%c%s%s%hd%hd%hd", PKT_LOGIN, "", "", 0, 0, 0);
4049 if (n) C_KILL(id_list, n, int);
4050 KILL(l_acc, struct account);
4051 }
4052 else{
4053 /* fail login here */
4054 Destroy_connection(ind, "Wrong password or name already in use.");
4055 }
4056 Sockbuf_flush(&connp->w);
4057 return(0);
4058
4059 } else if (connp->password_verified) { /* we have entered a character name */
4060 int check_account_reason = 0;
4061 bool censor_swearing_tmp = censor_swearing, took_reservation = FALSE;
4062 char tmp_name[CHARACTERNAME_LEN];
4063
4064 #if 0
4065 /* just in case - some places can't handle a longer name and a valid client shouldn't supply a name this long anyway - mikaelh */
4066 choice[NAME_LEN - 1] = '\0';
4067 #else
4068 choice[CHARACTERNAME_LEN - 1] = '\0';
4069 #endif
4070
4071 /* Prevent EXPLOIT (adding a SPACE to foreign charname) */
4072 s_printf("Player %s chooses character '%s' (strlen=%d)\n", connp->nick, choice, strlen(choice));
4073 Trim_name(choice);
4074
4075 /* If already exists, change capitalization to match */
4076 if (fix_player_case(choice)) s_printf("Name capitalization: -> '%s'\n", choice);
4077
4078 /* Check for forbidden names (technical/lore reasons) */
4079 if (forbidden_name(choice)) {
4080 // Packet_printf(&connp->c, "%c", E_INVAL);
4081 Destroy_connection(ind, "Forbidden character name. Please choose a different name.");
4082 return(-1);
4083 }
4084
4085 /* Check for forbidden names (swearing).
4086 Note: This overrides 'censor_swearing' and is always on! */
4087 censor_swearing = censor_swearing_identity;
4088 strcpy(tmp_name, choice);
4089 if (handle_censor(tmp_name)) {
4090 censor_swearing = censor_swearing_tmp;
4091 Destroy_connection(ind, "This character name is not available. Please choose a different name.");
4092 return(-1);
4093 }
4094 censor_swearing = censor_swearing_tmp;
4095
4096 /* check if player tries to use one of the temporarily reserved character names */
4097 for (i = 0; i < MAX_RESERVED_NAMES; i++) {
4098 if (!reserved_name_character[i][0]) break;
4099 if (strcasecmp(reserved_name_character[i], choice)) continue;
4100
4101 if (!strcmp(reserved_name_account[i], connp->nick)) {
4102 reserved_name_character[i][0] = '\0'; //clear reservation
4103 took_reservation = TRUE;
4104 break;
4105 }
4106
4107 Destroy_connection(ind, "Name already in use by another player.");
4108 return(-1);
4109 }
4110
4111 /* Check if a too similar account name already exists.
4112 Only for characters that don't exist yet and would be newly created. */
4113 if (!lookup_player_id(choice) && lookup_similar_account(choice, connp->nick)
4114 /* exception! reserved character names have priority.
4115 Otherwise someone could create an account meanwhile to block this player's reincarnation.
4116 Ok, far-fetched paranoia, but still >_>.. */
4117 && !took_reservation) {
4118 Destroy_connection(ind, "A too similar name exists. Please choose a different name.");
4119 return -1;
4120 }
4121
4122 /* at this point, we are authorised as the owner
4123 of the account. any valid name will be
4124 allowed. */
4125 /* i realise it should return different value depending
4126 on reason - evileye */
4127 check_account_reason = check_account(connp->nick, choice);
4128 //s_printf("success = %d\n", check_account_reason);
4129 switch (check_account_reason) {
4130 case 0: //NOT OK
4131 /* fail login here */
4132 Destroy_connection(ind, "Name already in use by another player.");
4133 return(-1);
4134 case 1: //OK
4135 break;
4136 case -1: //NOT OK: Max 1 char (RPG)
4137 /* fail login here */
4138 Destroy_connection(ind, "Only one character per account is allowed.");
4139 return(-1);
4140 case -2: //NOT OK
4141 /* fail login here */
4142 Destroy_connection(ind, "Multiple logins on the same account aren't allowed.");
4143 return(-1);
4144 case -3: /* Out of character slots! */
4145 Destroy_connection(ind, "Character amount limit reached.");
4146 return(-1);
4147 case -4: /* Force creation of MODE_DED_PVP character */
4148 connp->sex = MODE_DED_PVP;
4149 break;
4150 case -5: /* Force creation of MODE_DED_IDDC or MODE_DED_PVP character */
4151 connp->sex = MODE_DED_IDDC;
4152 break;
4153 case -6:
4154 /*hack: marker for both possibilities. We will decide when we see the user's actual choice later. */
4155 connp->sex = MODE_DED_PVP | MODE_DED_IDDC;
4156 break;
4157 case -7: /* like 1, and allow non-forced creation of slot-exclusive chars */
4158 connp->sex = MODE_DED_PVP_OK | MODE_DED_IDDC_OK;
4159 break;
4160 case -8: /* like 1, and allow non-forced creation of iddc-slot-exclusive char */
4161 connp->sex = MODE_DED_IDDC_OK;
4162 break;
4163 case -9: /* like 1, and allow non-forced creation of pvp-slot-exclusive char */
4164 connp->sex = MODE_DED_PVP_OK;
4165 break;
4166 default:
4167 Destroy_connection(ind, "unknown error");
4168 return -1;
4169 }
4170
4171 /* Check that no one else is creating a char with the same name - mikaelh */
4172 for (i = 0; i < max_connections; i++) {
4173 connp2 = Conn[i];
4174 if (!connp2 || connp2->state == CONN_FREE) continue;
4175 if (connp2->c_name && !strcasecmp(connp2->c_name, choice) &&
4176 strcasecmp(connp2->nick, connp->nick)) { /* check that it's a different account, too */
4177 /* Fail login */
4178 Destroy_connection(ind, "Character name already in use.");
4179 s_printf("(Prevented simultaneous creation of same character.)\n");
4180 return(-1);
4181 }
4182 }
4183
4184 /* Validate names/resume in proper place */
4185 if ((res = Check_names(choice, connp->real, connp->host, connp->addr, TRUE))) {
4186 /* connp->real is _always_ 'PLAYER' - connp->nick is the account name, choice the c_name */
4187 /* fail login here */
4188 if (res == E_LETTER)
4189 Destroy_connection(ind, "Your charactername must start on a letter (A-Z).");
4190 else if (res == E_INVAL)
4191 Destroy_connection(ind, "Your charactername contains invalid characters"); //user+host names have already been checked previously (on account login)
4192 else
4193 Destroy_connection(ind, "Security violation");
4194 return(-1);
4195 }
4196 Packet_printf(&connp->c, "%c", lookup_player_id(choice) ? SUCCESS : E_NEED_INFO);
4197 connp->c_name = strdup(choice);
4198 } else {
4199 /* fail login due to missing password */
4200 s_printf("EXPLOIT: Missing password of player %s.\n", connp->nick);
4201 Destroy_connection(ind, "Missing password");
4202 return(-1);
4203 }
4204 if (connp->setup >= Setup.setup_size)
4205 Conn_set_state(connp, CONN_LOGIN, CONN_LOGIN);
4206 return(0);
4207 }
4208
4209 #define RECEIVE_PLAY_SIZE (2*6+OPT_MAX+2*(TV_MAX+MAX_F_IDX_COMPAT+MAX_K_IDX_COMPAT+MAX_R_IDX_COMPAT))
4210 #define RECEIVE_PLAY_SIZE_OPTMAXCOMPAT (2*6+OPT_MAX_COMPAT+2*(TV_MAX+MAX_F_IDX_COMPAT+MAX_K_IDX_COMPAT+MAX_R_IDX_COMPAT))
4211 #define RECEIVE_PLAY_SIZE_OPTMAXOLD (2*6+OPT_MAX_OLD+2*(TV_MAX+MAX_F_IDX_COMPAT+MAX_K_IDX_COMPAT+MAX_R_IDX_COMPAT))
4212 //#define STRICT_RECEIVE_PLAY
4213 static int Receive_play(int ind) {
4214 connection_t *connp = Conn[ind];
4215 unsigned char ch;
4216 int i, n;
4217 s16b sex, race, class, trait = 0;
4218 short int sfx = -1, mus = -1;
4219
4220 /* XXX */
4221 n = Sockbuf_read(&connp->r);
4222 if (n == 0 && !(errno == EAGAIN || errno == EWOULDBLOCK)) {
4223 /* avoid SIGPIPE in zero read */
4224 close(connp->w.sock);
4225 remove_input(connp->w.sock);
4226 connp->w.sock = -1;
4227 Destroy_connection(ind, "disconnect in play");
4228 return(-1);
4229 }
4230
4231 if ((n = Packet_scanf(&connp->r, "%c", &ch)) != 1) {
4232 errno = 0;
4233 plog("Cannot receive play packet");
4234 Destroy_connection(ind, "receive error in play");
4235 return -1;
4236 }
4237
4238 /* Do not tell me how much this sucks. I didn't do the design
4239 evileye */
4240 if (ch == PKT_LOGIN) {
4241 Receive_login(ind);
4242 return(0);
4243 }
4244 if (ch != PKT_PLAY) {
4245 // errno = 0;
4246 #if DEBUG_LEVEL > 1
4247 #if DEBUG_LEVEL < 3
4248 if (ch != PKT_KEEPALIVE)
4249 #endif // DEBUG_LEVEL(2)
4250 plog(format("Packet is not of play type (%d)", ch));
4251 #endif // DEBUG_LEVEL(1)
4252 //Destroy_connection(ind, "not play");
4253 //return -1;
4254 return 0;
4255 }
4256 // else
4257 {
4258 if (is_newer_than(&connp->version, 4, 4, 5, 10, 0, 0)) {
4259 if ((n = Packet_scanf(&connp->r, "%hd%hd%hd%hd%hd%hd", &sex, &race, &class, &trait, &sfx, &mus)) <= 0) {
4260 errno = 0;
4261 plog("Play packet is broken");
4262 Destroy_connection(ind, "receive error 2 in play");
4263 return -1;
4264 }
4265 } else {
4266 if ((n = Packet_scanf(&connp->r, "%hd%hd%hd", &sex, &race, &class)) <= 0) {
4267 errno = 0;
4268 plog("Play packet is broken");
4269 Destroy_connection(ind, "receive error 2 in play");
4270 return -1;
4271 }
4272 }
4273
4274 /* hacks for forcibly dedicated characters */
4275 if ((connp->sex & MODE_DED_PVP) &&
4276 (connp->sex & MODE_DED_IDDC)) { //allow both, depending on what the user wants:
4277 if (sex & MODE_PVP) {
4278 sex &= ~(MODE_EVERLASTING | MODE_NO_GHOST | MODE_HARD | MODE_DED_IDDC);
4279 sex |= MODE_DED_PVP;
4280 } else {
4281 sex &= ~MODE_DED_PVP;
4282 sex |= MODE_DED_IDDC;
4283 }
4284 }
4285 else if (connp->sex & MODE_DED_PVP) {
4286 sex &= ~(MODE_EVERLASTING | MODE_NO_GHOST | MODE_HARD | MODE_DED_IDDC);
4287 sex |= MODE_DED_PVP | MODE_PVP;
4288 }
4289 else if (connp->sex & MODE_DED_IDDC) {
4290 sex &= ~(MODE_PVP | MODE_DED_PVP);
4291 sex |= MODE_DED_IDDC;
4292 }
4293
4294 /* hack for willingly dedicated characters */
4295 if (!(connp->sex & (MODE_DED_PVP | MODE_DED_IDDC))) {//not forced..
4296 if (sex & MODE_DED_PVP) { //..but wants to be dedicated pvp. Check if that's not allowed.
4297 if (!(connp->sex & MODE_DED_PVP_OK)) sex &= ~MODE_DED_PVP;
4298 if (!(sex & MODE_PVP)) sex &= ~MODE_DED_PVP;
4299 }
4300 if (sex & MODE_DED_IDDC) { //..but wants to be dedicated iddc. Check if that's not allowed.
4301 if (!(connp->sex & MODE_DED_IDDC_OK)) sex &= ~MODE_DED_IDDC;
4302 if (sex & MODE_PVP) sex &= ~MODE_DED_IDDC;
4303 }
4304 }
4305
4306 /* Dedicated IDDC characters are always no-ghost */
4307 if (sex & MODE_DED_IDDC) {
4308 sex &= ~MODE_EVERLASTING;
4309 sex |= MODE_NO_GHOST;
4310 }
4311
4312 if (sex & MODE_DED_PVP) sex |= MODE_PVP;
4313
4314 /* Set his character info */
4315 connp->sex = sex;
4316 connp->race = race;
4317 connp->class = class;
4318 connp->trait = trait;
4319
4320 // if (2654 > connp->r.len - (connp->r.ptr - connp->r.buf))
4321 if ((is_newer_than(&connp->version, 4, 5, 8, 1, 0, 1) ? RECEIVE_PLAY_SIZE :
4322 (is_newer_than(&connp->version, 4, 5, 5, 0, 0, 0) ? RECEIVE_PLAY_SIZE_OPTMAXCOMPAT : RECEIVE_PLAY_SIZE_OPTMAXOLD))
4323 > connp->r.len - (connp->r.ptr - connp->r.buf)) {
4324 #if DEBUG_LEVEL > 2
4325 plog(format("Play packet is not large enough yet (%d)",
4326 connp->r.len - (connp->r.ptr - connp->r.buf)));
4327 #endif // DEBUG_LEVEL
4328 connp->r.ptr = connp->r.buf;
4329 return 1;
4330 }
4331
4332 #if DEBUG_LEVEL > 2
4333 plog(format("Play packet is now large enough (%d)",
4334 connp->r.len - (connp->r.ptr - connp->r.buf)));
4335 #endif // DEBUG_LEVEL
4336
4337 #if 1 // moved from Handle_listening
4338 /* Read the stat order */
4339 for (i = 0; i < 6; i++) {
4340 n = Packet_scanf(&connp->r, "%hd", &connp->stat_order[i]);
4341 if (n <= 0) {
4342 Destroy_connection(ind, "Misread stat order");
4343 return -1;
4344 }
4345 }
4346
4347 #if 0
4348 /* Read class extra */
4349 n = Packet_scanf(&connp->r, "%hd", &connp->class_extra);
4350 if (n <= 0) {
4351 Destroy_connection(ind, "Misread class extra");
4352 return -1;
4353 }
4354 #endif // 0
4355
4356 /* Read the options */
4357 if (is_newer_than(&connp->version, 4, 5, 8, 1, 0, 1)) {
4358 for (i = 0; i < OPT_MAX; i++) {
4359 n = Packet_scanf(&connp->r, "%c", &connp->Client_setup.options[i]);
4360 if (n <= 0) {
4361 Destroy_connection(ind, "Misread options");
4362 return -1;
4363 }
4364 }
4365 } else if (is_newer_than(&connp->version, 4, 5, 5, 0, 0, 0)) {
4366 for (i = 0; i < OPT_MAX_COMPAT; i++) {
4367 n = Packet_scanf(&connp->r, "%c", &connp->Client_setup.options[i]);
4368 if (n <= 0) {
4369 Destroy_connection(ind, "Misread options");
4370 return -1;
4371 }
4372 }
4373 } else {
4374 for (i = 0; i < OPT_MAX_OLD; i++) {
4375 n = Packet_scanf(&connp->r, "%c", &connp->Client_setup.options[i]);
4376 if (n <= 0) {
4377 Destroy_connection(ind, "Misread options");
4378 return -1;
4379 }
4380 }
4381 }
4382
4383 /* Read screen dimensions */
4384 if (is_newer_than(&connp->version, 4, 4, 9, 1, 0, 1)) {
4385 n = Packet_scanf(&connp->r, "%d%d", &connp->Client_setup.screen_wid, &connp->Client_setup.screen_hgt);
4386 if (n <= 0) {
4387 Destroy_connection(ind, "Misread dimensions");
4388 return -1;
4389 }
4390
4391 /* fix limits */
4392 #ifdef BIG_MAP
4393 if (connp->Client_setup.screen_wid > MAX_SCREEN_WID) connp->Client_setup.screen_wid = MAX_SCREEN_WID;
4394 if (connp->Client_setup.screen_wid < MIN_SCREEN_WID) connp->Client_setup.screen_wid = MIN_SCREEN_WID;
4395 if (connp->Client_setup.screen_hgt > MAX_SCREEN_HGT) connp->Client_setup.screen_hgt = MAX_SCREEN_HGT;
4396 if (connp->Client_setup.screen_hgt < MIN_SCREEN_HGT) connp->Client_setup.screen_hgt = MIN_SCREEN_HGT;
4397 /* for now until resolved: avoid dimensions whose half values aren't divisors of MAX_WID/HGT */
4398 if (MAX_WID % (connp->Client_setup.screen_wid / 2)) connp->Client_setup.screen_wid = SCREEN_WID;
4399 if (MAX_HGT % (connp->Client_setup.screen_hgt / 2)) connp->Client_setup.screen_hgt = SCREEN_HGT;
4400 #else
4401 connp->Client_setup.screen_wid = SCREEN_WID;
4402 connp->Client_setup.screen_hgt = SCREEN_HGT;
4403 #endif
4404 } else {
4405 connp->Client_setup.screen_wid = SCREEN_WID;
4406 connp->Client_setup.screen_hgt = SCREEN_HGT;
4407 }
4408
4409 /* Read the "unknown" char/attrs */
4410 for (i = 0; i < TV_MAX; i++) {
4411 n = Packet_scanf(&connp->r, "%c%c", &connp->Client_setup.u_attr[i], &connp->Client_setup.u_char[i]);
4412 if (n <= 0) {
4413 #ifdef STRICT_RECEIVE_PLAY
4414 Destroy_connection(ind, "Misread unknown redefinitions");
4415 return -1;
4416 #else
4417 break;
4418 #endif
4419 }
4420 }
4421
4422 /* Read the "feature" char/attrs */
4423 for (i = 0; i < MAX_F_IDX_COMPAT; i++) {
4424 n = Packet_scanf(&connp->r, "%c%c", &connp->Client_setup.f_attr[i], &connp->Client_setup.f_char[i]);
4425 if (n <= 0) {
4426 #ifdef STRICT_RECEIVE_PLAY
4427 Destroy_connection(ind, "Misread feature redefinitions");
4428 return -1;
4429 #else
4430 break;
4431 #endif
4432 }
4433 }
4434
4435 /* Read the "object" char/attrs */
4436 for (i = 0; i < MAX_K_IDX_COMPAT; i++) {
4437 n = Packet_scanf(&connp->r, "%c%c", &connp->Client_setup.k_attr[i], &connp->Client_setup.k_char[i]);
4438 if (n <= 0) {
4439 #ifdef STRICT_RECEIVE_PLAY
4440 Destroy_connection(ind, "Misread object redefinitions");
4441 return -1;
4442 #else
4443 break;
4444 #endif
4445 }
4446 }
4447
4448 /* Read the "monster" char/attrs */
4449 for (i = 0; i < MAX_R_IDX_COMPAT; i++) {
4450 n = Packet_scanf(&connp->r, "%c%c", &connp->Client_setup.r_attr[i], &connp->Client_setup.r_char[i]);
4451 if (n <= 0) {
4452 #ifdef STRICT_RECEIVE_PLAY
4453 Destroy_connection(ind, "Misread monster redefinitions");
4454 return -1;
4455 #else
4456 break;
4457 #endif
4458 }
4459 }
4460 #endif // 0
4461 }
4462 if (connp->state != CONN_LOGIN) {
4463 if (connp->state != CONN_PLAYING) {
4464 if (connp->state == CONN_READY) {
4465 connp->r.ptr = connp->r.buf + connp->r.len;
4466 return 0;
4467 }
4468 errno = 0;
4469 plog(format("Connection not in login state (%02x)", connp->state));
4470 Destroy_connection(ind, "not login");
4471 return -1;
4472 }
4473 //if (Send_reliable_old(ind) == -1)
4474 if (Send_reliable(ind) == -1)
4475 return -1;
4476 return 0;
4477 }
4478
4479 s_printf("AUDIO: %s features %hd, %hd.\n", connp->nick, sfx, mus);
4480 connp->audio_sfx = (short int)sfx;
4481 connp->audio_mus = (short int)mus;
4482
4483 Sockbuf_clear(&connp->w);
4484 if (Handle_login(ind) == -1) {
4485 /* The connection has already been destroyed */
4486 return -1;
4487 }
4488
4489 return 2;
4490 }
4491
4492 /* Head of file transfer system receive */
4493 /* DO NOT TOUCH - work in progress */
4494 static int Receive_file(int ind) {
4495 char command, ch;
4496 char fname[MAX_CHARS]; /* possible filename */
4497 int x; /* return value/ack */
4498 unsigned short fnum; /* unique SENDER side file number */
4499 unsigned short len;
4500 u32b csum;
4501 int n;
4502 connection_t *connp = Conn[ind];
4503 player_type *p_ptr = NULL;
4504 int Ind;
4505
4506 Ind = GetInd[connp->id];
4507 p_ptr = Players[Ind];
4508 n = Packet_scanf(&connp->r, "%c%c%hd", &ch, &command, &fnum);
4509 if (n == 3) {
4510 switch (command) {
4511 case PKT_FILE_INIT:
4512 /* Admin to do this only !!! */
4513 Packet_scanf(&connp->r, "%s", fname);
4514 if (!is_admin(p_ptr)) {
4515 msg_print(Ind, "\377rFile transfer refused");
4516 x = 0;
4517 } else {
4518 msg_print(Ind, "\377gAttempting file transfer");
4519 x = local_file_init(ind, fnum, fname);
4520 }
4521 break;
4522 case PKT_FILE_DATA:
4523 Packet_scanf(&connp->r, "%hd", &len);
4524 x = local_file_write(ind, fnum, len);
4525 break;
4526 case PKT_FILE_END:
4527 x = local_file_close(ind, fnum);
4528 msg_format(Ind, "\377oFile transfer %s.", x? "successful":"failed");
4529 break;
4530 case PKT_FILE_CHECK:
4531 /* Admin to do this only !!! */
4532 Packet_scanf(&connp->r, "%s", fname);
4533 if (!is_admin(p_ptr)) {
4534 msg_print(Ind, "\377rFile check refused");
4535 x = 0;
4536 } else {
4537 msg_print(Ind, "\377yChecking file");
4538 x = local_file_check(fname, &csum);
4539 Packet_printf(&connp->w, "%c%c%hd%d", PKT_FILE, PKT_FILE_SUM, fnum, csum);
4540 return(1);
4541 }
4542 break;
4543 case PKT_FILE_SUM:
4544 Packet_scanf(&connp->r, "%d", &csum);
4545 check_return(ind, fnum, csum, Ind);
4546
4547 /* for 4.4.8.1.0.0 LUA update crash bug */
4548 if (p_ptr->warning_lua_count == 0 && p_ptr->warning_lua_update == 1
4549 /* don't give him messages if he can't help it */
4550 && !p_ptr->v_latest) {
4551 msg_print(Ind, "\377RWarning: Due to a bug in client 4.4.8 it cannot update LUA files.");
4552 msg_print(Ind, "\377R If you play spell-casting characters please update your client!");
4553 }
4554
4555 return(1);
4556 break;
4557 case PKT_FILE_ACK:
4558 local_file_ack(ind, fnum);
4559 return(1);
4560 break;
4561 case PKT_FILE_ERR:
4562 local_file_err(ind, fnum);
4563 /* continue the send/terminate */
4564 return(1);
4565 break;
4566 default:
4567 printf("unknown file transfer packet\n");
4568 x = 0;
4569 }
4570 Packet_printf(&connp->c, "%c%c%hd", PKT_FILE, x?PKT_FILE_ACK:PKT_FILE_ERR, fnum);
4571 }
4572 return(1);
4573 }
4574
4575 int Receive_file_data(int ind, unsigned short len, char *buffer) {
4576 connection_t *connp = Conn[ind];
4577 memcpy(buffer, connp->r.ptr, len);
4578 connp->r.ptr += len;
4579 return(1);
4580 }
4581
4582 int Send_file_check(int ind, unsigned short id, char *fname) {
4583 connection_t *connp = Conn[ind];
4584 Packet_printf(&connp->c, "%c%c%hd%s", PKT_FILE, PKT_FILE_CHECK, id, fname);
4585 return(1);
4586 }
4587
4588 int Send_file_init(int ind, unsigned short id, char *fname) {
4589 connection_t *connp = Conn[ind];
4590 Packet_printf(&connp->c, "%c%c%hd%s", PKT_FILE, PKT_FILE_INIT, id, fname);
4591 return(1);
4592 }
4593
4594 int Send_file_data(int ind, unsigned short id, char *buf, unsigned short len) {
4595 connection_t *connp = Conn[ind];
4596 Packet_printf(&connp->c, "%c%c%hd%hd", PKT_FILE, PKT_FILE_DATA, id, len);
4597 if (Sockbuf_write(&connp->c, buf, len) != len) {
4598 printf("failed sending file data\n");
4599 }
4600 return(1);
4601 }
4602
4603 int Send_file_end(int ind, unsigned short id) {
4604 connection_t *connp = Conn[ind];
4605 Packet_printf(&connp->c, "%c%c%hd", PKT_FILE, PKT_FILE_END, id);
4606 return(1);
4607 }
4608
4609 int Send_reliable(int ind)
4610 {
4611 connection_t *connp = Conn[ind];
4612 int num_written;
4613
4614 /* Hack -- make sure we have a valid socket to write to. -1 is used to
4615 * specify a player that has disconnected but is still "in game".
4616 */
4617 if (connp->w.sock == -1) return 0;
4618
4619 if (Sockbuf_write(&connp->w, connp->c.buf, connp->c.len) != connp->c.len)
4620 {
4621 plog("Cannot write reliable data");
4622 Destroy_connection(ind, "write error");
4623 return -1;
4624 }
4625 if ((num_written = Sockbuf_flush(&connp->w)) < connp->w.len)
4626 {
4627 plog(format("Cannot flush reliable data (%d)", num_written));
4628 Destroy_connection(ind, "flush error");
4629
4630 #if 0
4631 /* Very bad hack :/ - C. Blue */
4632 save_game_panic();
4633 #endif
4634
4635 return -1;
4636 }
4637 Sockbuf_clear(&connp->c);
4638 return num_written;
4639 }
4640
4641 #if 0 /* old UDP networking stuff - mikaelh */
4642 int Send_reliable_old(int ind)
4643 {
4644 connection_t *connp = Conn[ind];
4645 char *read_buf;
4646 int i, n, len, todo, max_todo, rel_off;
4647 const int max_packet_size = MAX_RELIABLE_DATA_PACKET_SIZE,
4648 min_send_size = 1;
4649
4650 if (connp->c.len <= 0 || connp->last_send_loops == turn) {
4651 connp->last_send_loops = turn;
4652 return 0;
4653 }
4654 read_buf = connp->c.buf;
4655 max_todo = connp->c.len;
4656 rel_off = connp->reliable_offset;
4657 if (connp->w.len > 0) {
4658 if (connp->w.len >= max_packet_size - min_send_size)
4659 return 0;
4660 if (max_todo > max_packet_size - connp->w.len)
4661 max_todo = max_packet_size - connp->w.len;
4662 }
4663 if (connp->retransmit_at_loop > turn)
4664 {
4665 if (max_todo <= connp->reliable_unsent - connp->reliable_offset
4666 + min_send_size || connp->w.len == 0)
4667 return 0;
4668 }
4669 else if (connp->retransmit_at_loop != 0)
4670 connp->acks >>= 1;
4671
4672 todo = max_todo;
4673
4674 for (i = 0; i <= connp->acks && todo > 0; i++)
4675 {
4676 len = (todo > max_packet_size) ? max_packet_size : todo;
4677 if (Packet_printf(&connp->w, "%c%hd%d%d%d", PKT_RELIABLE,
4678 len, rel_off, turn, max_todo) <= 0
4679 || Sockbuf_write(&connp->w, read_buf, len) != len)
4680 {
4681 plog("Cannot write reliable data");
4682 Destroy_connection(ind, "write error");
4683 return -1;
4684 }
4685
4686 if ((n = Sockbuf_flush(&connp->w)) < len)
4687 {
4688 if (n == 0 && (errno == EWOULDBLOCK
4689 || errno == EAGAIN))
4690 {
4691 connp->acks = 0;
4692 break;
4693 }
4694 else
4695 {
4696 plog(format("Cannot flush reliable data (%d)", n));
4697 Destroy_connection(ind, "flush error");
4698 return -1;
4699 }
4700 }
4701
4702 todo -= len;
4703 rel_off += len;
4704 read_buf += len;
4705 }
4706
4707 Sockbuf_clear(&connp->w);
4708
4709 connp->last_send_loops = turn;
4710
4711 if (max_todo - todo <= 0)
4712 return 0;
4713
4714 if (connp->rtt_retransmit > MAX_RETRANSMIT)
4715 connp->rtt_retransmit = MAX_RETRANSMIT;
4716 if (connp->retransmit_at_loop <= turn)
4717 {
4718 connp->retransmit_at_loop = turn + connp->rtt_retransmit;
4719 connp->rtt_retransmit <<= 1;
4720 connp->rtt_timeouts++;
4721 }
4722 else connp->retransmit_at_loop = turn + connp->rtt_retransmit;
4723
4724 if (rel_off > connp->reliable_unsent)
4725 connp->reliable_unsent = rel_off;
4726
4727 return (max_todo - todo);
4728 }
4729 #endif
4730
4731 #if 0 /* old UDP networking stuff - mikaelh */
4732 static int Receive_ack(int ind)
4733 {
4734 connection_t *connp = Conn[ind];
4735 int n;
4736 unsigned char ch;
4737 int rel, rtt, diff, delta, rel_loops;
4738
4739 if ((n = Packet_scanf(&connp->r, "%c%d%d", &ch, &rel, &rel_loops))
4740 <= 0)
4741 {
4742 errno = 0;
4743 plog(format("Cannot read ack packet (%d)", n));
4744 Destroy_connection(ind, "read error");
4745 return -1;
4746 }
4747 if (ch != PKT_ACK)
4748 {
4749 errno = 0;
4750 plog(format("Not an ack packet (%d)", ch));
4751 Destroy_connection(ind, "not ack");
4752 return -1;
4753 }
4754 rtt = turn - rel_loops;
4755 if (rtt > 0 && rtt <= MAX_RTT)
4756 {
4757 if (connp->rtt_smoothed == 0)
4758 connp->rtt_smoothed = rtt << 3;
4759 delta = rtt - (connp->rtt_smoothed >> 3);
4760 connp->rtt_smoothed += delta;
4761 if (delta < 0)
4762 delta = -delta;
4763 connp->rtt_dev += delta - (connp->rtt_dev >> 2);
4764 connp->rtt_retransmit = ((connp->rtt_smoothed >> 2)
4765 + connp->rtt_dev) >> 1;
4766 if (connp->rtt_retransmit < MIN_RETRANSMIT)
4767 connp->rtt_retransmit = MIN_RETRANSMIT;
4768 }
4769 diff = rel - connp->reliable_offset;
4770 if (diff > connp->c.len)
4771 {
4772 errno = 0;
4773 plog(format("Bad ack (diff=%d,cru=%d,c=%d,len=%d)",
4774 diff, rel, connp->reliable_offset, connp->c.len));
4775 Destroy_connection(ind, "bad ack");
4776 return -1;
4777 }
4778 else if (diff <= 0)
4779 return 1;
4780 Sockbuf_advance(&connp->c, (int) diff);
4781 connp->reliable_offset += diff;
4782 if ((n = ((diff + 512 - 1) / 512)) > connp->acks)
4783 connp->acks = n;
4784 else
4785 connp->acks++;
4786 if (connp->reliable_offset >= connp->reliable_unsent)
4787 {
4788 connp->retransmit_at_loop = 0;
4789 if (connp->state == CONN_DRAIN)
4790 Conn_set_state(connp, connp->drain_state, connp->drain_state);
4791 }
4792 if (connp->state == CONN_READY
4793 && (connp->c.len <= 0
4794 || (connp->c.buf[0] != PKT_REPLY
4795 && connp->c.buf[0] != PKT_PLAY
4796 && connp->c.buf[0] != PKT_SUCCESS
4797 && connp->c.buf[0] != PKT_FAILURE)))
4798 Conn_set_state(connp, connp->drain_state, connp->drain_state);
4799
4800 connp->rtt_timeouts = 0;
4801
4802 /*printf("Received ack to data sent at %d.\n", rel_loops);*/
4803
4804 return 1;
4805 }
4806 #endif
4807
4808 static int Receive_discard(int ind)
4809 {
4810 connection_t *connp = Conn[ind];
4811
4812 errno = 0;
4813 plog(format("Discarding packet %d while in state %02x",
4814 connp->r.ptr[0], connp->state));
4815 connp->r.ptr = connp->r.buf + connp->r.len;
4816
4817 return 0;
4818 }
4819
4820 static int Receive_undefined(int ind)
4821 {
4822 connection_t *connp = Conn[ind];
4823
4824 errno = 0;
4825 plog(format("Unknown packet type (%d,%02x)", connp->r.ptr[0], connp->state));
4826
4827 /* Dont destroy connection. Ignore the invalid packet */
4828 /*Destroy_connection(ind, "undefined packet");*/
4829
4830 /* Discard everything - mikaelh */
4831 connp->r.ptr = connp->r.buf + connp->r.len;
4832
4833 return -1; /* Crash if not (evil) */
4834 /*return 0;*/
4835 }
4836
4837 int Send_plusses(int ind, int tohit, int todam, int hr, int dr, int hm, int dm)
4838 {
4839 connection_t *connp = Conn[Players[ind]->conn], *connp2;
4840 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[ind];*/
4841
4842 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
4843 {
4844 errno = 0;
4845 plog(format("Connection not ready for plusses (%d.%d.%d)",
4846 ind, connp->state, connp->id));
4847 return 0;
4848 }
4849
4850 if (get_esp_link(ind, LINKF_MISC, &p_ptr2)) {
4851 connp2 = Conn[p_ptr2->conn];
4852 Packet_printf(&connp2->c, "%c%hd%hd%hd%hd%hd%hd", PKT_PLUSSES, tohit, todam, hr, dr, hm, dm);
4853 }
4854
4855 return Packet_printf(&connp->c, "%c%hd%hd%hd%hd%hd%hd", PKT_PLUSSES, tohit, todam, hr, dr, hm, dm);
4856 }
4857
4858
4859 int Send_ac(int ind, int base, int plus)
4860 {
4861 connection_t *connp = Conn[Players[ind]->conn], *connp2;
4862 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[ind];*/
4863
4864 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
4865 {
4866 errno = 0;
4867 plog(format("Connection not ready for ac (%d.%d.%d)",
4868 ind, connp->state, connp->id));
4869 return 0;
4870 }
4871 if (get_esp_link(ind, LINKF_MISC, &p_ptr2)) {
4872 connp2 = Conn[p_ptr2->conn];
4873 Packet_printf(&connp2->c, "%c%hd%hd", PKT_AC, base, plus);
4874 }
4875 return Packet_printf(&connp->c, "%c%hd%hd", PKT_AC, base, plus);
4876 }
4877
4878 int Send_experience(int Ind, int lev, s32b max, s32b cur, s32b adv, s32b adv_prev) {
4879 connection_t *connp = Conn[Players[Ind]->conn];
4880
4881
4882 int Ind2;
4883 connection_t *connp2;
4884 player_type *p_ptr2 = NULL;
4885
4886 if (Players[Ind]->esp_link_flags & LINKF_VIEW_DEDICATED) return(0);
4887 if ((Ind2 = get_esp_link(Ind, LINKF_VIEW, &p_ptr2))) {
4888 connp2 = Conn[p_ptr2->conn];
4889 if (is_newer_than(&Players[Ind2]->version, 4, 5, 6, 0, 0, 1))
4890 /* hack: add marker to 'lev' to allow keeping track of exp_frac during level 1 exp'ing phase */
4891 Packet_printf(&connp2->c, "%c%hu%hu%hu%d%d%d%d", PKT_EXPERIENCE, lev + (Players[Ind]->exp_frac >= 5000 ? 1000 : 0), Players[Ind]->max_lev, Players[Ind]->max_plv, max, cur, adv, adv_prev);
4892 else if (is_newer_than(&Players[Ind2]->version, 4, 4, 1, 3, 0, 0))
4893 Packet_printf(&connp2->c, "%c%hu%hu%hu%d%d%d", PKT_EXPERIENCE, lev, Players[Ind]->max_lev, Players[Ind]->max_plv, max, cur, adv);
4894 else
4895 Packet_printf(&connp2->c, "%c%hu%d%d%d", PKT_EXPERIENCE, lev, max, cur, adv);
4896 }
4897
4898
4899 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
4900 errno = 0;
4901 plog(format("Connection not ready for experience (%d.%d.%d)",
4902 Ind, connp->state, connp->id));
4903 return 0;
4904 }
4905
4906 if (is_newer_than(&Players[Ind]->version, 4, 5, 6, 0, 0, 1))
4907 /* hack: add marker to 'lev' to allow keeping track of exp_frac during level 1 exp'ing phase */
4908 return Packet_printf(&connp->c, "%c%hu%hu%hu%d%d%d%d", PKT_EXPERIENCE, lev + (Players[Ind]->exp_frac >= 5000 ? 1000 : 0), Players[Ind]->max_lev, Players[Ind]->max_plv, max, cur, adv, adv_prev);
4909 else if (is_newer_than(&Players[Ind]->version, 4, 4, 1, 3, 0, 0))
4910 return Packet_printf(&connp->c, "%c%hu%hu%hu%d%d%d", PKT_EXPERIENCE, lev, Players[Ind]->max_lev, Players[Ind]->max_plv, max, cur, adv);
4911 else
4912 return Packet_printf(&connp->c, "%c%hu%d%d%d", PKT_EXPERIENCE, lev, max, cur, adv);
4913 }
4914
4915 #if 0
4916 int Send_skill_init(int Ind, int type, int i)
4917 #else
4918 int Send_skill_init(int Ind, u16b i)
4919 #endif
4920 {
4921 connection_t *connp = Conn[Players[Ind]->conn];
4922
4923 char *tmp;
4924 int mkey;
4925
4926 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
4927 {
4928 errno = 0;
4929 plog(format("Connection not ready for skill init (%d.%d.%d)",
4930 Ind, connp->state, connp->id));
4931 return 0;
4932 }
4933
4934 tmp = s_info[i].action_desc ? s_text + s_info[i].action_desc : "";
4935 mkey = s_info[i].action_mkey;
4936
4937 /* hack for fighting/shooting techniques */
4938 if (mkey == MKEY_MELEE && Players[Ind]->melee_techniques == 0x0000) mkey = 0;
4939 if (mkey == MKEY_RANGED && Players[Ind]->ranged_techniques == 0x0000) mkey = 0;
4940
4941 /* Note: %hd is 2 bytes - use this for x16b.
4942 We can use %c for bytes. */
4943 return( Packet_printf(&connp->c, "%c%hd%hd%hd%hd%d%c%S%S%S",
4944 PKT_SKILL_INIT, i,
4945 s_info[i].father, s_info[i].order, mkey,
4946 s_info[i].flags1, s_info[i].tval, s_name+s_info[i].name,
4947 s_text+s_info[i].desc, tmp ? tmp : "" ) );
4948
4949 }
4950
4951 int Send_skill_points(int Ind) {
4952 connection_t *connp = Conn[Players[Ind]->conn];
4953 player_type *p_ptr = Players[Ind];
4954
4955 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
4956 {
4957 errno = 0;
4958 plog(format("Connection not ready for skill mod (%d.%d.%d)",
4959 Ind, connp->state, connp->id));
4960 return 0;
4961 }
4962 return Packet_printf(&connp->c, "%c%d", PKT_SKILL_PTS, p_ptr->skill_points);
4963 }
4964
4965 /* i is skill index, keep means if we want the client to keep his 'deflated?' state */
4966 int Send_skill_info(int Ind, int i, bool keep)
4967 {
4968 connection_t *connp = Conn[Players[Ind]->conn];
4969 player_type *p_ptr = Players[Ind];
4970 int mkey;
4971
4972 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
4973 {
4974 errno = 0;
4975 plog(format("Connection not ready for skill mod (%d.%d.%d)",
4976 Ind, connp->state, connp->id));
4977 return 0;
4978 }
4979
4980 mkey = s_info[i].action_mkey;
4981 /* hack for fighting/shooting techniques */
4982 if (mkey == MKEY_MELEE && Players[Ind]->melee_techniques == 0x0000) mkey = 0;
4983 if (mkey == MKEY_RANGED && Players[Ind]->ranged_techniques == 0x0000) mkey = 0;
4984
4985 #ifndef ENABLE_DRACONIAN_TRAITS
4986 if (mkey == MKEY_BREATH) mkey = 0;
4987 #endif
4988
4989 if (!is_newer_than(&connp->version, 4, 4, 1, 2, 0, 0))
4990 return Packet_printf(&connp->c, "%c%d%d%d%d%d", PKT_SKILL_MOD, i, p_ptr->s_info[i].value, p_ptr->s_info[i].mod, p_ptr->s_info[i].dev, p_ptr->s_info[i].flags1 & SKF1_HIDDEN);
4991 else if (!is_newer_than(&connp->version, 4, 4, 1, 7, 0, 0)) {
4992 return Packet_printf(&connp->c, "%c%d%d%d%d%d%d", PKT_SKILL_MOD, i, p_ptr->s_info[i].value, p_ptr->s_info[i].mod, p_ptr->s_info[i].dev, p_ptr->s_info[i].flags1 & SKF1_HIDDEN, mkey);
4993 } else if (!is_newer_than(&connp->version, 4, 4, 4, 1, 0, 0)) {
4994 return Packet_printf(&connp->c, "%c%d%d%d%d%d%d%d", PKT_SKILL_MOD, i, p_ptr->s_info[i].value, p_ptr->s_info[i].mod, p_ptr->s_info[i].dev, p_ptr->s_info[i].flags1 & SKF1_HIDDEN, mkey, p_ptr->s_info[i].flags1 & SKF1_DUMMY);
4995 } else if (!is_newer_than(&connp->version, 4, 4, 6, 2, 0, 0)) {
4996 return Packet_printf(&connp->c, "%c%d%d%d%d%c%d", PKT_SKILL_MOD, i, p_ptr->s_info[i].value, p_ptr->s_info[i].mod, p_ptr->s_info[i].dev, p_ptr->s_info[i].flags1, mkey);
4997 } else {
4998 return Packet_printf(&connp->c, "%c%d%d%d%d%c%d", PKT_SKILL_MOD, i, p_ptr->s_info[i].value, p_ptr->s_info[i].mod, keep ? -1 : (p_ptr->s_info[i].dev ? 1 : 0), p_ptr->s_info[i].flags1, mkey);
4999 }
5000 }
5001
5002 int Send_gold(int Ind, s32b au, s32b balance)
5003 {
5004 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5005 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
5006
5007 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5008 {
5009 errno = 0;
5010 plog(format("Connection not ready for gold (%d.%d.%d)",
5011 Ind, connp->state, connp->id));
5012 return 0;
5013 }
5014 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5015 connp2 = Conn[p_ptr2->conn];
5016 Packet_printf(&connp2->c, "%c%d%d", PKT_GOLD, au, balance);
5017 }
5018 return Packet_printf(&connp->c, "%c%d%d", PKT_GOLD, au, balance);
5019 }
5020
5021 #if 0 // well, it's easily cracked by client
5022 int Send_sanity(int Ind, int msane, int csane)
5023 {
5024 #ifdef SHOW_SANITY
5025 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5026 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
5027 // printf("sanity send!\n");
5028
5029 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5030 {
5031 errno = 0;
5032 plog(format("Connection not ready for hp (%d.%d.%d)",
5033 Ind, connp->state, connp->id));
5034 return 0;
5035 }
5036 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5037 connp2 = Conn[p_ptr2->conn];
5038 Packet_printf(&connp2->c, "%c%hd%hd", PKT_SANITY, msane, csane);
5039 }
5040 return Packet_printf(&connp->c, "%c%hd%hd", PKT_SANITY, msane, csane);
5041 #endif // SHOW_SANITY
5042 }
5043 #else // 0
5044 int Send_sanity(int Ind, byte attr, cptr msg)
5045 {
5046 #ifdef SHOW_SANITY
5047 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5048 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
5049 // printf("sanity send!\n");
5050
5051 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5052 {
5053 errno = 0;
5054 plog(format("Connection not ready for hp (%d.%d.%d)",
5055 Ind, connp->state, connp->id));
5056 return 0;
5057 }
5058 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5059 connp2 = Conn[p_ptr2->conn];
5060 Packet_printf(&connp2->c, "%c%c%s", PKT_SANITY, attr, msg);
5061 }
5062 return Packet_printf(&connp->c, "%c%c%s", PKT_SANITY, attr, msg);
5063 #endif // SHOW_SANITY
5064 }
5065 #endif // 0
5066
5067 int Send_hp(int Ind, int mhp, int chp)
5068 {
5069 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5070 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
5071
5072 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5073 {
5074 errno = 0;
5075 plog(format("Connection not ready for hp (%d.%d.%d)",
5076 Ind, connp->state, connp->id));
5077 return 0;
5078 }
5079 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5080 connp2 = Conn[p_ptr2->conn];
5081 Packet_printf(&connp2->c, "%c%hd%hd", PKT_HP, mhp, chp);
5082 }
5083 return Packet_printf(&connp->c, "%c%hd%hd", PKT_HP, mhp, chp);
5084 }
5085
5086 int Send_sp(int Ind, int msp, int csp)
5087 {
5088 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5089 player_type *p_ptr = Players[Ind], *p_ptr2 = NULL;
5090
5091 #if 1 /* can we use mana at all? */
5092 if (is_newer_than(&p_ptr->version, 4, 4, 1, 3, 0, 0) &&
5093 (p_ptr->pclass == CLASS_WARRIOR || p_ptr->pclass == CLASS_ARCHER)) {
5094 msp = -9999;
5095 csp = -9999;
5096 }
5097 #endif
5098
5099 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5100 {
5101 errno = 0;
5102 plog(format("Connection not ready for sp (%d.%d.%d)",
5103 Ind, connp->state, connp->id));
5104 return 0;
5105 }
5106 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5107 connp2 = Conn[p_ptr2->conn];
5108 Packet_printf(&connp2->c, "%c%hd%hd", PKT_SP, msp, csp);
5109 }
5110 return Packet_printf(&connp->c, "%c%hd%hd", PKT_SP, msp, csp);
5111 }
5112
5113 int Send_stamina(int Ind, int mst, int cst) {
5114 player_type *p_ptr = Players[Ind], *p_ptr2 = NULL;
5115 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5116
5117 #ifndef ENABLE_TECHNIQUES
5118 #ifdef ENABLE_DRACONIAN_TRAITS
5119 /* may breathe elements for stamina */
5120 if (p_ptr->race != RACE_DRACONIAN)
5121 #endif
5122 return(0); /* disabled until client can handle it */
5123 #endif
5124
5125 if (!is_newer_than(&connp->version, 4, 4, 1, 2, 0, 0)) return(0);
5126
5127 /* can we use stamina at all? */
5128 if (is_newer_than(&p_ptr->version, 4, 4, 1, 3, 0, 0) &&
5129 (p_ptr->pclass == CLASS_MAGE || p_ptr->pclass == CLASS_PRIEST ||
5130 p_ptr->pclass == CLASS_SHAMAN)
5131 #ifdef ENABLE_DRACONIAN_TRAITS
5132 /* may breathe elements for stamina */
5133 && p_ptr->prace != RACE_DRACONIAN
5134 #endif
5135 ) {
5136 mst = -9999;
5137 cst = -9999;
5138 }
5139
5140 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
5141 errno = 0;
5142 plog(format("Connection not ready for hp (%d.%d.%d)",
5143 Ind, connp->state, connp->id));
5144 return 0;
5145 }
5146 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5147 connp2 = Conn[p_ptr2->conn];
5148 Packet_printf(&connp2->c, "%c%hd%hd", PKT_STAMINA, mst, cst);
5149 }
5150 return Packet_printf(&connp->c, "%c%hd%hd", PKT_STAMINA, mst, cst);
5151 }
5152
5153 int Send_char_info(int Ind, int race, int class, int trait, int sex, int mode, cptr name) {
5154 connection_t *connp = Conn[Players[Ind]->conn];
5155
5156 #ifndef ENABLE_DRACONIAN_TRAITS
5157 if (race == RACE_DRACONIAN) trait = 0;
5158 #endif
5159
5160 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
5161 errno = 0;
5162 plog(format("Connection not ready for char info (%d.%d.%d)",
5163 Ind, connp->state, connp->id));
5164 return 0;
5165 }
5166
5167 if (is_newer_than(&connp->version, 4, 5, 2, 0, 0, 0)) {
5168 return Packet_printf(&connp->c, "%c%hd%hd%hd%hd%hd%s", PKT_CHAR_INFO, race, class, trait, sex, mode, name);
5169 } else if (is_newer_than(&connp->version, 4, 4, 5, 10, 0, 0)) {
5170 return Packet_printf(&connp->c, "%c%hd%hd%hd%hd%hd", PKT_CHAR_INFO, race, class, trait, sex, mode);
5171 } else {
5172 return Packet_printf(&connp->c, "%c%hd%hd%hd%hd", PKT_CHAR_INFO, race, class, sex, mode);
5173 }
5174 }
5175
5176 int Send_various(int Ind, int hgt, int wgt, int age, int sc, cptr body)
5177 {
5178 connection_t *connp = Conn[Players[Ind]->conn];
5179
5180 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5181 {
5182 errno = 0;
5183 plog(format("Connection not ready for various (%d.%d.%d)",
5184 Ind, connp->state, connp->id));
5185 return 0;
5186 }
5187 return Packet_printf(&connp->c, "%c%hu%hu%hu%hu%s", PKT_VARIOUS, hgt, wgt, age, sc, body);
5188 }
5189
5190 int Send_stat(int Ind, int stat, int max, int cur, int s_ind, int max_base)
5191 {
5192 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5193 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
5194
5195 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5196 {
5197 errno = 0;
5198 plog(format("Connection not ready for stat (%d.%d.%d)",
5199 Ind, connp->state, connp->id));
5200 return 0;
5201 }
5202
5203 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5204 connp2 = Conn[p_ptr2->conn];
5205 Packet_printf(&connp2->c, "%c%c%hd%hd%hd%hd", PKT_STAT, stat, max, cur, s_ind, max_base);
5206 }
5207
5208 return Packet_printf(&connp->c, "%c%c%hd%hd%hd%hd", PKT_STAT, stat, max, cur, s_ind, max_base);
5209 }
5210
5211 int Send_history(int Ind, int line, cptr hist)
5212 {
5213 connection_t *connp = Conn[Players[Ind]->conn];
5214
5215 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5216 {
5217 errno = 0;
5218 plog(format("Connection not ready for history (%d.%d.%d)",
5219 Ind, connp->state, connp->id));
5220 return 0;
5221 }
5222 return Packet_printf(&connp->c, "%c%hu%s", PKT_HISTORY, line, hist);
5223 }
5224
5225 /* XXX 'pval' is sent only when the item is TV_BOOK (same with Send_equip)
5226 * otherwise you can use badly-cracked client :) - Jir -
5227 */
5228 int Send_inven(int Ind, char pos, byte attr, int wgt, object_type *o_ptr, cptr name) {
5229 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5230 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
5231 char uses_dir = 0; /* flag whether a rod requires a direction for zapping or not */
5232
5233 /* Mark rods that require a direction */
5234 if (o_ptr->tval == TV_ROD && rod_requires_direction(Ind, o_ptr))
5235 uses_dir = 1;
5236
5237 /* Mark activatable items that require a direction */
5238 if (activation_requires_direction(o_ptr)
5239 //appearently not for A'able items >_> || !object_aware_p(Ind, o_ptr))
5240 ) {
5241 uses_dir = 1;
5242 }
5243
5244 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
5245 errno = 0;
5246 plog(format("Connection not ready for inven (%d.%d.%d)",
5247 Ind, connp->state, connp->id));
5248 return 0;
5249 }
5250
5251 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5252 connp2 = Conn[p_ptr2->conn];
5253 if (is_newer_than(&p_ptr2->version, 4, 5, 2, 0, 0, 0))
5254 Packet_printf(&connp2->c, "%c%c%c%hu%hd%c%c%hd%hd%c%I", PKT_INVEN, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval, o_ptr->tval == TV_BOOK ? o_ptr->pval : 0, object_known_p(Ind, o_ptr) ? o_ptr->name1 : 0, uses_dir, name);
5255 else if (is_newer_than(&p_ptr2->version, 4, 4, 5, 10, 0, 0))
5256 Packet_printf(&connp2->c, "%c%c%c%hu%hd%c%c%hd%c%I", PKT_INVEN, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval, o_ptr->tval == TV_BOOK ? o_ptr->pval : 0, uses_dir, name);
5257 else if (is_newer_than(&p_ptr2->version, 4, 4, 4, 2, 0, 0))
5258 Packet_printf(&connp2->c, "%c%c%c%hu%hd%c%c%hd%I", PKT_INVEN, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval, o_ptr->tval == TV_BOOK ? o_ptr->pval : 0, name);
5259 else
5260 Packet_printf(&connp2->c, "%c%c%c%hu%hd%c%c%hd%s", PKT_INVEN, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval, o_ptr->tval == TV_BOOK ? o_ptr->pval : 0, name);
5261 }
5262
5263 if (is_newer_than(&Players[Ind]->version, 4, 5, 2, 0, 0, 0))
5264 return Packet_printf(&connp->c, "%c%c%c%hu%hd%c%c%hd%hd%c%I", PKT_INVEN, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval, o_ptr->tval == TV_BOOK ? o_ptr->pval : 0, object_known_p(Ind, o_ptr) ? o_ptr->name1 : 0, uses_dir, name);
5265 else if (is_newer_than(&Players[Ind]->version, 4, 4, 5, 10, 0, 0))
5266 return Packet_printf(&connp->c, "%c%c%c%hu%hd%c%c%hd%c%I", PKT_INVEN, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval, o_ptr->tval == TV_BOOK ? o_ptr->pval : 0, uses_dir, name);
5267 else if (is_newer_than(&Players[Ind]->version, 4, 4, 4, 2, 0, 0))
5268 return Packet_printf(&connp->c, "%c%c%c%hu%hd%c%c%hd%I", PKT_INVEN, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval, o_ptr->tval == TV_BOOK ? o_ptr->pval : 0, name);
5269 else
5270 return Packet_printf(&connp->c, "%c%c%c%hu%hd%c%c%hd%s", PKT_INVEN, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval, o_ptr->tval == TV_BOOK ? o_ptr->pval : 0, name);
5271 }
5272
5273 int Send_inven_wide(int Ind, char pos, byte attr, int wgt, object_type *o_ptr, cptr name) {
5274 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5275 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
5276
5277 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
5278 errno = 0;
5279 plog(format("Connection not ready for inven (%d.%d.%d)",
5280 Ind, connp->state, connp->id));
5281 return 0;
5282 }
5283
5284 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5285 connp2 = Conn[p_ptr2->conn];
5286 if (is_newer_than(&p_ptr2->version, 4, 5, 2, 0, 0, 0))
5287 Packet_printf(&connp2->c, "%c%c%c%hu%hd%c%c%hd%hd%c%c%c%c%c%c%c%c%c%I", PKT_INVEN_WIDE, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval,
5288 o_ptr->tval == TV_BOOK ? o_ptr->pval : 0, object_known_p(Ind, o_ptr) ? o_ptr->name1 : 0,
5289 o_ptr->xtra1, o_ptr->xtra2, o_ptr->xtra3, o_ptr->xtra4, o_ptr->xtra5, o_ptr->xtra6, o_ptr->xtra7, o_ptr->xtra8, o_ptr->xtra9, name);
5290 else if (is_newer_than(&p_ptr2->version, 4, 4, 4, 2, 0, 0))
5291 Packet_printf(&connp2->c, "%c%c%c%hu%hd%c%c%hd%c%c%c%c%c%c%c%c%c%I", PKT_INVEN_WIDE, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval, o_ptr->tval == TV_BOOK ? o_ptr->pval : 0,
5292 o_ptr->xtra1, o_ptr->xtra2, o_ptr->xtra3, o_ptr->xtra4, o_ptr->xtra5, o_ptr->xtra6, o_ptr->xtra7, o_ptr->xtra8, o_ptr->xtra9, name);
5293 else
5294 Packet_printf(&connp2->c, "%c%c%c%hu%hd%c%c%hd%c%c%c%c%c%c%c%c%c%s", PKT_INVEN_WIDE, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval, o_ptr->tval == TV_BOOK ? o_ptr->pval : 0,
5295 o_ptr->xtra1, o_ptr->xtra2, o_ptr->xtra3, o_ptr->xtra4, o_ptr->xtra5, o_ptr->xtra6, o_ptr->xtra7, o_ptr->xtra8, o_ptr->xtra9, name);
5296 }
5297
5298 if (is_newer_than(&Players[Ind]->version, 4, 5, 2, 0, 0, 0))
5299 return Packet_printf(&connp->c, "%c%c%c%hu%hd%c%c%hd%hd%c%c%c%c%c%c%c%c%c%I", PKT_INVEN_WIDE, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval,
5300 o_ptr->tval == TV_BOOK ? o_ptr->pval : 0, object_known_p(Ind, o_ptr) ? o_ptr->name1 : 0,
5301 o_ptr->xtra1, o_ptr->xtra2, o_ptr->xtra3, o_ptr->xtra4, o_ptr->xtra5, o_ptr->xtra6, o_ptr->xtra7, o_ptr->xtra8, o_ptr->xtra9, name);
5302 else if (is_newer_than(&Players[Ind]->version, 4, 4, 4, 2, 0, 0))
5303 return Packet_printf(&connp->c, "%c%c%c%hu%hd%c%c%hd%c%c%c%c%c%c%c%c%c%I", PKT_INVEN_WIDE, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval, o_ptr->tval == TV_BOOK ? o_ptr->pval : 0,
5304 o_ptr->xtra1, o_ptr->xtra2, o_ptr->xtra3, o_ptr->xtra4, o_ptr->xtra5, o_ptr->xtra6, o_ptr->xtra7, o_ptr->xtra8, o_ptr->xtra9, name);
5305 else
5306 return Packet_printf(&connp->c, "%c%c%c%hu%hd%c%c%hd%c%c%c%c%c%c%c%c%c%s", PKT_INVEN_WIDE, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval, o_ptr->tval == TV_BOOK ? o_ptr->pval : 0,
5307 o_ptr->xtra1, o_ptr->xtra2, o_ptr->xtra3, o_ptr->xtra4, o_ptr->xtra5, o_ptr->xtra6, o_ptr->xtra7, o_ptr->xtra8, o_ptr->xtra9, name);
5308 }
5309
5310 //int Send_equip(int Ind, char pos, byte attr, int wgt, byte tval, cptr name)
5311 int Send_equip(int Ind, char pos, byte attr, int wgt, object_type *o_ptr, cptr name) {
5312 char uses_dir = 0;
5313 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5314 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
5315 int slot = INVEN_WIELD + pos - 'a';
5316
5317 /* Mark activatable items that require a direction */
5318 if (activation_requires_direction(o_ptr)
5319 //appearently not for A'able items >_> || !object_aware_p(Ind, o_ptr))
5320 ) {
5321 uses_dir = 1;
5322 }
5323
5324 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
5325 errno = 0;
5326 plog(format("Connection not ready for equip (%d.%d.%d)",
5327 Ind, connp->state, connp->id));
5328 return 0;
5329 }
5330
5331 /* for characters in forms that cannot use full equipment */
5332 if (!item_tester_hook_wear(Ind, slot)) {
5333 attr = TERM_L_DARK;
5334 name = "(unavailable)";
5335 }
5336 /* hack: display INVEN_ARM slot as unavailable for 2-h weapons */
5337 else if (slot == INVEN_ARM && Players[Ind]->inventory[INVEN_WIELD].k_idx && (k_info[Players[Ind]->inventory[INVEN_WIELD].k_idx].flags4 & TR4_MUST2H)) {
5338 attr = TERM_L_DARK;
5339 //name = "(occupied)";
5340 name = "-";
5341 }
5342
5343
5344 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5345 connp2 = Conn[p_ptr2->conn];
5346 if (is_newer_than(&p_ptr2->version, 4, 5, 2, 0, 0, 0))
5347 Packet_printf(&connp2->c, "%c%c%c%hu%hd%c%c%hd%hd%c%I", PKT_EQUIP, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval,
5348 o_ptr->tval == TV_BOOK ? o_ptr->pval : 0, object_known_p(Ind, o_ptr) ? o_ptr->name1 : 0, uses_dir, name);
5349 else if (is_newer_than(&p_ptr2->version, 4, 4, 5, 10, 0, 0))
5350 Packet_printf(&connp2->c, "%c%c%c%hu%hd%c%c%hd%c%I", PKT_EQUIP, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval, o_ptr->tval == TV_BOOK ? o_ptr->pval : 0, uses_dir, name);
5351 else if (is_newer_than(&p_ptr2->version, 4, 4, 4, 2, 0, 0))
5352 Packet_printf(&connp2->c, "%c%c%c%hu%hd%c%c%hd%I", PKT_EQUIP, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval, o_ptr->tval == TV_BOOK ? o_ptr->pval : 0, name);
5353 else
5354 Packet_printf(&connp2->c, "%c%c%c%hu%hd%c%c%hd%s", PKT_EQUIP, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval, o_ptr->tval == TV_BOOK ? o_ptr->pval : 0, name);
5355 }
5356
5357 if (is_newer_than(&Players[Ind]->version, 4, 5, 2, 0, 0, 0))
5358 return Packet_printf(&connp->c, "%c%c%c%hu%hd%c%c%hd%hd%c%I", PKT_EQUIP, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval,
5359 o_ptr->tval == TV_BOOK ? o_ptr->pval : 0, object_known_p(Ind, o_ptr) ? o_ptr->name1 : 0, uses_dir, name);
5360 else if (is_newer_than(&Players[Ind]->version, 4, 4, 5, 10, 0, 0))
5361 return Packet_printf(&connp->c, "%c%c%c%hu%hd%c%c%hd%c%I", PKT_EQUIP, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval, o_ptr->tval == TV_BOOK ? o_ptr->pval : 0, uses_dir, name);
5362 else if (is_newer_than(&Players[Ind]->version, 4, 4, 4, 2, 0, 0))
5363 return Packet_printf(&connp->c, "%c%c%c%hu%hd%c%c%hd%I", PKT_EQUIP, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval, o_ptr->tval == TV_BOOK ? o_ptr->pval : 0, name);
5364 else
5365 return Packet_printf(&connp->c, "%c%c%c%hu%hd%c%c%hd%s", PKT_EQUIP, pos, attr, wgt, o_ptr->number, o_ptr->tval, o_ptr->sval, o_ptr->tval == TV_BOOK ? o_ptr->pval : 0, name);
5366 }
5367
5368 int Send_equip_availability(int Ind, int slot) {
5369 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5370 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
5371
5372 char pos = 'a' + slot - INVEN_WIELD;
5373 cptr name = "(nothing)";
5374 byte attr = TERM_WHITE;
5375
5376 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
5377 errno = 0;
5378 plog(format("Connection not ready for equip (%d.%d.%d)",
5379 Ind, connp->state, connp->id));
5380 return 0;
5381 }
5382
5383 if (!item_tester_hook_wear(Ind, slot)) {
5384 attr = TERM_L_DARK;
5385 name = "(unavailable)";
5386 }
5387 /* hack: 2-h weapon disables INVEN_ARM slot */
5388 else if (slot == INVEN_ARM && Players[Ind]->inventory[INVEN_WIELD].k_idx && (k_info[Players[Ind]->inventory[INVEN_WIELD].k_idx].flags4 & TR4_MUST2H)) {
5389 attr = TERM_L_DARK;
5390 //name = "(occupied)";
5391 name = "-";
5392 }
5393
5394 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5395 connp2 = Conn[p_ptr2->conn];
5396 if (is_newer_than(&p_ptr2->version, 4, 5, 2, 0, 0, 0))
5397 Packet_printf(&connp2->c, "%c%c%c%hu%hd%c%c%hd%hd%c%I", PKT_EQUIP, pos, attr, 0, 0, 0, 0, 0, 0, 0, name);
5398 else if (is_newer_than(&p_ptr2->version, 4, 4, 5, 10, 0, 0))
5399 Packet_printf(&connp2->c, "%c%c%c%hu%hd%c%c%hd%c%I", PKT_EQUIP, pos, attr, 0, 0, 0, 0, 0, 0, name);
5400 else if (is_newer_than(&p_ptr2->version, 4, 4, 4, 2, 0, 0))
5401 Packet_printf(&connp2->c, "%c%c%c%hu%hd%c%c%hd%I", PKT_EQUIP, pos, attr, 0, 0, 0, 0, 0, name);
5402 else
5403 Packet_printf(&connp2->c, "%c%c%c%hu%hd%c%c%hd%s", PKT_EQUIP, pos, attr, 0, 0, 0, 0, 0, name);
5404 }
5405
5406 if (is_newer_than(&Players[Ind]->version, 4, 5, 2, 0, 0, 0))
5407 return Packet_printf(&connp->c, "%c%c%c%hu%hd%c%c%hd%hd%c%I", PKT_EQUIP, pos, attr, 0, 0, 0, 0, 0, 0, 0, name);
5408 else if (is_newer_than(&Players[Ind]->version, 4, 4, 5, 10, 0, 0))
5409 return Packet_printf(&connp->c, "%c%c%c%hu%hd%c%c%hd%c%I", PKT_EQUIP, pos, attr, 0, 0, 0, 0, 0, 0, name);
5410 else if (is_newer_than(&Players[Ind]->version, 4, 4, 4, 2, 0, 0))
5411 return Packet_printf(&connp->c, "%c%c%c%hu%hd%c%c%hd%I", PKT_EQUIP, pos, attr, 0, 0, 0, 0, 0, name);
5412 else
5413 return Packet_printf(&connp->c, "%c%c%c%hu%hd%c%c%hd%s", PKT_EQUIP, pos, attr, 0, 0, 0, 0, 0, name);
5414 }
5415
5416 int Send_title(int Ind, cptr title) {
5417 connection_t *connp = Conn[Players[Ind]->conn];
5418
5419
5420 int Ind2;
5421 connection_t *connp2;
5422 player_type *p_ptr2 = NULL;
5423
5424 if (Players[Ind]->esp_link_flags & LINKF_VIEW_DEDICATED) return(0);
5425 if ((Ind2 = get_esp_link(Ind, LINKF_VIEW, &p_ptr2))) {
5426 connp2 = Conn[p_ptr2->conn];
5427 Packet_printf(&connp2->c, "%c%s", PKT_TITLE, title);
5428 }
5429
5430
5431 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
5432 errno = 0;
5433 plog(format("Connection not ready for title (%d.%d.%d)",
5434 Ind, connp->state, connp->id));
5435 return 0;
5436 }
5437 return Packet_printf(&connp->c, "%c%s", PKT_TITLE, title);
5438 }
5439
5440 int Send_extra_status(int Ind, cptr status)
5441 {
5442 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5443 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
5444
5445 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5446 {
5447 errno = 0;
5448 plog(format("Connection not ready for extra status (%d.%d.%d)",
5449 Ind, connp->state, connp->id));
5450 return 0;
5451 }
5452 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5453 connp2 = Conn[p_ptr2->conn];
5454 Packet_printf(&connp2->c, "%c%s", PKT_EXTRA_STATUS, status);
5455 }
5456 return Packet_printf(&connp->c, "%c%s", PKT_EXTRA_STATUS, status);
5457 }
5458
5459 int Send_depth(int Ind, struct worldpos *wpos) {
5460 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5461 player_type *p_ptr = Players[Ind], *p_ptr2 = NULL;
5462 bool ville = istown(wpos) && !isdungeontown(wpos); /* -> print name (TRUE) or a depth value (FALSE)? */
5463 cptr desc = "", loc_name = "";
5464 dungeon_type *d_ptr = NULL;
5465 int colour, colour_sector = TERM_L_GREEN, Ind2;
5466 cave_type **zcave;
5467 bool no_tele = FALSE;
5468 int dlev = getlevel(wpos);
5469 if ((zcave = getcave(&p_ptr->wpos))) no_tele = (zcave[p_ptr->py][p_ptr->px].info & CAVE_STCK) != 0;
5470
5471 if (Players[Ind]->esp_link_flags & LINKF_VIEW_DEDICATED) return(0);
5472
5473 if (wpos->wz > 0) d_ptr = wild_info[wpos->wy][wpos->wx].tower;
5474 else if (wpos->wz < 0) d_ptr = wild_info[wpos->wy][wpos->wx].dungeon;
5475 if (d_ptr) loc_name = get_dun_name(wpos->wx, wpos->wy, (wpos->wz > 0), d_ptr, 0, TRUE);
5476
5477 /* XXX this kinda thing should be done *before* calling Send_*
5478 * in general, of course.. - Jir - */
5479 if (ville) {
5480 int i;
5481 for (i = 0; i < numtowns; i++) {
5482 if (town[i].x == wpos->wx && town[i].y == wpos->wy) {
5483 desc = town_profile[town[i].type].name;
5484 break;
5485 }
5486 }
5487 }
5488
5489 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
5490 errno = 0;
5491 plog(format("Connection not ready for depth (%d.%d.%d)",
5492 Ind, connp->state, connp->id));
5493 return 0;
5494 }
5495
5496 /* Hack for Valinor */
5497 if (in_valinor(wpos)) {
5498 ville = TRUE;
5499 desc = "Valinor";
5500 }
5501 /* Hack for PvP Arena */
5502 else if (wpos->wx == WPOS_PVPARENA_X && wpos->wy == WPOS_PVPARENA_Y && wpos->wz == WPOS_PVPARENA_Z) {
5503 ville = TRUE;
5504 desc = "Arena";
5505 }
5506 #if 0
5507 /* Hack for Arena Monster Challenge */
5508 else if (wpos->wx == WPOS_ARENA_X && wpos->wy == WPOS_ARENA_Y && wpos->wz == WPOS_ARENA_Z) {
5509 ville = TRUE;
5510 desc = "Arena";
5511 }
5512 #endif
5513 #ifdef IRONDEEPDIVE_FIXED_TOWNS
5514 /* Hack for Ironman Deep Dive Challenge static dungeons */
5515 else if (is_fixed_irondeepdive_town(wpos, dlev)) {
5516 if (dlev == 40) {
5517 ville = TRUE;
5518 desc = "Menegroth";
5519 } else if (dlev == 80) {
5520 ville = TRUE;
5521 desc = "Nargothrond";
5522 }
5523 }
5524 #endif
5525 else if (sector00separation) {
5526 /* Hack for Dungeon Keeper */
5527 if (wpos->wx == WPOS_SECTOR00_X && wpos->wy == WPOS_SECTOR00_Y && wpos->wz == WPOS_SECTOR00_Z
5528 && (sector00flags2 & LF2_INDOORS)) {
5529 ville = TRUE;
5530 desc = "Old Dungeon";
5531 }
5532 /* Hack for Highlander */
5533 else if (wpos->wx == WPOS_HIGHLANDER_X && wpos->wy == WPOS_HIGHLANDER_Y && wpos->wz == WPOS_HIGHLANDER_Z) {
5534 ville = TRUE;
5535 desc = "Highlands";
5536 }
5537 /* Hack for Highlander (dungeon) */
5538 else if (wpos->wx == WPOS_HIGHLANDER_DUN_X && wpos->wy == WPOS_HIGHLANDER_DUN_Y && wpos->wz * WPOS_HIGHLANDER_DUN_Z > 0) {
5539 ville = TRUE;
5540 desc = "Underground";
5541 }
5542 }
5543
5544 if (desc[0]) loc_name = desc;
5545
5546 if (is_newer_than(&p_ptr->version, 4, 4, 1, 5, 0, 0)) {
5547 /* pending recall? */
5548 if (p_ptr->word_recall) colour = TERM_ORANGE;
5549 /* use as indicator for pvp_prevent_tele, actually */
5550 else if ((p_ptr->mode & MODE_PVP) && p_ptr->pvp_prevent_tele) colour = TERM_RED;
5551 /* use indicator asterisk instead in newer versions */
5552 else if ((!is_newer_than(&p_ptr->version, 4, 5, 6, 0, 0, 1) || ville) &&
5553 /* able to get extra level feeling on next floor? */
5554 TURNS_FOR_EXTRA_FEELING && p_ptr->turns_on_floor >= TURNS_FOR_EXTRA_FEELING)
5555 colour = TERM_L_BLUE;
5556 /* in a town? ignore town level */
5557 else if (ville) colour = TERM_WHITE;
5558 /* way too low to get good exp? */
5559 else if (dlev < det_req_level(p_ptr->lev) - 5) colour = TERM_L_DARK;
5560 /* too low to get 100% exp? */
5561 else if (dlev < det_req_level(p_ptr->lev)) colour = TERM_YELLOW;
5562 /* normal exp depth or deeper (default) */
5563 else colour = TERM_WHITE;
5564 } else {
5565 colour = p_ptr->word_recall;
5566 }
5567 /* able to get extra level feeling on next floor? */
5568 if (is_newer_than(&p_ptr->version, 4, 5, 6, 0, 0, 1) && !ville &&
5569 TURNS_FOR_EXTRA_FEELING && p_ptr->turns_on_floor >= TURNS_FOR_EXTRA_FEELING)
5570 desc = "*";
5571
5572
5573 if (is_newer_than(&p_ptr->version, 4, 4, 1, 6, 0, 0) && no_tele) {
5574 Send_cut(Ind, 0); /* hack: clear the field shared between cut and depth */
5575 colour_sector = TERM_L_DARK;
5576 }
5577
5578 if ((Ind2 = get_esp_link(Ind, LINKF_VIEW, &p_ptr2))) {
5579 connp2 = Conn[p_ptr2->conn];
5580 if (is_newer_than(&p_ptr2->version, 4, 5, 9, 0, 0, 0)) {
5581 if (no_tele) Send_cut(Ind2, 0); /* hack: clear the field shared between cut and depth */
5582 Packet_printf(&connp2->c, "%c%hu%hu%hu%c%c%c%s%s", PKT_DEPTH, wpos->wx, wpos->wy, wpos->wz, ville, colour, colour_sector, desc, loc_name);
5583 } else if (is_newer_than(&p_ptr2->version, 4, 4, 1, 6, 0, 0)) {
5584 if (no_tele) Send_cut(Ind2, 0); /* hack: clear the field shared between cut and depth */
5585 Packet_printf(&connp2->c, "%c%hu%hu%hu%c%c%c%s", PKT_DEPTH, wpos->wx, wpos->wy, wpos->wz, ville, colour, colour_sector, desc);
5586 } else {
5587 Packet_printf(&connp2->c, "%c%hu%hu%hu%c%hu%s", PKT_DEPTH, wpos->wx, wpos->wy, wpos->wz, ville, colour, desc);
5588 }
5589 }
5590
5591 if (is_newer_than(&p_ptr->version, 4, 5, 9, 0, 0, 0)) {
5592 return Packet_printf(&connp->c, "%c%hu%hu%hu%c%c%c%s%s", PKT_DEPTH, wpos->wx, wpos->wy, wpos->wz, ville, colour, colour_sector, desc, loc_name);
5593 } else if (is_newer_than(&p_ptr->version, 4, 4, 1, 6, 0, 0)) {
5594 return Packet_printf(&connp->c, "%c%hu%hu%hu%c%c%c%s", PKT_DEPTH, wpos->wx, wpos->wy, wpos->wz, ville, colour, colour_sector, desc);
5595 } else {
5596 return Packet_printf(&connp->c, "%c%hu%hu%hu%c%hu%s", PKT_DEPTH, wpos->wx, wpos->wy, wpos->wz, ville, colour, desc);
5597 }
5598 }
5599
5600 /* (added for Valinor, but now just unused except for debugging purpose: /testdisplay in slash.c)
5601 This allows determining whether we're in a (fake) 'town' or not, and also
5602 the exact (fake) town's name that will be displayed to the player. */
5603 int Send_depth_hack(int Ind, struct worldpos *wpos, bool town, cptr desc)
5604 {
5605 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5606 player_type *p_ptr = Players[Ind], *p_ptr2 = NULL;
5607 int colour, colour2, colour_sector = TERM_L_GREEN, colour2_sector = TERM_L_GREEN, Ind2;
5608 cave_type **zcave;
5609 bool no_tele = FALSE;
5610 if ((zcave = getcave(&p_ptr->wpos))) no_tele = (zcave[p_ptr->py][p_ptr->px].info & CAVE_STCK) != 0;
5611
5612 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5613 {
5614 errno = 0;
5615 plog(format("Connection not ready for depth (%d.%d.%d)",
5616 Ind, connp->state, connp->id));
5617 return 0;
5618 }
5619 if (Players[Ind]->esp_link_flags & LINKF_VIEW_DEDICATED) return(0);
5620 if ((Ind2 = get_esp_link(Ind, LINKF_VIEW, &p_ptr2))) {
5621 connp2 = Conn[p_ptr2->conn];
5622
5623 if (is_newer_than(&p_ptr2->version, 4, 4, 1, 5, 0, 0)) {
5624 /* pending recall? */
5625 if (p_ptr2->word_recall) colour2 = TERM_ORANGE;
5626 /* able to get extra level feeling on next floor? */
5627 else if (TURNS_FOR_EXTRA_FEELING && (p_ptr2->turns_on_floor >= TURNS_FOR_EXTRA_FEELING)) colour2 = TERM_L_BLUE;
5628 /* in a town? ignore town level */
5629 else if (town) colour2 = TERM_WHITE;
5630 /* way too low to get good exp? */
5631 else if (getlevel(wpos) < det_req_level(p_ptr2->lev) - 5) colour2 = TERM_L_DARK;
5632 /* too low to get 100% exp? */
5633 else if (getlevel(wpos) < det_req_level(p_ptr2->lev)) colour2 = TERM_YELLOW;
5634 /* normal exp depth or deeper (default) */
5635 else colour2 = TERM_WHITE;
5636 } else {
5637 colour2 = p_ptr2->word_recall;
5638 }
5639
5640 if (is_newer_than(&p_ptr2->version, 4, 4, 1, 6, 0, 0)) {
5641 if (no_tele) {
5642 Send_cut(Ind2, 0); /* hack: clear the field shared between cut and depth */
5643 colour2_sector = TERM_L_DARK;
5644 }
5645 Packet_printf(&connp2->c, "%c%hu%hu%hu%c%c%c%s", PKT_DEPTH, wpos->wx, wpos->wy, wpos->wz, town, colour2, colour2_sector, desc);
5646 } else {
5647 Packet_printf(&connp2->c, "%c%hu%hu%hu%c%hu%s", PKT_DEPTH, wpos->wx, wpos->wy, wpos->wz, town, colour2, desc);
5648 }
5649 }
5650
5651 if (is_newer_than(&p_ptr->version, 4, 4, 1, 5, 0, 0)) {
5652 /* pending recall? */
5653 if (p_ptr->word_recall) colour = TERM_ORANGE;
5654 /* able to get extra level feeling on next floor? */
5655 else if (TURNS_FOR_EXTRA_FEELING && (p_ptr->turns_on_floor >= TURNS_FOR_EXTRA_FEELING)) colour = TERM_L_BLUE;
5656 /* in a town? ignore town level */
5657 else if (town) colour = TERM_WHITE;
5658 /* way too low to get good exp? */
5659 else if (getlevel(wpos) < det_req_level(p_ptr->lev) - 5) colour = TERM_L_DARK;
5660 /* too low to get 100% exp? */
5661 else if (getlevel(wpos) < det_req_level(p_ptr->lev)) colour = TERM_YELLOW;
5662 /* normal exp depth or deeper (default) */
5663 else colour = TERM_WHITE;
5664 } else {
5665 colour = p_ptr->word_recall;
5666 }
5667
5668 if (is_newer_than(&p_ptr->version, 4, 4, 1, 6, 0, 0)) {
5669 if (no_tele) {
5670 Send_cut(Ind, 0); /* hack: clear the field shared between cut and depth */
5671 colour_sector = TERM_L_DARK;
5672 }
5673 return Packet_printf(&connp->c, "%c%hu%hu%hu%c%c%c%s", PKT_DEPTH, wpos->wx, wpos->wy, wpos->wz, town, colour, colour_sector, desc);
5674 } else {
5675 return Packet_printf(&connp->c, "%c%hu%hu%hu%c%hu%s", PKT_DEPTH, wpos->wx, wpos->wy, wpos->wz, town, p_ptr->word_recall, desc);
5676 }
5677 }
5678
5679 int Send_food(int Ind, int food)
5680 {
5681 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5682 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
5683
5684 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5685 {
5686 errno = 0;
5687 plog(format("Connection not ready for food (%d.%d.%d)",
5688 Ind, connp->state, connp->id));
5689 return 0;
5690 }
5691 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5692 connp2 = Conn[p_ptr2->conn];
5693 Packet_printf(&connp2->c, "%c%hu", PKT_FOOD, food);
5694 }
5695 return Packet_printf(&connp->c, "%c%hu", PKT_FOOD, food);
5696 }
5697
5698 int Send_blind(int Ind, bool blind)
5699 {
5700 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5701 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
5702
5703 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5704 {
5705 errno = 0;
5706 plog(format("Connection not ready for blind (%d.%d.%d)",
5707 Ind, connp->state, connp->id));
5708 return 0;
5709 }
5710 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5711 connp2 = Conn[p_ptr2->conn];
5712 Packet_printf(&connp2->c, "%c%c", PKT_BLIND, blind);
5713 }
5714 return Packet_printf(&connp->c, "%c%c", PKT_BLIND, blind);
5715 }
5716
5717 int Send_confused(int Ind, bool confused)
5718 {
5719 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5720 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
5721
5722 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5723 {
5724 errno = 0;
5725 plog(format("Connection not ready for confusion (%d.%d.%d)",
5726 Ind, connp->state, connp->id));
5727 return 0;
5728 }
5729 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5730 connp2 = Conn[p_ptr2->conn];
5731 Packet_printf(&connp2->c, "%c%c", PKT_CONFUSED, confused);
5732 }
5733 return Packet_printf(&connp->c, "%c%c", PKT_CONFUSED, confused);
5734 }
5735
5736 int Send_fear(int Ind, bool fear)
5737 {
5738 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5739 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
5740
5741 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5742 {
5743 errno = 0;
5744 plog(format("Connection not ready for fear (%d.%d.%d)",
5745 Ind, connp->state, connp->id));
5746 return 0;
5747 }
5748 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5749 connp2 = Conn[p_ptr2->conn];
5750 Packet_printf(&connp2->c, "%c%c", PKT_FEAR, fear);
5751 }
5752 return Packet_printf(&connp->c, "%c%c", PKT_FEAR, fear);
5753 }
5754
5755 int Send_poison(int Ind, bool poisoned)
5756 {
5757 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5758 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
5759
5760 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5761 {
5762 errno = 0;
5763 plog(format("Connection not ready for poison (%d.%d.%d)",
5764 Ind, connp->state, connp->id));
5765 return 0;
5766 }
5767 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5768 connp2 = Conn[p_ptr2->conn];
5769 Packet_printf(&connp2->c, "%c%c", PKT_POISON, poisoned);
5770 }
5771 return Packet_printf(&connp->c, "%c%c", PKT_POISON, poisoned);
5772 }
5773
5774 int Send_state(int Ind, bool paralyzed, bool searching, bool resting)
5775 {
5776 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5777 player_type *p_ptr = Players[Ind], *p_ptr2 = NULL;
5778
5779 /* give 'knocked out' priority over paralysis;
5780 give stun priority over search/rest */
5781 if (is_newer_than(&connp->version, 4, 4, 2, 0, 0, 0) &&
5782 (p_ptr->stun > 100 || (!paralyzed && p_ptr->stun))) return 0;
5783
5784 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5785 {
5786 errno = 0;
5787 plog(format("Connection not ready for state (%d.%d.%d)",
5788 Ind, connp->state, connp->id));
5789 return 0;
5790 }
5791 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5792 connp2 = Conn[p_ptr2->conn];
5793 Packet_printf(&connp2->c, "%c%hu%hu%hu", PKT_STATE, paralyzed, searching, resting);
5794 }
5795 return Packet_printf(&connp->c, "%c%hu%hu%hu", PKT_STATE, paralyzed, searching, resting);
5796 }
5797
5798 int Send_speed(int Ind, int speed)
5799 {
5800 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5801 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
5802
5803 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5804 {
5805 errno = 0;
5806 plog(format("Connection not ready for speed (%d.%d.%d)",
5807 Ind, connp->state, connp->id));
5808 return 0;
5809 }
5810 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5811 connp2 = Conn[p_ptr2->conn];
5812 Packet_printf(&connp2->c, "%c%hd", PKT_SPEED, speed);
5813 }
5814 return Packet_printf(&connp->c, "%c%hd", PKT_SPEED, speed);
5815 }
5816
5817 int Send_study(int Ind, bool study)
5818 {
5819 connection_t *connp = Conn[Players[Ind]->conn];
5820
5821 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5822 {
5823 errno = 0;
5824 plog(format("Connection not ready for study (%d.%d.%d)",
5825 Ind, connp->state, connp->id));
5826 return 0;
5827 }
5828 return Packet_printf(&connp->c, "%c%c", PKT_STUDY, study);
5829 }
5830
5831 int Send_bpr(int Ind, byte bpr, byte attr)
5832 {
5833 int Ind2;
5834 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5835 player_type *p_ptr2 = NULL;
5836
5837 if (Players[Ind]->esp_link_flags & LINKF_VIEW_DEDICATED) return(0);
5838 if ((Ind2 = get_esp_link(Ind, LINKF_VIEW, &p_ptr2))) {
5839 connp2 = Conn[p_ptr2->conn];
5840 Packet_printf(&connp2->c, "%c%c%c", PKT_BPR, bpr, attr);
5841 }
5842
5843 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
5844 errno = 0;
5845 plog(format("Connection not ready for bpr (%d.%d.%d)",
5846 Ind, connp->state, connp->id));
5847 return 0;
5848 }
5849 return Packet_printf(&connp->c, "%c%c%c", PKT_BPR, bpr, attr);
5850 }
5851
5852 int Send_cut(int Ind, int cut)
5853 {
5854 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5855 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
5856
5857 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5858 {
5859 errno = 0;
5860 plog(format("Connection not ready for cut (%d.%d.%d)",
5861 Ind, connp->state, connp->id));
5862 return 0;
5863 }
5864
5865 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5866 connp2 = Conn[p_ptr2->conn];
5867 Packet_printf(&connp2->c, "%c%hu", PKT_CUT, cut);
5868 }
5869 return Packet_printf(&connp->c, "%c%hu", PKT_CUT, cut);
5870 }
5871
5872 int Send_stun(int Ind, int stun)
5873 {
5874 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5875 player_type *p_ptr = Players[Ind], *p_ptr2 = NULL;
5876
5877 /* give 'knocked out' priority over paralysis */
5878 if (is_newer_than(&connp->version, 4, 4, 2, 0, 0, 0) &&
5879 p_ptr->paralyzed && p_ptr->stun <= 100) return 0;
5880
5881 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5882 {
5883 errno = 0;
5884 plog(format("Connection not ready for stun (%d.%d.%d)",
5885 Ind, connp->state, connp->id));
5886 return 0;
5887 }
5888 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5889 connp2 = Conn[p_ptr2->conn];
5890 Packet_printf(&connp2->c, "%c%hu", PKT_STUN, stun);
5891 }
5892 return Packet_printf(&connp->c, "%c%hu", PKT_STUN, stun);
5893 }
5894
5895 int Send_direction(int Ind)
5896 {
5897 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
5898 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
5899
5900 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5901 {
5902 errno = 0;
5903 plog(format("Connection not ready for direction (%d.%d.%d)",
5904 Ind, connp->state, connp->id));
5905 return FALSE;
5906 }
5907 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
5908 connp2 = Conn[p_ptr2->conn];
5909 return Packet_printf(&connp2->c, "%c", PKT_DIRECTION);
5910 }
5911 return Packet_printf(&connp->c, "%c", PKT_DIRECTION);
5912 }
5913
5914 static bool hack_message = FALSE;
5915
5916 int Send_message(int Ind, cptr msg)
5917 {
5918 connection_t *connp = Conn[Players[Ind]->conn];
5919 player_type *p_ptr = Players[Ind];
5920 char buf[80 +80]; // for +80 see below, at 'Clip end of msg'..
5921
5922 if (msg == NULL)
5923 return 1;
5924
5925 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5926 {
5927 errno = 0;
5928 plog(format("Connection not ready for message (%d.%d.%d)",
5929 Ind, connp->state, connp->id));
5930 return 0;
5931 }
5932
5933 /* Clip end of msg if too long */
5934 // Taking this out for now, since it's ONLY called from msg_print in util.c,
5935 // which already performs checks - C. Blue
5936 // (otherwise, lines with colour codes might be crippled here :| )
5937 // strncpy(buf, msg, 78);
5938 // buf[78] = '\0';
5939 strncpy(buf, msg, 158);
5940 buf[158] = '\0';
5941
5942 if ((!hack_message) && p_ptr->esp_link_type && p_ptr->esp_link && (p_ptr->esp_link_flags & LINKF_MISC))
5943 {
5944 int Ind2 = find_player(p_ptr->esp_link);
5945 player_type *p_ptr2;
5946 connection_t *connp2;
5947
5948 if (!Ind2) {
5949 hack_message = TRUE;
5950 end_mind(Ind, TRUE);
5951 hack_message = FALSE;
5952 }
5953 else
5954 {
5955 p_ptr2 = Players[Ind2];
5956 connp2 = Conn[p_ptr2->conn];
5957
5958 if (!BIT(connp2->state, CONN_PLAYING | CONN_READY))
5959 {
5960 plog(format("Connection not ready for message (%d.%d.%d)",
5961 Ind, connp2->state, connp2->id));
5962 }
5963 else Packet_printf(&connp2->c, "%c%S", PKT_MESSAGE, buf);
5964 }
5965 }
5966 return Packet_printf(&connp->c, "%c%S", PKT_MESSAGE, buf);
5967 }
5968
5969 int Send_char(int Ind, int x, int y, byte a, char c)
5970 {
5971 player_type *p_ptr = Players[Ind], *p_ptr2 = NULL;
5972
5973 if (!BIT(Conn[Players[Ind]->conn]->state, CONN_PLAYING | CONN_READY))
5974 return 0;
5975
5976 if (p_ptr->esp_link_flags & LINKF_VIEW_DEDICATED) return 0;
5977
5978 if (get_esp_link(Ind, LINKF_VIEW, &p_ptr2)) {
5979 if (BIT(Conn[p_ptr2->conn]->state, CONN_PLAYING | CONN_READY))
5980 Packet_printf(&Conn[p_ptr2->conn]->c, "%c%c%c%c%c", PKT_CHAR, x, y, a, c);
5981 }
5982
5983 return Packet_printf(&Conn[p_ptr->conn]->c, "%c%c%c%c%c", PKT_CHAR, x, y, a, c);
5984 }
5985
5986 int Send_spell_info(int Ind, int realm, int book, int i, cptr out_val)
5987 {
5988 connection_t *connp = Conn[Players[Ind]->conn];
5989 player_type *p_ptr = Players[Ind];
5990
5991 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
5992 {
5993 errno = 0;
5994 plog(format("Connection not ready for spell info (%d.%d.%d)",
5995 Ind, connp->state, connp->id));
5996 return 0;
5997 }
5998 return Packet_printf(&connp->c, "%c%d%d%d%hu%hu%hu%s", PKT_SPELL_INFO, p_ptr->innate_spells[0], p_ptr->innate_spells[1], p_ptr->innate_spells[2], realm, book, i, out_val);
5999 }
6000
6001 /* Implementing fighting/shooting techniques, but maybe using a lua 'school' file would be better instead - C. Blue */
6002 int Send_technique_info(int Ind)
6003 {
6004 #ifndef ENABLE_TECHNIQUES
6005 return(0); /* disabled until client can handle it */
6006 #endif
6007 connection_t *connp = Conn[Players[Ind]->conn];
6008 if (!is_newer_than(&connp->version, 4, 4, 1, 2, 0, 0)) return(0);
6009
6010 player_type *p_ptr = Players[Ind];
6011
6012 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
6013 {
6014 errno = 0;
6015 plog(format("Connection not ready for techniques info (%d.%d.%d)",
6016 Ind, connp->state, connp->id));
6017 return 0;
6018 }
6019 return Packet_printf(&connp->c, "%c%d%d", PKT_TECHNIQUE_INFO, p_ptr->melee_techniques, p_ptr->ranged_techniques);
6020 }
6021
6022 int Send_item_request(int Ind, signed char tester_hook) { //paranoia @ 'signed' char =-p
6023 connection_t *connp = Conn[Players[Ind]->conn];
6024 #if 0
6025 connection_t *connp2;
6026 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
6027 #endif
6028
6029 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
6030 errno = 0;
6031 plog(format("Connection not ready for item request (%d.%d.%d)",
6032 Ind, connp->state, connp->id));
6033 return 0;
6034 }
6035
6036 #if 0 /* what is this needed for, actually? */
6037 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
6038 connp2 = Conn[p_ptr2->conn];
6039 if (is_newer_than(&p_ptr2->version, 4, 5, 2, 0, 0, 0))
6040 Packet_printf(&connp2->c, "%c%c", PKT_ITEM, tester_hook);
6041 else
6042 Packet_printf(&connp2->c, "%c", PKT_ITEM);
6043 }
6044 #endif
6045
6046 if (is_newer_than(&Players[Ind]->version, 4, 5, 2, 0, 0, 0))
6047 return Packet_printf(&connp->c, "%c%c", PKT_ITEM, tester_hook);
6048 else
6049 return Packet_printf(&connp->c, "%c", PKT_ITEM);
6050 }
6051
6052 /* for DISCRETE_SPELL_SYSTEM: DSS_EXPANDED_SCROLLS */
6053 int Send_spell_request(int Ind, int item) {
6054 connection_t *connp = Conn[Players[Ind]->conn];
6055
6056 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
6057 errno = 0;
6058 plog(format("Connection not ready for spell request (%d.%d.%d)",
6059 Ind, connp->state, connp->id));
6060 return 0;
6061 }
6062
6063 return Packet_printf(&connp->c, "%c%d", PKT_SPELL, item);
6064 }
6065
6066 int Send_flush(int Ind)
6067 {
6068 connection_t *connp = Conn[Players[Ind]->conn];
6069 //player_type *p_ptr = Players[Ind];
6070
6071 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
6072 {
6073 errno = 0;
6074 plog(format("Connection not ready for flush (%d.%d.%d)",
6075 Ind, connp->state, connp->id));
6076 return 0;
6077 }
6078 return Packet_printf(&connp->c, "%c", PKT_FLUSH);
6079 }
6080
6081 /*
6082 * As an attempt to lower bandwidth requirements, each line is run length
6083 * encoded. Non-encoded grids are sent as normal, but if a grid is
6084 * repeated at least twice, then bit 0x40 of the attribute is set, and
6085 * the next byte contains the number of repetitions of the previous grid.
6086 */
6087 int Send_line_info(int Ind, int y)
6088 {
6089 player_type *p_ptr = Players[Ind], *p_ptr2 = NULL;
6090 connection_t *connp = Conn[p_ptr->conn];
6091 int x, x1, n;
6092 char c;
6093 byte a;
6094 int Ind2 = 0;
6095 #ifdef EXTENDED_TERM_COLOURS
6096 bool old_colours = is_older_than(&p_ptr->version, 4, 5, 1, 2, 0, 0);
6097 int a_c;
6098 #endif
6099
6100 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
6101 {
6102 errno = 0;
6103 plog(format("Connection not ready for line info (%d.%d.%d)",
6104 Ind, connp->state, connp->id));
6105 return 0;
6106 }
6107
6108 if (p_ptr->esp_link_flags & LINKF_VIEW_DEDICATED) return 0; /* bad hack for shortcut */
6109 // if (p_ptr->esp_link && p_ptr->esp_link_type && (p_ptr->esp_link_flags & LINKF_VIEW_DEDICATED)) return 0;
6110
6111 Ind2 = get_esp_link(Ind, LINKF_VIEW, &p_ptr2);
6112
6113 /* Put a header on the packet */
6114 Packet_printf(&connp->c, "%c%hd", PKT_LINE_INFO, y);
6115 if (Ind2) Packet_printf(&(Conn[p_ptr2->conn]->c), "%c%hd", PKT_LINE_INFO, y);
6116
6117 /* Each column */
6118 for (x = 0; x < 80; x++)
6119 {
6120 /* Obtain the char/attr pair */
6121 c = p_ptr->scr_info[y][x].c;
6122 a = p_ptr->scr_info[y][x].a;
6123
6124 #ifdef EXTENDED_TERM_COLOURS
6125 if (old_colours) {
6126 a_c = a & ~(TERM_BNW | TERM_PVP);
6127 if (a_c == 29 || a_c == 30 || a_c >= 32)
6128 a = TERM_WHITE; /* use white to indicate that client needs updating */
6129 }
6130 #endif
6131
6132 /* Start looking here */
6133 x1 = x + 1;
6134
6135 /* Start with count of 1 */
6136 n = 1;
6137
6138 /* Count repetitions of this grid */
6139 while (p_ptr->scr_info[y][x1].c == c &&
6140 p_ptr->scr_info[y][x1].a == a && x1 < 80) //TODO (EXTENDED_TERM_COLOURS): the scr_info.a should also be changed to TERM_WHITE if client is old, but it doesn't matter.
6141 {
6142 /* Increment count and column */
6143 n++;
6144 x1++;
6145 }
6146
6147 /* RLE if there at least 2 similar grids in a row */
6148 if (n >= 2)
6149 {
6150 /* 4.4.3.1 clients support new RLE */
6151 if (is_newer_than(&connp->version, 4, 4, 3, 0, 0, 5))
6152 {
6153 /* New RLE */
6154 Packet_printf(&connp->c, "%c%c%c%c", c, 0xFF, a, n);
6155 }
6156 else
6157 {
6158 /* Old RLE */
6159 Packet_printf(&connp->c, "%c%c%c", c, a | 0x40, n);
6160 }
6161
6162 if (Ind2)
6163 {
6164 /* 4.4.3.1 clients support new RLE */
6165 if (is_newer_than(&Conn[p_ptr2->conn]->version, 4, 4, 3, 0, 0, 5))
6166 {
6167 /* New RLE */
6168 Packet_printf(&Conn[p_ptr2->conn]->c, "%c%c%c%c", c, 0xFF, a, n);
6169 }
6170 else {
6171 /* Old RLE */
6172 Packet_printf(&Conn[p_ptr2->conn]->c, "%c%c%c", c, a | 0x40, n);
6173 }
6174 }
6175
6176 /* Start again after the run */
6177 x = x1 - 1;
6178 }
6179 else
6180 {
6181 /* Normal, single grid */
6182 if (!is_newer_than(&connp->version, 4, 4, 3, 0, 0, 5)) {
6183 /* Remove 0x40 (TERM_PVP) if the client is old */
6184 Packet_printf(&connp->c, "%c%c", c, a & ~0xC0);
6185 }
6186 else
6187 {
6188 if (a == 0xFF)
6189 {
6190 /* Use RLE format as an escape sequence for 0xFF as attr */
6191 Packet_printf(&connp->c, "%c%c%c%c", c, 0xFF, a, 1);
6192 }
6193 else
6194 {
6195 /* Normal output */
6196 Packet_printf(&connp->c, "%c%c", c, a);
6197 }
6198 }
6199
6200 if (Ind2)
6201 {
6202 if (!is_newer_than(&Conn[p_ptr2->conn]->version, 4, 4, 3, 0, 0, 5)) {
6203 /* Remove 0x40 (TERM_PVP) if the client is old */
6204 Packet_printf(&Conn[p_ptr2->conn]->c, "%c%c", c, a & ~0xC0);
6205 }
6206 else
6207 {
6208 if (a == 0xFF)
6209 {
6210 /* Use RLE format as an escape sequence for 0xFF as attr */
6211 Packet_printf(&Conn[p_ptr2->conn]->c, "%c%c%c%c", c, 0xFF, a, 1);
6212 }
6213 else
6214 {
6215 /* Normal output */
6216 Packet_printf(&Conn[p_ptr2->conn]->c, "%c%c", c, a);
6217 }
6218 }
6219 }
6220 }
6221 }
6222
6223 /* Hack -- Prevent buffer overruns by flushing after each line sent */
6224 /* Send_reliable(Players[Ind]->conn); */
6225
6226 return 1;
6227 }
6228
6229 int Send_mini_map(int Ind, int y, byte *sa, char *sc)
6230 {
6231 player_type *p_ptr = Players[Ind];
6232 connection_t *connp = Conn[p_ptr->conn];
6233 int x, x1, n;
6234 char c;
6235 byte a;
6236
6237 int Ind2 = 0;
6238 player_type *p_ptr2 = NULL;
6239 connection_t *connp2 = NULL;
6240
6241 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
6242 {
6243 errno = 0;
6244 plog(format("Connection not ready for minimap (%d.%d.%d)",
6245 Ind, connp->state, connp->id));
6246 return 0;
6247 }
6248
6249 if (p_ptr->esp_link_flags & LINKF_VIEW_DEDICATED) return 0;
6250
6251 /* Sending this packet to a mind-linked person is bad - mikaelh */
6252 #if 0
6253 if ((Ind2 = get_esp_link(Ind, LINKF_VIEW, &p_ptr2)))
6254 connp2 = Conn[p_ptr2->conn];
6255 #endif
6256
6257 /* Packet header */
6258 Packet_printf(&connp->c, "%c%hd", PKT_MINI_MAP, y);
6259 if (Ind2) Packet_printf(&connp2->c, "%c%hd", PKT_MINI_MAP, y);
6260
6261 /* Each column */
6262 for (x = 0; x < 80; x++)
6263 {
6264 /* Obtain the char/attr pair */
6265 c = sc[x];
6266 a = sa[x];
6267
6268 /* Start looking here */
6269 x1 = x + 1;
6270
6271 /* Start with count of 1 */
6272 n = 1;
6273
6274 /* Count repetitions of this grid */
6275 while (x1 < 80 && sc[x1] == c && sa[x1] == a)
6276 {
6277 /* Increment count and column */
6278 n++;
6279 x1++;
6280 }
6281
6282 /* RLE if there at least 2 similar grids in a row */
6283 if (n >= 2)
6284 {
6285 /* 4.4.3.1 clients support new RLE */
6286 if (is_newer_than(&connp->version, 4, 4, 3, 0, 0, 5))
6287 {
6288 /* New RLE */
6289 Packet_printf(&connp->c, "%c%c%c%c", c, 0xFF, a, n);
6290 }
6291 else
6292 {
6293 /* Old RLE */
6294 Packet_printf(&connp->c, "%c%c%c", c, a | 0x40, n);
6295 }
6296
6297 if (Ind2)
6298 {
6299 /* 4.4.3.1 clients support new RLE */
6300 if (is_newer_than(&Conn[p_ptr2->conn]->version, 4, 4, 3, 0, 0, 5))
6301 {
6302 /* New RLE */
6303 Packet_printf(&Conn[p_ptr2->conn]->c, "%c%c%c%c", c, 0xFF, a, n);
6304 }
6305 else {
6306 /* Old RLE */
6307 Packet_printf(&Conn[p_ptr2->conn]->c, "%c%c%c", c, a | 0x40, n);
6308 }
6309 }
6310
6311 /* Start again after the run */
6312 x = x1 - 1;
6313 }
6314 else
6315 {
6316 /* Normal, single grid */
6317 if (!is_newer_than(&connp->version, 4, 4, 3, 0, 0, 5)) {
6318 /* Remove 0x40 (TERM_PVP) if the client is old */
6319 Packet_printf(&connp->c, "%c%c", c, a & ~0xD0);
6320 }
6321 else
6322 {
6323 if (a == 0xFF)
6324 {
6325 /* Use RLE format as an escape sequence for 0xFF as attr */
6326 Packet_printf(&connp->c, "%c%c%c%c", c, 0xFF, a, 1);
6327 }
6328 else
6329 {
6330 /* Normal output */
6331 Packet_printf(&connp->c, "%c%c", c, a);
6332 }
6333 }
6334
6335 if (Ind2)
6336 {
6337 if (!is_newer_than(&Conn[p_ptr2->conn]->version, 4, 4, 3, 0, 0, 5)) {
6338 /* Remove 0x40 (TERM_PVP) if the client is old */
6339 Packet_printf(&Conn[p_ptr2->conn]->c, "%c%c", c, a & ~0xD0);
6340 }
6341 else
6342 {
6343 if (a == 0xFF)
6344 {
6345 /* Use RLE format as an escape sequence for 0xFF as attr */
6346 Packet_printf(&Conn[p_ptr2->conn]->c, "%c%c%c%c", c, 0xFF, a, 1);
6347 }
6348 else
6349 {
6350 /* Normal output */
6351 Packet_printf(&Conn[p_ptr2->conn]->c, "%c%c", c, a);
6352 }
6353 }
6354 }
6355 }
6356 }
6357
6358 /* Hack -- Prevent buffer overruns by flushing after each line sent */
6359 /* Send_reliable(Players[Ind]->conn); */
6360
6361 return 1;
6362 }
6363
6364 int Send_mini_map_pos(int Ind, int x, int y, byte a, char c) {
6365 player_type *p_ptr = Players[Ind];
6366 connection_t *connp = Conn[p_ptr->conn];
6367 short int xs = (short int)x, ys = (short int)y; //note: this isn't required, can just use x and y instead
6368
6369 //int Ind2 = 0;
6370 //player_type *p_ptr2 = NULL;
6371 //connection_t *connp2 = NULL;
6372
6373 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
6374 errno = 0;
6375 plog(format("Connection not ready for minimap_pos (%d.%d.%d)",
6376 Ind, connp->state, connp->id));
6377 return 0;
6378 }
6379
6380 if (p_ptr->esp_link_flags & LINKF_VIEW_DEDICATED) return 0;
6381
6382 /* Sending this packet to a mind-linked person is bad - mikaelh */
6383 #if 0
6384 if ((Ind2 = get_esp_link(Ind, LINKF_VIEW, &p_ptr2)))
6385 connp2 = Conn[p_ptr2->conn];
6386 #endif
6387
6388 /* Packet header */
6389 if (is_newer_than(&p_ptr->version, 4, 5, 5, 0, 0, 0)) Packet_printf(&connp->c, "%c%hd%hd%c%c", PKT_MINI_MAP_POS, xs, ys, a, c);
6390 //if (Ind2 && is_newer_than(&p_ptr2->version, 4, 5, 5, 0, 0, 0)) Packet_printf(&connp2->c, "%c%hd%hd%c%c", PKT_MINI_MAP_POS, xs, ys, a, c);
6391
6392 return 1;
6393 }
6394
6395 //int Send_store(int Ind, char pos, byte attr, int wgt, int number, int price, cptr name)
6396 int Send_store(int Ind, char pos, byte attr, int wgt, int number, int price, cptr name, char tval, char sval, s16b pval)
6397 {
6398 connection_t *connp = Conn[Players[Ind]->conn];
6399 #ifdef MINDLINK_STORE
6400 connection_t *connp2;
6401 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
6402
6403 #endif
6404
6405 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
6406 {
6407 errno = 0;
6408 plog(format("Connection not ready for store item (%d.%d.%d)",
6409 Ind, connp->state, connp->id));
6410 return 0;
6411 }
6412
6413 /* don't segfault old clients which use STORE_INVEN_MAX = 48 */
6414 if (pos >= 48 && is_older_than(&Players[Ind]->version, 4, 4, 9, 0, 0, 0)) return 0;
6415
6416 /* Hack -- send pval only if it's School book */
6417 if (tval != TV_BOOK) pval = 0;
6418
6419 #ifdef MINDLINK_STORE
6420 if (get_esp_link(Ind, LINKF_VIEW, &p_ptr2)) {
6421 connp2 = Conn[p_ptr2->conn];
6422 if (is_newer_than(&p_ptr2->version, 4, 4, 7, 0, 0, 0))
6423 Packet_printf(&connp2->c, "%c%c%c%hd%hd%d%S%c%c%hd", PKT_STORE, pos, attr, wgt, number, price, name, tval, sval, pval);
6424 else
6425 Packet_printf(&connp2->c, "%c%c%c%hd%hd%d%s%c%c%hd", PKT_STORE, pos, attr, wgt, number, price, name, tval, sval, pval);
6426 }
6427 #endif
6428
6429 if (is_newer_than(&Players[Ind]->version, 4, 4, 7, 0, 0, 0))
6430 return Packet_printf(&connp->c, "%c%c%c%hd%hd%d%S%c%c%hd", PKT_STORE, pos, attr, wgt, number, price, name, tval, sval, pval);
6431 else
6432 return Packet_printf(&connp->c, "%c%c%c%hd%hd%d%s%c%c%hd", PKT_STORE, pos, attr, wgt, number, price, name, tval, sval, pval);
6433 }
6434
6435 /* Send_store() variant for custom spellbooks */
6436 int Send_store_wide(int Ind, char pos, byte attr, int wgt, int number, int price, cptr name, char tval, char sval, s16b pval,
6437 byte xtra1, byte xtra2, byte xtra3, byte xtra4, byte xtra5, byte xtra6, byte xtra7, byte xtra8, byte xtra9)
6438 {
6439 connection_t *connp = Conn[Players[Ind]->conn];
6440 #ifdef MINDLINK_STORE
6441 connection_t *connp2;
6442 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
6443
6444 #endif
6445
6446 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
6447 {
6448 errno = 0;
6449 plog(format("Connection not ready for store item (%d.%d.%d)",
6450 Ind, connp->state, connp->id));
6451 return 0;
6452 }
6453
6454 /* don't segfault old clients which use STORE_INVEN_MAX = 48 */
6455 if (pos >= 48 && is_older_than(&Players[Ind]->version, 4, 4, 9, 0, 0, 0)) return 0;
6456
6457 /* Hack -- send pval only if it's School book */
6458 if (tval != TV_BOOK) pval = 0;
6459
6460 #ifdef MINDLINK_STORE
6461 if (get_esp_link(Ind, LINKF_VIEW, &p_ptr2)) {
6462 connp2 = Conn[p_ptr2->conn];
6463 if (is_newer_than(&p_ptr2->version, 4, 4, 7, 0, 0, 0))
6464 Packet_printf(&connp2->c, "%c%c%c%hd%hd%d%S%c%c%hd%c%c%c%c%c%c%c%c%c", PKT_STORE_WIDE, pos, attr, wgt, number, price, name, tval, sval, pval, xtra1, xtra2, xtra3, xtra4, xtra5, xtra6, xtra7, xtra8, xtra9);
6465 else
6466 Packet_printf(&connp2->c, "%c%c%c%hd%hd%d%s%c%c%hd%c%c%c%c%c%c%c%c%c", PKT_STORE_WIDE, pos, attr, wgt, number, price, name, tval, sval, pval, xtra1, xtra2, xtra3, xtra4, xtra5, xtra6, xtra7, xtra8, xtra9);
6467 }
6468 #endif
6469
6470 if (is_newer_than(&Players[Ind]->version, 4, 4, 7, 0, 0, 0))
6471 return Packet_printf(&connp->c, "%c%c%c%hd%hd%d%S%c%c%hd%c%c%c%c%c%c%c%c%c", PKT_STORE_WIDE, pos, attr, wgt, number, price, name, tval, sval, pval, xtra1, xtra2, xtra3, xtra4, xtra5, xtra6, xtra7, xtra8, xtra9);
6472 else
6473 return Packet_printf(&connp->c, "%c%c%c%hd%hd%d%s%c%c%hd%c%c%c%c%c%c%c%c%c", PKT_STORE_WIDE, pos, attr, wgt, number, price, name, tval, sval, pval, xtra1, xtra2, xtra3, xtra4, xtra5, xtra6, xtra7, xtra8, xtra9);
6474 }
6475
6476 /* For new non-shop stores (SPECIAL flag) - C. Blue */
6477 int Send_store_special_str(int Ind, char line, char col, char attr, char *str) {
6478 connection_t *connp = Conn[Players[Ind]->conn];
6479 #ifdef MINDLINK_STORE
6480 connection_t *connp2;
6481 player_type *p_ptr2 = NULL;
6482 #endif
6483
6484 if (!is_newer_than(&connp->version, 4, 4, 6, 1, 0, 0)) return 0;
6485
6486 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
6487 errno = 0;
6488 plog(format("Connection not ready for store item (%d.%d.%d)",
6489 Ind, connp->state, connp->id));
6490 return 0;
6491 }
6492
6493 #ifdef MINDLINK_STORE
6494 if (get_esp_link(Ind, LINKF_VIEW, &p_ptr2)) {
6495 connp2 = Conn[p_ptr2->conn];
6496 if (is_newer_than(&connp2->version, 4, 4, 6, 1, 0, 0))
6497 Packet_printf(&connp2->c, "%c%c%c%c%s", PKT_STORE_SPECIAL_STR, line, col, attr, str);
6498 }
6499 #endif
6500
6501 return Packet_printf(&connp->c, "%c%c%c%c%s", PKT_STORE_SPECIAL_STR, line, col, attr, str);
6502 }
6503
6504 /* For new non-shop stores (SPECIAL flag) - C. Blue */
6505 int Send_store_special_char(int Ind, char line, char col, char attr, char c) {
6506 connection_t *connp = Conn[Players[Ind]->conn];
6507 #ifdef MINDLINK_STORE
6508 connection_t *connp2;
6509 player_type *p_ptr2 = NULL;
6510 #endif
6511
6512 if (!is_newer_than(&connp->version, 4, 4, 6, 1, 0, 0)) return 0;
6513
6514 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
6515 errno = 0;
6516 plog(format("Connection not ready for store item (%d.%d.%d)",
6517 Ind, connp->state, connp->id));
6518 return 0;
6519 }
6520
6521 #ifdef MINDLINK_STORE
6522 if (get_esp_link(Ind, LINKF_VIEW, &p_ptr2)) {
6523 connp2 = Conn[p_ptr2->conn];
6524 if (is_newer_than(&connp2->version, 4, 4, 6, 1, 0, 0))
6525 Packet_printf(&connp2->c, "%c%c%c%c%c", PKT_STORE_SPECIAL_CHAR, line, col, attr, c);
6526 }
6527 #endif
6528
6529 return Packet_printf(&connp->c, "%c%c%c%c%c", PKT_STORE_SPECIAL_CHAR, line, col, attr, c);
6530 }
6531
6532 /* For new non-shop stores (SPECIAL flag) - C. Blue */
6533 int Send_store_special_clr(int Ind, char line_start, char line_end) {
6534 connection_t *connp = Conn[Players[Ind]->conn];
6535 #ifdef MINDLINK_STORE
6536 connection_t *connp2;
6537 player_type *p_ptr2 = NULL;
6538 #endif
6539
6540 if (!is_newer_than(&connp->version, 4, 4, 6, 1, 0, 0)) return 0;
6541
6542 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
6543 errno = 0;
6544 plog(format("Connection not ready for store item (%d.%d.%d)",
6545 Ind, connp->state, connp->id));
6546 return 0;
6547 }
6548
6549 #ifdef MINDLINK_STORE
6550 if (get_esp_link(Ind, LINKF_VIEW, &p_ptr2)) {
6551 connp2 = Conn[p_ptr2->conn];
6552 if (is_newer_than(&connp2->version, 4, 4, 6, 1, 0, 0))
6553 Packet_printf(&connp2->c, "%c%c%c", PKT_STORE_SPECIAL_CLR, line_start, line_end);
6554 }
6555 #endif
6556
6557 return Packet_printf(&connp->c, "%c%c%c", PKT_STORE_SPECIAL_CLR, line_start, line_end);
6558 }
6559
6560 /*
6561 * This function is supposed to handle 'store actions' too,
6562 * like 'buy' 'identify' 'heal' 'bid to an auction' - Jir -
6563 */
6564 int Send_store_info(int Ind, int num, cptr store, cptr owner, int items, int purse, byte attr, char c)
6565 {
6566 connection_t *connp = Conn[Players[Ind]->conn];
6567 #ifdef MINDLINK_STORE
6568 connection_t *connp2;
6569 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
6570 #endif
6571
6572 /* don't segfault old clients which use STORE_INVEN_MAX = 48 */
6573 if (is_older_than(&Players[Ind]->version, 4, 4, 9, 0, 0, 0)) {
6574 if (items > 48) items = 48;
6575 if ((num == STORE_HOME || num == STORE_HOME_DUN)
6576 && purse > 48) purse = 48;
6577 }
6578
6579 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
6580 {
6581 errno = 0;
6582 plog(format("Connection not ready for store info (%d.%d.%d)",
6583 Ind, connp->state, connp->id));
6584 return 0;
6585 }
6586
6587 #ifdef MINDLINK_STORE
6588 if (get_esp_link(Ind, LINKF_VIEW, &p_ptr2)) {
6589 connp2 = Conn[p_ptr2->conn];
6590 if (is_newer_than(&connp2->version, 4, 4, 4, 0, 0, 0)) {
6591 Packet_printf(&connp2->c, "%c%hd%s%s%hd%d%c%c", PKT_STORE_INFO, num, store, owner, items, purse, attr, c);
6592 } else {
6593 Packet_printf(&connp2->c, "%c%hd%s%s%hd%d", PKT_STORE_INFO, num, store, owner, items, purse);
6594 }
6595 }
6596 #endif
6597
6598 if (is_newer_than(&connp->version, 4, 4, 4, 0, 0, 0)) {
6599 return Packet_printf(&connp->c, "%c%hd%s%s%hd%d%c%c", PKT_STORE_INFO, num, store, owner, items, purse, attr, c);
6600 } else {
6601 return Packet_printf(&connp->c, "%c%hd%s%s%hd%d", PKT_STORE_INFO, num, store, owner, items, purse);
6602 }
6603 }
6604
6605 int Send_store_action(int Ind, char pos, u16b bact, u16b action, cptr name, char attr, char letter, s16b cost, byte flag)
6606 {
6607 connection_t *connp = Conn[Players[Ind]->conn];
6608 #ifdef MINDLINK_STORE
6609 connection_t *connp2;
6610 player_type *p_ptr = Players[Ind], *p_ptr2;
6611 #endif
6612
6613 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
6614 {
6615 errno = 0;
6616 plog(format("Connection not ready for store info (%d.%d.%d)",
6617 Ind, connp->state, connp->id));
6618 return 0;
6619 }
6620
6621 #ifdef MINDLINK_STORE
6622 if (get_esp_link(Ind, LINKF_VIEW, &p_ptr2)) {
6623 connp2 = Conn[p_ptr2->conn];
6624 Packet_printf(&connp2->c, "%c%c%hd%hd%s%c%c%hd%c", PKT_BACT, pos, bact, action, name, attr, letter, cost, flag);
6625 }
6626 #endif
6627
6628 return Packet_printf(&connp->c, "%c%c%hd%hd%s%c%c%hd%c", PKT_BACT, pos, bact, action, name, attr, letter, cost, flag);
6629 }
6630
6631 int Send_store_sell(int Ind, int price)
6632 {
6633 connection_t *connp = Conn[Players[Ind]->conn];
6634 #ifdef MINDLINK_STORE
6635 connection_t *connp2;
6636 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
6637 #endif
6638
6639 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
6640 {
6641 errno = 0;
6642 plog(format("Connection not ready for sell price (%d.%d.%d)",
6643 Ind, connp->state, connp->id));
6644 return 0;
6645 }
6646
6647 #ifdef MINDLINK_STORE
6648 if (get_esp_link(Ind, LINKF_VIEW, &p_ptr2)) {
6649 connp2 = Conn[p_ptr2->conn];
6650 Packet_printf(&connp2->c, "%c%d", PKT_SELL, price);
6651 }
6652 #endif
6653
6654 return Packet_printf(&connp->c, "%c%d", PKT_SELL, price);
6655 }
6656
6657 int Send_store_kick(int Ind)
6658 {
6659 connection_t *connp = Conn[Players[Ind]->conn];
6660 #ifdef MINDLINK_STORE
6661 connection_t *connp2;
6662 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
6663 #endif
6664
6665 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
6666 {
6667 errno = 0;
6668 plog(format("Connection not ready for store_kick (%d.%d.%d)",
6669 Ind, connp->state, connp->id));
6670 return 0;
6671 }
6672
6673 #ifdef MINDLINK_STORE
6674 if (get_esp_link(Ind, LINKF_VIEW, &p_ptr2)) {
6675 connp2 = Conn[p_ptr2->conn];
6676 Packet_printf(&connp2->c, "%c", PKT_STORE_LEAVE);
6677 }
6678 #endif
6679
6680 return Packet_printf(&connp->c, "%c", PKT_STORE_LEAVE);
6681 }
6682
6683 int Send_target_info(int Ind, int x, int y, cptr str)
6684 {
6685 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
6686 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
6687 char buf[80];
6688
6689 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
6690 {
6691 errno = 0;
6692 plog(format("Connection not ready for target info (%d.%d.%d)",
6693 Ind, connp->state, connp->id));
6694 return 0;
6695 }
6696
6697 /* Copy */
6698 strncpy(buf, str, 80 - 1);
6699 /* Paranoia -- Add null */
6700 buf[80 - 1] = '\0';
6701
6702 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
6703 connp2 = Conn[p_ptr2->conn];
6704 Packet_printf(&connp2->c, "%c%c%c%s", PKT_TARGET_INFO, x, y, buf);
6705 }
6706 return Packet_printf(&connp->c, "%c%c%c%s", PKT_TARGET_INFO, x, y, buf);
6707 }
6708 /* type is for client-side, regarding efficiency options;
6709 vol is the relative volume, if it stems from a source nearby instead of concerning the player directly;
6710 player_id is the player it actually concerns; - C. Blue */
6711 int Send_sound(int Ind, int sound, int alternative, int type, int vol, s32b player_id) {
6712 connection_t *connp = Conn[Players[Ind]->conn];
6713
6714 /* Mind-linked to someone? Send him our sound too! */
6715 player_type *p_ptr2 = NULL;
6716 connection_t *connp2 = NULL;
6717 /* If we're the target, we still hear our own sounds! */
6718 // if (Players[Ind]->esp_link_flags & LINKF_VIEW_DEDICATED) ;//nothing
6719 /* Get target player */
6720 if (get_esp_link(Ind, LINKF_VIEW, &p_ptr2)) connp2 = Conn[p_ptr2->conn];
6721 /* Send same info to target player, if available */
6722 if (connp2) {
6723 if (is_newer_than(&connp2->version, 4, 4, 5, 3, 0, 0))
6724 Packet_printf(&connp2->c, "%c%d%d%d%d%d", PKT_SOUND, sound, alternative, type, vol, player_id);
6725 else if (is_newer_than(&connp2->version, 4, 4, 5, 1, 0, 0))
6726 Packet_printf(&connp2->c, "%c%d%d%d", PKT_SOUND, sound, alternative, type);
6727 else if (is_newer_than(&connp2->version, 4, 4, 5, 0, 0, 0))
6728 Packet_printf(&connp2->c, "%c%d%d", PKT_SOUND, sound, alternative);
6729 else
6730 Packet_printf(&connp2->c, "%c%c", PKT_SOUND, sound);
6731 }
6732
6733 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
6734 errno = 0;
6735 plog(format("Connection not ready for sound (%d.%d.%d)",
6736 Ind, connp->state, connp->id));
6737 return 0;
6738 }
6739
6740 // if (is_admin(Players[Ind])) s_printf("USE_SOUND_2010: sound %d (alt %d) sent to player %s (%d).\n", sound, alternative, Players[Ind]->name, Ind);//debug
6741
6742 if (is_newer_than(&connp->version, 4, 4, 5, 3, 0, 0)) {
6743 return Packet_printf(&connp->c, "%c%d%d%d%d%d", PKT_SOUND, sound, alternative, type, vol, player_id);
6744 } else if (is_newer_than(&connp->version, 4, 4, 5, 1, 0, 0)) {
6745 return Packet_printf(&connp->c, "%c%d%d%d", PKT_SOUND, sound, alternative, type);
6746 } else if (is_newer_than(&connp->version, 4, 4, 4, 5, 0, 0)) {
6747 return Packet_printf(&connp->c, "%c%d%d", PKT_SOUND, sound, alternative);
6748 } else {
6749 return Packet_printf(&connp->c, "%c%c", PKT_SOUND, sound);
6750 }
6751 }
6752
6753 #ifdef USE_SOUND_2010
6754 int Send_music(int Ind, int music, int musicalt) {
6755 connection_t *connp = Conn[Players[Ind]->conn];
6756
6757 /* Mind-linked to someone? Send him our music too! */
6758 player_type *p_ptr2 = NULL;
6759 connection_t *connp2 = NULL;
6760 /* If we're the target, we won't hear our own music */
6761 if (Players[Ind]->esp_link_flags & LINKF_VIEW_DEDICATED) return(0);
6762 /* Get target player */
6763 if (get_esp_link(Ind, LINKF_VIEW, &p_ptr2)) connp2 = Conn[p_ptr2->conn];
6764 /* Send same info to target player, if available */
6765 if (connp2) {
6766 if (p_ptr2->music_current != music) {
6767 p_ptr2->music_current = music;
6768 p_ptr2->musicalt_current = musicalt;
6769 if (is_newer_than(&connp2->version, 4, 5, 6, 0, 0, 1))
6770 Packet_printf(&connp2->c, "%c%c%c", PKT_MUSIC, music, musicalt);
6771 else if (is_newer_than(&connp2->version, 4, 4, 4, 5, 0, 0))
6772 Packet_printf(&connp2->c, "%c%c", PKT_MUSIC, music);
6773 }
6774 }
6775
6776 if (Players[Ind]->music_current == music) return(-1);
6777 Players[Ind]->music_current = music;
6778 Players[Ind]->musicalt_current = musicalt;
6779
6780 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
6781 errno = 0;
6782 plog(format("Connection not ready for music (%d.%d.%d)",
6783 Ind, connp->state, connp->id));
6784 return 0;
6785 }
6786
6787 if (is_newer_than(&connp->version, 4, 5, 6, 0, 0, 1))
6788 return Packet_printf(&connp->c, "%c%c%c", PKT_MUSIC, music, musicalt);
6789 else if (!is_newer_than(&connp->version, 4, 4, 4, 5, 0, 0))
6790 return(-1);
6791 // s_printf("USE_SOUND_2010: music %d sent to player %s (%d).\n", music, Players[Ind]->name, Ind);//debug
6792 return Packet_printf(&connp->c, "%c%c", PKT_MUSIC, music);
6793 }
6794 int Send_sfx_ambient(int Ind, int sfx_ambient, bool smooth) {
6795 connection_t *connp = Conn[Players[Ind]->conn];
6796
6797
6798 /* translate: ambient sfx index -> sound index */
6799 int i = -1;
6800 cptr name = NULL;
6801
6802 //-1: smooth (poor with WoR, otherwise great), -2: sudden (needed for WoR/staircases)
6803 switch (sfx_ambient) {
6804 case SFX_AMBIENT_NONE: i = (smooth ? -1 : -2); break;
6805 case SFX_AMBIENT_FIREPLACE: name = "ambient_fireplace"; break;
6806 case SFX_AMBIENT_SHORE: name = "ambient_shore"; break;
6807 case SFX_AMBIENT_LAKE: name = "ambient_lake"; break;
6808 }
6809
6810 if (name) for (i = 0; i < SOUND_MAX_2010; i++) {
6811 if (!audio_sfx[i][0]) {
6812 i = -2;
6813 break;
6814 }
6815 if (!strcmp(audio_sfx[i], name)) break;
6816 }
6817 /* paranoia */
6818 if (i == SOUND_MAX_2010) i = -2;
6819
6820 /* Mind-linked to someone? Send him our sound too! */
6821 player_type *p_ptr2 = NULL;
6822 connection_t *connp2 = NULL;
6823 /* If we're the target, we won't hear our own sfx */
6824 if (Players[Ind]->esp_link_flags & LINKF_VIEW_DEDICATED) return(0);
6825 /* Get target player */
6826 if (get_esp_link(Ind, LINKF_VIEW, &p_ptr2)) connp2 = Conn[p_ptr2->conn];
6827 /* Send same info to target player, if available */
6828 if (connp2) {
6829 if (p_ptr2->sound_ambient != sfx_ambient) {
6830 p_ptr2->sound_ambient = sfx_ambient;
6831 if (is_newer_than(&connp2->version, 4, 5, 4, 0, 0, 0))
6832 Packet_printf(&connp2->c, "%c%d", PKT_SFX_AMBIENT, i);
6833 }
6834 }
6835
6836 if (Players[Ind]->sound_ambient == sfx_ambient) return(-1);
6837 Players[Ind]->sound_ambient = sfx_ambient;
6838
6839 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
6840 errno = 0;
6841 plog(format("Connection not ready for ambient sfx (%d.%d.%d)",
6842 Ind, connp->state, connp->id));
6843 return 0;
6844 }
6845
6846 if (!is_newer_than(&connp->version, 4, 5, 4, 0, 0, 0)) return(-1);
6847 //s_printf("USE_SOUND_2010: ambient sfx %d sent to player %s (%d).\n", i, Players[Ind]->name, Ind);//debug
6848 return Packet_printf(&connp->c, "%c%d", PKT_SFX_AMBIENT, i);
6849 }
6850 int Send_sfx_volume(int Ind, char sfx_ambient_vol, char sfx_weather_vol) {
6851 connection_t *connp = Conn[Players[Ind]->conn];
6852 /* Mind-linked to someone? Send him our sound too! */
6853 player_type *p_ptr2 = NULL;
6854 connection_t *connp2 = NULL;
6855
6856 /* If we're the target, we won't hear our own sfx */
6857 if (Players[Ind]->esp_link_flags & LINKF_VIEW_DEDICATED) return(0);
6858 /* Get target player */
6859 if (get_esp_link(Ind, LINKF_VIEW, &p_ptr2)) connp2 = Conn[p_ptr2->conn];
6860 /* Send same info to target player, if available */
6861 if (connp2 && is_newer_than(&connp2->version, 4, 5, 5, 0, 0, 0))
6862 Packet_printf(&connp2->c, "%c%c%c", PKT_SFX_VOLUME, sfx_ambient_vol, sfx_weather_vol);
6863
6864 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
6865 errno = 0;
6866 plog(format("Connection not ready for ambient sfx (%d.%d.%d)",
6867 Ind, connp->state, connp->id));
6868 return 0;
6869 }
6870
6871 if (!is_newer_than(&connp->version, 4, 5, 5, 0, 0, 0)) return(-1);
6872 //s_printf("USE_SOUND_2010: ambient sfx %d sent to player %s (%d).\n", i, Players[Ind]->name, Ind);//debug
6873 return Packet_printf(&connp->c, "%c%c%c", PKT_SFX_VOLUME, sfx_ambient_vol, sfx_weather_vol);
6874 }
6875 #endif
6876
6877 int Send_boni_col(int Ind, boni_col c) {
6878 connection_t *connp = Conn[Players[Ind]->conn];
6879 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
6880 errno = 0;
6881 plog(format("Connection not ready for boni_col (%d.%d.%d)",
6882 Ind, connp->state, connp->id));
6883 return 0;
6884 }
6885
6886 if (!is_newer_than(&connp->version, 4, 5, 3, 2, 0, 0)) return(-1);
6887 if (is_newer_than(&connp->version, 4, 5, 9, 0, 0, 0)) {
6888 return Packet_printf(&connp->c, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", PKT_BONI_COL, //1+22+13+2 bytes in total
6889 c.i, c.spd, c.slth, c.srch, c.infr, c.lite, c.dig, c.blow, c.crit, c.shot,
6890 c.migh, c.mxhp, c.mxmp, c.luck, c.pstr, c.pint, c.pwis, c.pdex, c.pcon, c.pchr, c.amfi, c.sigl,
6891 c.cb[0], c.cb[1], c.cb[2], c.cb[3], c.cb[4], c.cb[5], c.cb[6], c.cb[7], c.cb[8], c.cb[9],
6892 c.cb[10], c.cb[11], c.cb[12], c.color, c.symbol);
6893 } else { //send old info to old players
6894 return Packet_printf(&connp->c, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", PKT_BONI_COL, //1+20+13+2 bytes in total
6895 c.i, c.spd, c.slth, c.srch, c.infr, c.lite, c.dig, c.blow, c.crit, c.shot,
6896 c.migh, c.mxhp, c.mxmp, c.luck, c.pstr, c.pint, c.pwis, c.pdex, c.pcon, c.pchr,
6897 c.cb[0], c.cb[1], c.cb[2], c.cb[3], c.cb[4], c.cb[5], c.cb[6], c.cb[7], c.cb[8], c.cb[9],
6898 c.cb[10], c.cb[11], c.cb[12], c.color, c.symbol);
6899 }
6900 }
6901
6902 int Send_beep(int Ind) {
6903 connection_t *connp = Conn[Players[Ind]->conn];
6904
6905 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
6906 errno = 0;
6907 plog(format("Connection not ready for beep (page) (%d.%d.%d)",
6908 Ind, connp->state, connp->id));
6909 return 0;
6910 }
6911
6912 return Packet_printf(&connp->c, "%c", PKT_BEEP);
6913 }
6914
6915 int Send_warning_beep(int Ind)
6916 {
6917 connection_t *connp = Conn[Players[Ind]->conn];
6918
6919 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
6920 errno = 0;
6921 plog(format("Connection not ready for beep (warning) (%d.%d.%d)",
6922 Ind, connp->state, connp->id));
6923 return 0;
6924 }
6925
6926 if (is_newer_than(&Players[Ind]->version, 4, 5, 2, 0, 0, 0))
6927 return Packet_printf(&connp->c, "%c", PKT_WARNING_BEEP);
6928 else
6929 return Packet_printf(&connp->c, "%c", PKT_BEEP);
6930 }
6931
6932 int Send_AFK(int Ind, byte afk)
6933 {
6934 connection_t *connp = Conn[Players[Ind]->conn];
6935 // player_type *p_ptr = Players[Ind];
6936
6937 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
6938 errno = 0;
6939 plog(format("Connection not ready for AFK (%d.%d.%d)",
6940 Ind, connp->state, connp->id));
6941 return 0;
6942 }
6943 return Packet_printf(&connp->c, "%c%c", PKT_AFK, afk);
6944 }
6945
6946 int Send_encumberment(int Ind, byte cumber_armor, byte awkward_armor, byte cumber_glove, byte heavy_wield, byte heavy_shield, byte heavy_shoot,
6947 byte icky_wield, byte awkward_wield, byte easy_wield, byte cumber_weight, byte monk_heavyarmor, byte rogue_heavyarmor, byte awkward_shoot,
6948 byte heavy_swim) {
6949 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
6950 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
6951
6952 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
6953 errno = 0;
6954 plog(format("Connection not ready for encumberment (%d.%d.%d)",
6955 Ind, connp->state, connp->id));
6956 return 0;
6957 }
6958 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
6959 connp2 = Conn[p_ptr2->conn];
6960 if (!is_newer_than(&connp2->version, 4, 4, 2, 0, 0, 0)) {
6961 Packet_printf(&connp2->c, "%c%c%c%c%c%c%c%c%c%c%c%c%c", PKT_ENCUMBERMENT, cumber_armor, awkward_armor, cumber_glove, heavy_wield, heavy_shield, heavy_shoot,
6962 icky_wield, awkward_wield, easy_wield, cumber_weight, monk_heavyarmor, awkward_shoot);
6963 } else {
6964 Packet_printf(&connp2->c, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c", PKT_ENCUMBERMENT, cumber_armor, awkward_armor, cumber_glove, heavy_wield, heavy_shield, heavy_shoot,
6965 icky_wield, awkward_wield, easy_wield, cumber_weight, monk_heavyarmor, rogue_heavyarmor, awkward_shoot);
6966 }
6967 }
6968 if (!is_newer_than(&connp->version, 4, 4, 2, 0, 0, 0)) {
6969 return Packet_printf(&connp->c, "%c%c%c%c%c%c%c%c%c%c%c%c%c", PKT_ENCUMBERMENT, cumber_armor, awkward_armor, cumber_glove, heavy_wield, heavy_shield, heavy_shoot,
6970 icky_wield, awkward_wield, easy_wield, cumber_weight, monk_heavyarmor, awkward_shoot);
6971 } else {
6972 return Packet_printf(&connp->c, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c", PKT_ENCUMBERMENT, cumber_armor, awkward_armor, cumber_glove, heavy_wield, heavy_shield, heavy_shoot,
6973 icky_wield, awkward_wield, easy_wield, cumber_weight, monk_heavyarmor, rogue_heavyarmor, awkward_shoot);
6974 }
6975 }
6976
6977
6978 int Send_special_line(int Ind, s32b max, s32b line, byte attr, cptr buf) {
6979 connection_t *connp = Conn[Players[Ind]->conn];
6980 char temp[ONAME_LEN - 3], xattr = 'w', temp2[ONAME_LEN];
6981
6982 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
6983 errno = 0;
6984 plog(format("Connection not ready for special line (%d.%d.%d)",
6985 Ind, connp->state, connp->id));
6986 return 0;
6987 }
6988
6989 switch (attr) {
6990 case TERM_DARK: xattr = 'd';break;
6991 case TERM_RED: xattr = 'r';break;
6992 case TERM_L_DARK: xattr = 'D';break;
6993 case TERM_L_RED: xattr = 'R';break;
6994 case TERM_WHITE: xattr = 'w';break;
6995 case TERM_GREEN: xattr = 'g';break;
6996 case TERM_L_WHITE: xattr = 'W';break;
6997 case TERM_L_GREEN: xattr = 'G';break;
6998 case TERM_SLATE: xattr = 's';break;
6999 case TERM_BLUE: xattr = 'b';break;
7000 case TERM_VIOLET: xattr = 'v';break;
7001 case TERM_L_BLUE: xattr = 'B';break;
7002 case TERM_ORANGE: xattr = 'o';break;
7003 case TERM_UMBER: xattr = 'u';break;
7004 case TERM_YELLOW: xattr = 'y';break;
7005 case TERM_L_UMBER: xattr = 'U';break;
7006 case TERM_MULTI: xattr = 'm';break;
7007 case TERM_POIS: xattr = 'p';break;
7008 case TERM_FIRE: xattr = 'f';break;
7009 case TERM_COLD: xattr = 'c';break;
7010 case TERM_ACID: xattr = 'a';break;
7011 case TERM_ELEC: xattr = 'e';break;
7012 case TERM_LITE: xattr = 'L';break;
7013 case TERM_HALF: xattr = 'h';break;
7014 case TERM_CONF: xattr = 'C';break;
7015 case TERM_SOUN: xattr = 'S';break;
7016 case TERM_SHAR: xattr = 'H';break;
7017 case TERM_DARKNESS: xattr = 'A';break;
7018 case TERM_SHIELDM: xattr = 'M';break;
7019 case TERM_SHIELDI: xattr = 'I';break;
7020 //TODO: implement/watch client version for EXTENDED_TERM_COLOURS
7021 }
7022
7023 strncpy(temp, buf, ONAME_LEN - 4);
7024 temp[ONAME_LEN - 4] = '\0';
7025
7026 strcpy(temp2, "\377");
7027 temp2[1] = xattr; temp2[2] = '\0';
7028
7029 #if 0 /* default (no colour codes conversion) */
7030 strcat(temp2, temp);
7031 #else /* allow colour code shortcut - C. Blue */
7032 #if 0 /* '{' = colour, '{{' = normal */
7033 {
7034 char *t = temp, *t2 = temp2 + 2;
7035 while (*t) {
7036 if (*t != '{') *t2++ = *t++;
7037 else {
7038 /* double '{' ? */
7039 if (*(t + 1) == '{') {
7040 *t2++ = *t++;
7041 }
7042 /* single '{' ? -> becomes colour code */
7043 else {
7044 *t2++ = '\377';
7045 }
7046 t++;
7047 }
7048 }
7049 *t2 = 0;
7050 }
7051 #endif
7052 #if 1 /* '\{' = colour, '{' = normal */
7053 {
7054 char *t = temp, *t2 = temp2 + 2;
7055 while (*t) {
7056 if (*t != '\\') *t2++ = *t++;
7057 else {
7058 /* double code ? -> colour */
7059 if (*(t + 1) == '{') {
7060 *t2++ = '\377';
7061 t += 2;
7062 }
7063 /* single '{' ? keep */
7064 else *t2++ = *t++;
7065 }
7066 }
7067 *t2 = 0;
7068 }
7069 #endif
7070 #endif
7071
7072 if (is_newer_than(&Players[Ind]->version, 4, 4, 7, 0, 0, 0))
7073 return Packet_printf(&connp->c, "%c%d%d%c%I", PKT_SPECIAL_LINE, max, line, attr, temp2);
7074 else if (is_newer_than(&Players[Ind]->version, 4, 4, 6, 1, 0, 0))
7075 return Packet_printf(&connp->c, "%c%hd%hd%c%I", PKT_SPECIAL_LINE, max, line, attr, temp2);
7076 else {
7077 /* Cut it off so old clients can handle it, ouch */
7078 temp2[79] = 0;
7079 return Packet_printf(&connp->c, "%c%d%d%c%s", PKT_SPECIAL_LINE, max, line, attr, temp2);
7080 }
7081 }
7082
7083 int Send_floor(int Ind, char tval)
7084 {
7085 connection_t *connp = Conn[Players[Ind]->conn];
7086
7087 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
7088 {
7089 errno = 0;
7090 plog(format("Connection not ready for floor item (%d.%d.%d)",
7091 Ind, connp->state, connp->id));
7092 return 0;
7093 }
7094
7095 return Packet_printf(&connp->c, "%c%c", PKT_FLOOR, tval);
7096 }
7097
7098 int Send_pickup_check(int Ind, cptr buf)
7099 {
7100 connection_t *connp = Conn[Players[Ind]->conn];
7101
7102 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
7103 {
7104 errno = 0;
7105 plog(format("Connection not ready for pickup check (%d.%d.%d)",
7106 Ind, connp->state, connp->id));
7107 return 0;
7108 }
7109
7110 return Packet_printf(&connp->c, "%c%s", PKT_PICKUP_CHECK, buf);
7111 }
7112
7113 /* adding ultimate quick and dirty hack here so geraldo can play his 19th lvl char
7114 with the 80 character party name......
7115 -APD-
7116 */
7117
7118 int Send_party(int Ind, bool leave, bool clear) {
7119 int i;
7120 party_type *pa_ptr = &parties[Players[Ind]->party];
7121 char bufn[90], bufm[20], bufo[50], buf[10];
7122 char bufn_compat[90], bufm_compat[20], bufo_compat[50];
7123
7124 /* prepare data for outdated clients */
7125 if (pa_ptr->mode == PA_IRONTEAM)
7126 snprintf(bufn_compat, 90, "Party (Iron Team): %s", pa_ptr->name);
7127 else
7128 snprintf(bufn_compat, 90, "Party : %s", pa_ptr->name);
7129 strcpy(bufm_compat, "Members: ");
7130 snprintf(buf, 10, "%d", pa_ptr->members);
7131 strcat(bufm_compat, buf);
7132 strcpy(bufo_compat, "Owner : ");
7133 strcat(bufo_compat, pa_ptr->owner);
7134
7135 /* We're just sending that we aren't in a party? */
7136 if (Players[Ind]->party == 0) {
7137 connection_t *connp = Conn[Players[Ind]->conn];
7138 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
7139 errno = 0;
7140 plog(format("Connection nor ready for party info (%d.%d.%d)",
7141 Ind, connp->state, connp->id));
7142 return 0;
7143 }
7144 if (!is_newer_than(&Players[Ind]->version, 4, 4, 7, 0, 0, 0)) {
7145 Packet_printf(&connp->c, "%c%s%s%s", PKT_PARTY, bufn_compat, "Members: - ", "Owner : - ");
7146 } else {
7147 Packet_printf(&connp->c, "%c%s%s%s", PKT_PARTY, "", "", "");
7148 }
7149 return 1;
7150 }
7151
7152 /* prepare data for clients */
7153 if (pa_ptr->mode == PA_IRONTEAM)
7154 snprintf(bufn, 90, "Iron Team: '\377%c%s\377w'", COLOUR_CHAT_PARTY, pa_ptr->name);
7155 else
7156 snprintf(bufn, 90, "Party: '\377%c%s\377w'", COLOUR_CHAT_PARTY, pa_ptr->name);
7157 snprintf(buf, 10, "%d", pa_ptr->members);
7158 strcpy(bufm, buf);
7159 if (pa_ptr->members == 1) strcat(bufm, " member");
7160 else strcat(bufm, " members");
7161 strcpy(bufo, "owner: ");
7162 strcat(bufo, pa_ptr->owner);
7163
7164 /* scan party members and send info */
7165 for (i = 1; i <= NumPlayers; i++) {
7166 player_type *p_ptr = Players[i];
7167 connection_t *connp = Conn[p_ptr->conn];
7168
7169 if (p_ptr->party != Players[Ind]->party) continue;
7170 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
7171 errno = 0;
7172 plog(format("Connection nor ready for party info (%d.%d.%d)",
7173 i, connp->state, connp->id));
7174 continue;
7175 }
7176
7177 if (!is_newer_than(&p_ptr->version, 4, 4, 7, 0, 0, 0)) {
7178 Packet_printf(&connp->c, "%c%s%s%s", PKT_PARTY, bufn_compat, bufm_compat, bufo_compat);
7179 } else {
7180 if (!clear && (!leave || i != Ind)) {
7181 Packet_printf(&connp->c, "%c%s%s%s", PKT_PARTY, bufn, bufm, bufo);
7182 } else {
7183 Packet_printf(&connp->c, "%c%s%s%s", PKT_PARTY, "", "", "");
7184 }
7185 }
7186 }
7187
7188 return 1;
7189 }
7190
7191 int Send_guild(int Ind, bool leave, bool clear) {
7192 int i;
7193 guild_type *g_ptr = &guilds[Players[Ind]->guild];
7194 char bufn[90], bufm[20], bufo[50], buf[10];
7195
7196 /* We're just sending that we aren't in a guild? */
7197 if (Players[Ind]->guild == 0) {
7198 connection_t *connp = Conn[Players[Ind]->conn];
7199 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
7200 errno = 0;
7201 plog(format("Connection nor ready for guild info (%d.%d.%d)",
7202 Ind, connp->state, connp->id));
7203 return 0;
7204 }
7205 Packet_printf(&connp->c, "%c%s%s%s", PKT_GUILD, "", "", "");
7206 return 1;
7207 }
7208
7209 /* prepare data for clients */
7210 snprintf(bufn, 90, "Guild: '\377%c%s\377w'", COLOUR_CHAT_GUILD, g_ptr->name);
7211 snprintf(buf, 10, "%d", g_ptr->members);
7212 strcpy(bufm, buf);
7213 if (g_ptr->members == 1) strcat(bufm, " member");
7214 else strcat(bufm, " members");
7215 if (lookup_player_name(g_ptr->master)) {
7216 strcpy(bufo, "master: ");
7217 strcat(bufo, lookup_player_name(g_ptr->master));
7218 } else {
7219 strcpy(bufo, "master: <leaderless>");
7220 }
7221
7222 /* scan party members and send info */
7223 for (i = 1; i <= NumPlayers; i++) {
7224 player_type *p_ptr = Players[i];
7225 connection_t *connp = Conn[p_ptr->conn];
7226
7227 if (!is_newer_than(&p_ptr->version, 4, 4, 7, 0, 0, 0)) continue;
7228 if (p_ptr->guild != Players[Ind]->guild) continue;
7229 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
7230 errno = 0;
7231 plog(format("Connection nor ready for guild info (%d.%d.%d)",
7232 i, connp->state, connp->id));
7233 continue;
7234 }
7235
7236 if (!clear && (!leave || i != Ind)) {
7237 Packet_printf(&connp->c, "%c%s%s%s", PKT_GUILD, bufn, bufm, bufo);
7238 } else {
7239 Packet_printf(&connp->c, "%c%s%s%s", PKT_GUILD, "", "", "");
7240 }
7241 }
7242
7243 return 1;
7244 }
7245
7246 int Send_guild_config(int id) {
7247 int i, j;
7248 guild_type *g_ptr = &guilds[id];
7249 int master;
7250 int ghwx = -1, ghwy = 0, ghx, ghy, ghpos = -1;
7251
7252 /* guild hall location */
7253 if (g_ptr->h_idx) {
7254 ghwx = houses[g_ptr->h_idx - 1].wpos.wx;
7255 ghwy = houses[g_ptr->h_idx - 1].wpos.wy;
7256 ghx = houses[g_ptr->h_idx - 1].x;
7257 ghy = houses[g_ptr->h_idx - 1].y;
7258
7259 if (ghy < MAX_HGT / 3) ghpos = 0;
7260 else if (ghy < 2 * MAX_HGT / 3) ghpos = 1;
7261 else ghpos = 2;
7262 if (ghx < MAX_WID / 3) ghpos += 0;
7263 else if (ghx < 2 * MAX_WID / 3) ghpos += 4;
7264 else ghpos += 8;
7265 }
7266 #ifndef ENABLE_GUILD_HALL
7267 else ghwx = -2;
7268 #endif
7269
7270 /* scan party members and send info */
7271 for (i = 1; i <= NumPlayers; i++) {
7272 player_type *p_ptr = Players[i];
7273 connection_t *connp = Conn[p_ptr->conn];
7274
7275 if (!is_newer_than(&p_ptr->version, 4, 5, 2, 0, 0, 0)) continue;
7276 if (p_ptr->guild != id) continue;
7277 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
7278 errno = 0;
7279 plog(format("Connection nor ready for guild info (%d.%d.%d)",
7280 i, connp->state, connp->id));
7281 continue;
7282 }
7283
7284 if (g_ptr->master == p_ptr->id) master = 1;
7285 else master = 0;
7286
7287 Packet_printf(&connp->c, "%c%d%d%d%d%d%d%d", PKT_GUILD_CFG, master, g_ptr->flags, g_ptr->minlev, 5, ghwx, ghwy, ghpos);
7288 for (j = 0; j < 5; j++) Packet_printf(&connp->c, "%s", g_ptr->adder[j]);
7289 }
7290
7291 return 1;
7292 }
7293
7294 int Send_special_other(int Ind) {
7295 connection_t *connp = Conn[Players[Ind]->conn];
7296
7297 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
7298 errno = 0;
7299 plog(format("Connection not ready for special other (%d.%d.%d)",
7300 Ind, connp->state, connp->id));
7301 return 0;
7302 }
7303
7304 return Packet_printf(&connp->c, "%c", PKT_SPECIAL_OTHER);
7305 }
7306
7307 int Send_skills(int Ind) {
7308 player_type *p_ptr = Players[Ind];
7309 connection_t *connp = Conn[p_ptr->conn];
7310 s16b skills[12];
7311 int i, tmp = 0;
7312 object_type *o_ptr;
7313
7314 /* Fighting skill */
7315 o_ptr = &p_ptr->inventory[INVEN_WIELD];
7316 tmp = o_ptr->to_h;
7317 /* dual-wield? */
7318 #if 0 /* hmm seemed a bit glitchy? replacing below.. */
7319 o_ptr = &p_ptr->inventory[INVEN_ARM];
7320 if (o_ptr->k_idx && o_ptr->tval != TV_SHIELD) tmp += o_ptr->to_h;
7321 /* average? */
7322 if (p_ptr->dual_wield) tmp /= 2;
7323 #else
7324 if (p_ptr->dual_wield && p_ptr->dual_mode) {
7325 o_ptr = &p_ptr->inventory[INVEN_ARM];
7326 tmp += o_ptr->to_h;
7327 /* average */
7328 tmp /= 2;
7329 }
7330 #endif
7331
7332 #if 1 /* since Fighting and Bows/Throws have other effects, don't confuse players with this weird sum */
7333 tmp += p_ptr->to_h + p_ptr->to_h_melee;
7334 skills[0] = p_ptr->skill_thn + (tmp * BTH_PLUS_ADJ);
7335
7336 /* Shooting skill */
7337 o_ptr = &p_ptr->inventory[INVEN_BOW];
7338 tmp = p_ptr->to_h + o_ptr->to_h + p_ptr->to_h_ranged;
7339 skills[1] = p_ptr->skill_thb + (tmp * BTH_PLUS_ADJ);
7340 #else /* looks silly for a warrior who has maxed skills yet is only "good" or something */
7341 skills[0] = p_ptr->skill_thn;
7342 skills[1] = p_ptr->skill_thb;
7343 #endif
7344
7345 /* Basic abilities */
7346 skills[2] = p_ptr->skill_sav;
7347 skills[3] = p_ptr->skill_stl;
7348 skills[4] = p_ptr->skill_fos;
7349 skills[5] = p_ptr->skill_srh;
7350 skills[6] = p_ptr->skill_dis;
7351 skills[7] = p_ptr->skill_dev;
7352
7353 /* Number of blows */
7354 skills[8] = p_ptr->num_blow;
7355 skills[9] = p_ptr->num_fire;
7356 skills[10] = p_ptr->num_spell;
7357
7358 /* Infravision */
7359 skills[11] = p_ptr->see_infra;
7360
7361 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
7362 errno = 0;
7363 plog(format("Connection not ready for skills (%d.%d.%d)",
7364 Ind, connp->state, connp->id));
7365 return 0;
7366 }
7367
7368 Packet_printf(&connp->c, "%c", PKT_SKILLS);
7369
7370 for (i = 0; i < 12; i++) Packet_printf(&connp->c, "%hd", skills[i]);
7371
7372 return 1;
7373 }
7374
7375
7376 int Send_pause(int Ind) {
7377 connection_t *connp = Conn[Players[Ind]->conn];
7378
7379 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
7380 errno = 0;
7381 plog(format("Connection not ready for skills (%d.%d.%d)",
7382 Ind, connp->state, connp->id));
7383 return 0;
7384 }
7385
7386 return Packet_printf(&connp->c, "%c", PKT_PAUSE);
7387 }
7388
7389
7390
7391 int Send_monster_health(int Ind, int num, byte attr) {
7392 connection_t *connp = Conn[Players[Ind]->conn], *connp2;
7393 player_type *p_ptr2 = NULL; /*, *p_ptr = Players[Ind];*/
7394
7395 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
7396 errno = 0;
7397 plog(format("Connection not ready for monster health bar (%d.%d.%d)",
7398 Ind, connp->state, connp->id));
7399 return 0;
7400 }
7401 if (get_esp_link(Ind, LINKF_MISC, &p_ptr2)) {
7402 connp2 = Conn[p_ptr2->conn];
7403 Packet_printf(&connp2->c, "%c%c%c", PKT_MONSTER_HEALTH, num, attr);
7404 }
7405
7406 return Packet_printf(&connp->c, "%c%c%c", PKT_MONSTER_HEALTH, num, attr);
7407 }
7408
7409 /* Always display oneself as '@' for easier visibility,
7410 instead of number or minus sign (when dead)? */
7411 #define CHARDUMP_VIS_HACK
7412 int Send_chardump(int Ind, cptr tag) {
7413 player_type *p_ptr = Players[Ind];
7414 connection_t *connp = Conn[p_ptr->conn];
7415 int thp;
7416
7417 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
7418 errno = 0;
7419 plog(format("Connection not ready for chardump (%d.%d.%d)",
7420 Ind, connp->state, connp->id));
7421 return 0;
7422 }
7423
7424 #if 0 /* This works, but won't help non-death char dumps that are taken manually */
7425 /* hack: Quickly update the client's unique list first */
7426 for (i = 0; i < MAX_R_IDX; i++)
7427 if (r_info[i].flags1 & RF1_UNIQUE)
7428 Send_unique_monster(Ind, i);
7429 #endif
7430
7431 #ifdef CHARDUMP_VIS_HACK
7432 /* hack: display own symbol as '@' for this chardump, for easier recognising */
7433 thp = p_ptr->chp;
7434 #if 0
7435 if (p_ptr->chp < 0) /* only for death dumps? */
7436 #endif
7437 p_ptr->chp = p_ptr->mhp;
7438 lite_spot(Ind, p_ptr->py, p_ptr->px);
7439 #endif
7440
7441 if (!is_newer_than(&connp->version, 4, 4, 2, 0, 0, 0) ||
7442 MY_VERSION <= (4 << 12 | 4 << 8 | 2 << 4 | 0))
7443 return Packet_printf(&connp->c, "%c", PKT_CHARDUMP);
7444 else
7445 return Packet_printf(&connp->c, "%c%s", PKT_CHARDUMP, tag);
7446
7447 #ifdef CHARDUMP_VIS_HACK
7448 /* unhack '@' */
7449 p_ptr->chp = thp;
7450 lite_spot(Ind, p_ptr->py, p_ptr->px);
7451 #endif
7452 }
7453
7454 int Send_unique_monster(int Ind, int r_idx) {
7455 connection_t *connp = Conn[Players[Ind]->conn];
7456 player_type *p_ptr = Players[Ind];
7457
7458 if (!is_newer_than(&connp->version, 4, 4, 1, 7, 0, 0)) return(0);
7459
7460 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
7461 {
7462 errno = 0;
7463 plog(format("Connection not ready for unique monster (%d.%d.%d)",
7464 Ind, connp->state, connp->id));
7465 return 0;
7466 }
7467 return Packet_printf(&connp->c, "%c%d%d%s", PKT_UNIQUE_MONSTER, r_info[r_idx].u_idx, p_ptr->r_killed[r_idx], r_name + r_info[r_idx].name);
7468 }
7469
7470 int Send_weather(int Ind, int weather_type, int weather_wind, int weather_gen_speed, int weather_intensity, int weather_speed, bool update_clouds, bool revoke_clouds) {
7471 int n, i, c;
7472 int cx1, cy1, cx2, cy2;
7473
7474 /* Note: This is NOT the client-side limit, but rather the current
7475 server-side limit how many clouds we want to transmit to the client. */
7476 const int cloud_limit = 10;
7477
7478 connection_t *connp = Conn[Players[Ind]->conn];
7479
7480 /* Mind-linked to someone? Send him our weather */
7481 player_type *p_ptr2 = NULL;
7482 connection_t *connp2 = NULL;
7483 /* If we're the target, we won't see our own weather */
7484 if (Players[Ind]->esp_link_flags & LINKF_VIEW_DEDICATED) return(0);
7485 /* Get target player */
7486 if (get_esp_link(Ind, LINKF_VIEW, &p_ptr2)) connp2 = Conn[p_ptr2->conn];
7487
7488
7489 wilderness_type *w_ptr = &wild_info[Players[Ind]->wpos.wy][Players[Ind]->wpos.wx];
7490
7491 if (!is_newer_than(&connp->version, 4, 4, 2, 0, 0, 0)) return(0);
7492
7493 if (!BIT(connp->state, CONN_PLAYING | CONN_READY))
7494 {
7495 errno = 0;
7496 plog(format("Connection not ready for weather (%d.%d.%d)",
7497 Ind, connp->state, connp->id));
7498 return 0;
7499 }
7500
7501 /* hack: tell client to disable all clouds */
7502 if (revoke_clouds) c = -1;
7503 /* tell client to expect clouds */
7504 // else if (update_clouds) c = w_ptr->clouds_to_update;
7505 else if (update_clouds) c = cloud_limit;
7506 else c = 0;
7507 /* fix limit! (or crash/bug results on client-side,
7508 since it tries to read ALL clouds (despite discarding
7509 those which are too much) and hence tries to read more
7510 packets than we are actually sending, corrupting itself) */
7511 //redundant, see above
7512 // if (c > cloud_limit) c = cloud_limit;
7513 #ifdef TEST_SERVER
7514 if (weather_type > 0) s_printf("weather_type: %d\n", weather_type);
7515 #endif
7516 n = Packet_printf(&connp->c, "%c%d%d%d%d%d%d%d%d", PKT_WEATHER,
7517 weather_type, weather_wind, weather_gen_speed, weather_intensity, weather_speed,
7518 Players[Ind]->panel_col_prt, Players[Ind]->panel_row_prt, c);
7519 if (connp2) Packet_printf(&connp2->c, "%c%d%d%d%d%d%d%d%d", PKT_WEATHER,
7520 weather_type, weather_wind, weather_gen_speed, weather_intensity, weather_speed,
7521 Players[Ind]->panel_col_prt, Players[Ind]->panel_row_prt, c);
7522
7523 #ifdef TEST_SERVER
7524 #if 0
7525 s_printf("clouds_to_update %d (%d)\n", c, w_ptr->clouds_to_update);
7526 #endif
7527 #endif
7528
7529 /* re-send all clouds that have 'updated' flag set */
7530 if (c > 0) {
7531 for (i = 0; i < cloud_limit; i++) {
7532 #if 0 /* unfinished//also, make it visible to all players, so if0 here - see "/jokeweather" instead */
7533 /* fun stuff ;) abuse the last cloud for this */
7534 if (Players[Ind]->joke_weather && (i == cloud_limit - 1)) {
7535 n = Packet_printf(&connp->c, "%d%d%d%d%d%d%d%d", i,
7536 Players[Ind]->px - 1, Players[Ind]->py,
7537 Players[Ind]->px + 1, Players[Ind]->py,
7538 7, 0, 0);
7539 continue;
7540 }
7541 #endif
7542
7543 // if (w_ptr->cloud_updated[i]) {
7544 //s_printf("cloud_updated %d\n", i);
7545
7546 //DEBUGGING... (local should be correct, but that's not all yet..)
7547 #if 0 /* send global cloud coordinates, same as the server uses? */
7548 n = Packet_printf(&connp->c, "%d%d%d%d%d%d%d%d",
7549 i, w_ptr->cloud_x1[i], w_ptr->cloud_y1[i], w_ptr->cloud_x2[i], w_ptr->cloud_y2[i],
7550 w_ptr->cloud_dsum[i], w_ptr->cloud_xm100[i], w_ptr->cloud_ym100[i]);
7551 #else /* send local cloud coordinates especially for client-side? */
7552 /* convert global cloud coordinates (server-side)
7553 to local coordinates for the client, who only
7554 has to pay attention to one sector at a time
7555 (ie the one the player is currently in): */
7556 cx1 = w_ptr->cloud_x1[i] - Players[Ind]->wpos.wx * MAX_WID;
7557 cy1 = w_ptr->cloud_y1[i] - Players[Ind]->wpos.wy * MAX_HGT;
7558 cx2 = w_ptr->cloud_x2[i] - Players[Ind]->wpos.wx * MAX_WID;
7559 cy2 = w_ptr->cloud_y2[i] - Players[Ind]->wpos.wy * MAX_HGT;
7560 /* hack: 'disable' a cloud slot */
7561 if (w_ptr->cloud_x1[i] == -9999) cx1 = -9999;
7562
7563 #ifdef TEST_SERVER
7564 #if 0
7565 s_printf("sending local cloud %d (%d,%d - %d,%d)\n", i, cx1, cy1, cx2, cy2);
7566 #endif
7567 #endif
7568
7569 n = Packet_printf(&connp->c, "%d%d%d%d%d%d%d%d",
7570 i, cx1, cy1, cx2, cy2,
7571 w_ptr->cloud_dsum[i], w_ptr->cloud_xm100[i], w_ptr->cloud_ym100[i]);
7572 if (connp2) Packet_printf(&connp2->c, "%d%d%d%d%d%d%d%d",
7573 i, cx1, cy1, cx2, cy2,
7574 w_ptr->cloud_dsum[i], w_ptr->cloud_xm100[i], w_ptr->cloud_ym100[i]);
7575 #endif
7576 // }
7577 }
7578 }
7579
7580 return n;
7581 }
7582
7583 int Send_inventory_revision(int Ind) {
7584 connection_t *connp = Conn[Players[Ind]->conn];
7585 player_type *p_ptr = Players[Ind];
7586
7587 if (!is_newer_than(&connp->version, 4, 4, 2, 1, 0, 0)) return(0);
7588
7589 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
7590 errno = 0;
7591 plog(format("Connection not ready for inventory revision (%d.%d.%d)",
7592 Ind, connp->state, connp->id));
7593 return 0;
7594 }
7595
7596 return Packet_printf(&connp->c, "%c%d", PKT_INVENTORY_REV, p_ptr->inventory_revision);
7597 }
7598
7599 int Send_account_info(int Ind) {
7600 connection_t *connp = Conn[Players[Ind]->conn];
7601 struct account *l_acc;
7602 u32b acc_flags = 0;
7603
7604 if (!is_newer_than(&connp->version, 4, 4, 2, 2, 0, 0)) return(0);
7605
7606 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
7607 errno = 0;
7608 plog(format("Connection not ready for account info (%d.%d.%d)",
7609 Ind, connp->state, connp->id));
7610 return 0;
7611 }
7612
7613 l_acc = GetAccount(connp->nick, NULL, FALSE);
7614 if (l_acc)
7615 {
7616 acc_flags = l_acc->flags;
7617 KILL(l_acc, struct account);
7618 }
7619
7620 return Packet_printf(&connp->c, "%c%hd", PKT_ACCOUNT_INFO, acc_flags);
7621 }
7622
7623 int Send_request_key(int Ind, int id, char *prompt) {
7624 connection_t *connp = Conn[Players[Ind]->conn];
7625
7626 if (!is_newer_than(&connp->version, 4, 4, 6, 1, 0, 0)) return(0);
7627 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
7628 errno = 0;
7629 plog(format("Connection not ready for request_key (%d.%d.%d)",
7630 Ind, connp->state, connp->id));
7631 return 0;
7632 }
7633
7634 Players[Ind]->request_id = id;
7635 Players[Ind]->request_type = RTYPE_KEY;
7636 return Packet_printf(&connp->c, "%c%d%s", PKT_REQUEST_KEY, id, prompt);
7637 }
7638 int Send_request_num(int Ind, int id, char *prompt, int std) {
7639 connection_t *connp = Conn[Players[Ind]->conn];
7640
7641 if (!is_newer_than(&connp->version, 4, 4, 6, 1, 0, 0)) return(0);
7642 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
7643 errno = 0;
7644 plog(format("Connection not ready for request_num (%d.%d.%d)",
7645 Ind, connp->state, connp->id));
7646 return 0;
7647 }
7648
7649 Players[Ind]->request_id = id;
7650 Players[Ind]->request_type = RTYPE_NUM;
7651 return Packet_printf(&connp->c, "%c%d%s%d", PKT_REQUEST_NUM, id, prompt, std);
7652 }
7653 void Send_delayed_request_str(int Ind, int id, char *prompt, char *std) {
7654 player_type *p_ptr = Players[Ind];
7655
7656 p_ptr->delay_str = cfg.fps / 2;//delay (turns)
7657 p_ptr->delay_str_id = id;
7658 strcpy(p_ptr->delay_str_prompt, prompt);
7659 strcpy(p_ptr->delay_str_std, std);
7660 }
7661 int Send_request_str(int Ind, int id, char *prompt, char *std) {
7662 connection_t *connp = Conn[Players[Ind]->conn];
7663
7664 if (!is_newer_than(&connp->version, 4, 4, 6, 1, 0, 0)) return(0);
7665 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
7666 errno = 0;
7667 plog(format("Connection not ready for request_str (%d.%d.%d)",
7668 Ind, connp->state, connp->id));
7669 return 0;
7670 }
7671
7672 Players[Ind]->request_id = id;
7673 Players[Ind]->request_type = RTYPE_STR;
7674 return Packet_printf(&connp->c, "%c%d%s%s", PKT_REQUEST_STR, id, prompt, std);
7675 }
7676 void Send_delayed_request_cfr(int Ind, int id, char *prompt, bool default_yes) {
7677 player_type *p_ptr = Players[Ind];
7678
7679 p_ptr->delay_cfr = cfg.fps / 2;//delay (turns)
7680 p_ptr->delay_cfr_id = id;
7681 strcpy(p_ptr->delay_cfr_prompt, prompt);
7682 p_ptr->delay_cfr_default_yes = default_yes;
7683 }
7684 int Send_request_cfr(int Ind, int id, char *prompt, bool default_yes) {
7685 connection_t *connp = Conn[Players[Ind]->conn];
7686
7687 if (!is_newer_than(&connp->version, 4, 4, 6, 1, 0, 0)) return(0);
7688 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
7689 errno = 0;
7690 plog(format("Connection not ready for request_cfr (%d.%d.%d)",
7691 Ind, connp->state, connp->id));
7692 return 0;
7693 }
7694
7695 Players[Ind]->request_id = id;
7696 Players[Ind]->request_type = RTYPE_CFR;
7697 if (is_newer_than(&connp->version, 4, 5, 6, 0, 0, 1))
7698 return Packet_printf(&connp->c, "%c%d%s%c", PKT_REQUEST_CFR, id, prompt, default_yes ? 1 : 0);
7699 else
7700 return Packet_printf(&connp->c, "%c%d%s", PKT_REQUEST_CFR, id, prompt);
7701 }
7702 /* NOTE: Should be followed by a p_ptr->request_id = RID_NONE to clean up. */
7703 int Send_request_abort(int Ind) {
7704 connection_t *connp = Conn[Players[Ind]->conn];
7705
7706 if (!is_newer_than(&connp->version, 4, 4, 6, 1, 0, 0)) return(0);
7707 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
7708 errno = 0;
7709 plog(format("Connection not ready for request_abort (%d.%d.%d)",
7710 Ind, connp->state, connp->id));
7711 return 0;
7712 }
7713
7714 return Packet_printf(&connp->c, "%c", PKT_REQUEST_ABORT);
7715 }
7716
7717 int Send_apply_auto_insc(int Ind, int slot) {
7718 connection_t *connp = Conn[Players[Ind]->conn];
7719
7720 if (!is_newer_than(&connp->version, 4, 5, 5, 0, 0, 0)) return(0);
7721 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
7722 errno = 0;
7723 plog(format("Connection not ready for request_apply_auto_insc (%d.%d.%d)",
7724 Ind, connp->state, connp->id));
7725 return 0;
7726 }
7727
7728 return Packet_printf(&connp->c, "%c%c", PKT_AUTOINSCRIBE, (char)slot);
7729 }
7730
7731 /*
7732 * Return codes for the "Receive_XXX" functions are as follows:
7733 *
7734 * -1 --> Some error occured
7735 * 0 --> The action was queued (not enough energy)
7736 * 1 --> The action was ignored (not enough energy)
7737 * 2 --> The action completed successfully
7738 * 3 --> The action has been queued and is blocking further actions that need to be queued
7739 *
7740 * Every code except for 1 will cause the input handler to stop
7741 * processing actions.
7742 */
7743
7744 // This does absolutly nothing other than keep our connection active.
7745 static int Receive_keepalive(int ind) {
7746 int n, Ind;
7747 connection_t *connp = Conn[ind];
7748 char ch;
7749 player_type *p_ptr;
7750
7751 if ((n = Packet_scanf(&connp->r, "%c", &ch)) <= 0) {
7752 if (n == -1) Destroy_connection(ind, "read error");
7753 return n;
7754 }
7755
7756 /* If client has not been hacked, this should set AFK after 1 minute
7757 of no activity. */
7758
7759 connp->inactive_keepalive++;
7760
7761 if (connp->id != -1) {
7762 Ind = GetInd[connp->id];
7763 p_ptr = Players[Ind];
7764
7765 p_ptr->idle += 2;
7766 p_ptr->idle_char += 2;
7767
7768 /* Kick a starving player */
7769 if (p_ptr->idle_starve_kick && p_ptr->food < PY_FOOD_WEAK && connp->inactive_keepalive > STARVE_KICK_TIMER / 2) {
7770 Destroy_connection(ind, STARVING_AUTOKICK_MSG);
7771 return 2;
7772 }
7773
7774 else if (!p_ptr->afk && p_ptr->auto_afk && connp->inactive_keepalive > AUTO_AFK_TIMER / 2) { /* dont oscillate ;) */
7775 /* auto AFK timer (>1 min) */
7776 // if (!p_ptr->resting) toggle_afk(Ind, ""); /* resting can take quite long sometimes */
7777 toggle_afk(Ind, "");
7778 }
7779 }
7780
7781 return 2;
7782 }
7783
7784 static int Receive_walk(int ind)
7785 {
7786 connection_t *connp = Conn[ind];
7787 player_type *p_ptr = NULL;
7788 char ch, dir;
7789 int n, player = -1;
7790
7791 if (connp->id != -1) {
7792 player = GetInd[connp->id];
7793 use_esp_link(&player, LINKF_MOV);
7794 p_ptr = Players[player];
7795 }
7796 else player = 0;
7797
7798 if ((n = Packet_scanf(&connp->r, "%c%c", &ch, &dir)) <= 0) {
7799 if (n == -1) Destroy_connection(ind, "read error");
7800 return n;
7801 }
7802
7803 /* Sanity check */
7804 if (bad_dir(dir)) return 1;
7805
7806
7807 /* bugged here if !p_ptr */
7808
7809 /* Disturb if running or resting */
7810 if (p_ptr->running || p_ptr->resting) {
7811 disturb(player, 0, 0);
7812 #if 0 /* disabled, because this would prevent 'walking/running out of fire-till-kill/auto-ret' which is a bit annoying: \
7813 it'd actually first just do disturb() here, so the player would have to attempt a second time to run/walk, after that. - C. Blue */
7814 return 1;
7815 #endif
7816 }
7817
7818 if (p_ptr->command_rep) p_ptr->command_rep = -1;
7819
7820 if (player && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
7821 if (p_ptr->warning_run < 3) {
7822 p_ptr->warning_run_steps++;
7823 /* Give a warning after first 10 walked steps, then every 50 walked steps. */
7824 if (p_ptr->warning_run_steps == 60) p_ptr->warning_run_steps = 10;
7825 if (p_ptr->warning_run_steps == 10) {
7826 msg_print(player, "\374\377oHINT: You can run swiftly by holding the \377RSHIFT\377o key when pressing a direction!");
7827 msg_print(player, "\374\377o To use this, the \377RNUMLOCK\377o key (labelled 'Num') must be turned off,");
7828 msg_print(player, "\374\377o and no awake monster must be in your line-of-sight (except in Bree).");
7829 s_printf("warning_run_steps: %s\n", p_ptr->name);
7830 }
7831 }
7832 do_cmd_walk(player, dir, p_ptr->always_pickup);
7833 return 2;
7834 } else {
7835 // Otherwise discared the walk request.
7836 //if (!connp->q.len && p_ptr->autoattack)
7837 // If we have no commands queued, then queue our walk request.
7838 // Note that ch might equal PKT_RUN, since Receive_run will
7839 // sometimes call this function.
7840 if (connp->q.len < 2) {
7841 Packet_printf(&connp->q, "%c%c", PKT_WALK, dir);
7842 return 0;
7843 } else {
7844 // If we have a walk command queued at the end of the queue,
7845 // then replace it with this queue request.
7846 if (connp->q.buf[connp->q.len - 2] == PKT_WALK) {
7847 connp->q.len -= 2;
7848 Packet_printf(&connp->q, "%c%c", PKT_WALK, dir);
7849 return 0;
7850 }
7851 }
7852 }
7853
7854 return 1;
7855 }
7856
7857 static int Receive_run(int ind) {
7858 connection_t *connp = Conn[ind];
7859 player_type *p_ptr = NULL;
7860 char ch;
7861 int i, n, player = -1;
7862 char dir;
7863 dun_level *l_ptr = NULL;
7864
7865 if (connp->id != -1) {
7866 player = GetInd[connp->id];
7867 use_esp_link(&player, LINKF_MOV);
7868 p_ptr = Players[player];
7869 l_ptr = getfloor(&p_ptr->wpos);
7870 }
7871
7872 /* paranoia? */
7873 // if (player == -1) return;
7874
7875 if (p_ptr->command_rep) p_ptr->command_rep = -1;
7876
7877 /* If not the dungeon master, who can always run */
7878 if (!p_ptr->admin_dm) {
7879 monster_race *r_ptr;
7880
7881 if ((p_ptr->global_event_temp & PEVF_NO_RUN_00)) return Receive_walk(ind);
7882 if (l_ptr && (l_ptr->flags2 & LF2_NO_RUN)) return Receive_walk(ind);
7883 if (in_sector00(&p_ptr->wpos) && (sector00flags2 & LF2_NO_RUN)) return Receive_walk(ind);
7884
7885 /* check for status impairments (lack of light is checked in run_test()) */
7886 if (p_ptr->confused || p_ptr->blind)
7887 return Receive_walk(ind);
7888
7889 /* Check for monsters in sight */
7890 for (i = 0; i < m_max; i++) {
7891 /* Check this monster */
7892 if (p_ptr->mon_los[i] && !m_list[i].csleep && !m_list[i].special
7893 /* not for Bree townies, Santa, Halloween townies, Target dummy */
7894 && !((r_ptr = race_inf(&m_list[i]))->flags8 & RF8_ALLOW_RUNNING)) {
7895 // Treat this as a walk request
7896 // Hack -- send the same connp->r "arguments" to Receive_walk
7897 if (p_ptr->warning_run_monlos == 0) {
7898 p_ptr->warning_run_monlos = 1;
7899 msg_print(player, "\374\377yNote: You cannot initiate running while you are within line-of-sight");
7900 msg_print(player, "\374\377y of an awake monster. The town of Bree is excepted from this.");
7901 s_printf("warning_run_monlos: %s\n", p_ptr->name);
7902 }
7903 return Receive_walk(ind);
7904 }
7905 }
7906
7907 #ifdef HOSTILITY_ABORTS_RUNNING
7908 /* Check for hostile players. They should be treated as a disturbance.
7909 * Should lessen the unfair advantage melee have in PVP */
7910 for (i = 1; i <= NumPlayers; i++) {
7911 if (i == player) continue;
7912 if (check_hostile(player, i)) {
7913 if (target_able(player, 0 - i)) { /* target_able takes in midx usually */
7914 return Receive_walk(ind);
7915 }
7916 }
7917 }
7918 #endif
7919 }
7920
7921 #if 0 /* with new fire-till-kill/auto-ret code that accepts <= 100% energy, and accordingly the new \
7922 p_ptr->requires_energy flag, this stuff should no longer be required and hence obsolete. - C. Blue */
7923 /* hack to fix 'movelock' bug, which occurs if a player tries to RUN away from a
7924 monster while he's currently auto-retaliating. (WALKING away instead of
7925 trying to run works by the way.)
7926 It doesn't matter if auto-retaliation is done by melee weaponry, shooting, or by spellcasting.
7927 The bug results in the player being unable to move until he clears the buffer with ')' key or
7928 (even while attacking) inscribes his item to stop auto-retaliating.
7929 So this fix checks for adjacent monsters and, if found, changes the run command to a walk
7930 command.
7931 Note that the bug ONLY happens if the player is auto-retaliating. Manual attacks are fine.
7932 The fix also makes kind of sense, since players can't run anyways while seeing a monster that's
7933 awake. And any monster that's auto-retaliated (if not a 'pseudo monster' which rensembles an
7934 inanimate object) should definitely be awake.
7935 Better solutions (that also fix the 'double energy' players have after performing no action
7936 for a turn and NEED for running) might take its place in the future. - C. Blue */
7937 //if (p_ptr->auto_retaliating) s_printf("auto-retal\n");
7938 //else s_printf("not a-r\n");
7939 // if (!p_ptr->admin_dm && p_ptr->auto_retaliating) {
7940 if (p_ptr->auto_retaliating || p_ptr->shooting_till_kill)
7941 return Receive_walk(ind);
7942 #endif
7943
7944
7945 if ((n = Packet_scanf(&connp->r, "%c%c", &ch, &dir)) <= 0) {
7946 if (n == -1)
7947 Destroy_connection(ind, "read error");
7948 return n;
7949 }
7950
7951 /* Sanity check */
7952 if (bad_dir(dir)) return 1;
7953
7954 /* Disturb if we want to change directions */
7955 //if (dir != p_ptr->find_current) disturb(player, 0, 0);
7956
7957 /* Hack -- Fix the running in '5' bug */
7958 if (dir == 5) return 1;
7959
7960 #if 0
7961 /* Only process the run command if we are not already running in
7962 * the direction requested.
7963 */
7964 if (player && (!p_ptr->running || (dir != p_ptr->find_current)))
7965 #endif
7966 {
7967 // If we don't want to queue the command, return now.
7968 if ((n = do_cmd_run(player, dir)) == 2) {
7969 return 2;
7970 }
7971 // If do_cmd_run returns a 0, then there wasn't enough energy
7972 // to execute the run command. Queue the run command if desired.
7973 else if (n == 0) {
7974 // Only buffer a run request if we have no previous commands
7975 // buffered, and it is a new direction or we aren't already
7976 // running.
7977 #if 0 /* changed so we can 'run' out of fire-till-kill'ing, even if we got there while we were already running - C. Blue */
7978 if (((!connp->q.len) && (dir != p_ptr->find_current)) || (!p_ptr->running)) {
7979 #else
7980 if (!connp->q.len) {
7981 #endif
7982 Packet_printf(&connp->q, "%c%c", ch, dir);
7983 return 0;
7984 }
7985 }
7986 }
7987
7988 return 1;
7989 }
7990
7991 int fake_Receive_tunnel(int Ind, int dir) {
7992 player_type *p_ptr = Players[Ind];
7993 connection_t *connp = Conn[p_ptr->conn];
7994
7995 /* all this is temp just to make it work */
7996 if (p_ptr->command_rep == -1) {
7997 p_ptr->command_rep = 0;
7998 return 0;
7999 }
8000
8001 /* please redesign ALL of this out of higher level */
8002 if (p_ptr->command_rep != PKT_TUNNEL) p_ptr->command_rep = -1;
8003
8004 if (p_ptr->energy >= level_speed(&p_ptr->wpos)) {
8005 do_cmd_tunnel(Ind, dir, FALSE);
8006 if (p_ptr->command_rep) Packet_printf(&connp->q, "%c%c", PKT_TUNNEL, dir);
8007
8008 return 2;
8009 }
8010
8011 Packet_printf(&connp->q, "%c%c", PKT_TUNNEL, dir);
8012 return 0;
8013 }
8014
8015 static int Receive_tunnel(int ind)
8016 {
8017 connection_t *connp = Conn[ind];
8018 player_type *p_ptr = NULL;
8019 char ch, dir;
8020 int n, player = -1;
8021
8022 if (connp->id != -1)
8023 {
8024 player = GetInd[connp->id];
8025 use_esp_link(&player, LINKF_MOV);
8026 p_ptr = Players[player];
8027 }
8028
8029 if ((n = Packet_scanf(&connp->r, "%c%c", &ch, &dir)) <= 0)
8030 {
8031 if (n == -1)
8032 Destroy_connection(ind, "read error");
8033 return n;
8034 }
8035
8036 if (!p_ptr) return 1;
8037
8038 /* Sanity check */
8039 if (bad_dir(dir)) return 1;
8040
8041 /* all this is temp just to make it work */
8042 if (p_ptr->command_rep == -1) {
8043 p_ptr->command_rep = 0;
8044 return 0;
8045 }
8046
8047 /* please redesign ALL of this out of higher level */
8048 if (p_ptr->command_rep != PKT_TUNNEL) p_ptr->command_rep = -1;
8049
8050 if (p_ptr->energy >= level_speed(&p_ptr->wpos)) {
8051 do_cmd_tunnel(player, dir, FALSE);
8052 if (p_ptr->command_rep) Packet_printf(&connp->q, "%c%c", ch, dir);
8053
8054 return 2;
8055 }
8056
8057 Packet_printf(&connp->q, "%c%c", ch, dir);
8058 return 0;
8059 }
8060
8061 static int Receive_aim_wand(int ind)
8062 {
8063 connection_t *connp = Conn[ind];
8064 player_type *p_ptr = NULL;
8065 char ch, dir;
8066 s16b item;
8067 int n, player = -1;
8068
8069 if (connp->id != -1) {
8070 player = GetInd[connp->id];
8071 use_esp_link(&player, LINKF_OBJ);
8072 p_ptr = Players[player];
8073 }
8074
8075 if ((n = Packet_scanf(&connp->r, "%c%hd%c", &ch, &item, &dir)) <= 0) {
8076 if (n == -1) Destroy_connection(ind, "read error");
8077 return n;
8078 }
8079
8080 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
8081 /* Sanity check - mikaelh */
8082 if (item >= INVEN_TOTAL) return 1;
8083 if (bad_dir1(player, &dir)) return 1;
8084
8085 item = replay_inven_changes(player, item);
8086 if (item == 0xFF) {
8087 msg_print(player, "Command failed because item is gone.");
8088 return 1;
8089 }
8090
8091 do_cmd_aim_wand(player, item, dir);
8092 return 2;
8093 } else if (p_ptr) {
8094 Packet_printf(&connp->q, "%c%hd%c", ch, item, dir);
8095 return 0;
8096 }
8097
8098 return 1;
8099 }
8100
8101 static int Receive_drop(int ind)
8102 {
8103 connection_t *connp = Conn[ind];
8104 player_type *p_ptr = NULL;
8105 char ch;
8106 int n, player = -1;
8107 s16b item, amt;
8108
8109 if (connp->id != -1)
8110 {
8111 player = GetInd[connp->id];
8112 use_esp_link(&player, LINKF_OBJ);
8113 p_ptr = Players[player];
8114 }
8115
8116 if ((n = Packet_scanf(&connp->r, "%c%hd%hd", &ch, &item, &amt)) <= 0)
8117 {
8118 if (n == -1)
8119 Destroy_connection(ind, "read error");
8120 return n;
8121 }
8122
8123 /* Sanity check - mikaelh */
8124 if (item >= INVEN_TOTAL)
8125 return 1;
8126
8127 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos))
8128 {
8129 item = replay_inven_changes(player, item);
8130 if (item == 0xFF)
8131 {
8132 msg_print(player, "Command failed because item is gone.");
8133 return 1;
8134 }
8135
8136 do_cmd_drop(player, item, amt);
8137 return 2;
8138 }
8139 else if (p_ptr)
8140 {
8141 Packet_printf(&connp->q, "%c%hd%hd", ch, item, amt);
8142 return 0;
8143 }
8144
8145 return 1;
8146 }
8147
8148 static int Receive_fire(int ind)
8149 {
8150 connection_t *connp = Conn[ind];
8151 player_type *p_ptr = NULL;
8152 char ch, dir = 5;
8153 int n, player = -1;
8154 //s16b item;
8155
8156 if (connp->id != -1) {
8157 player = GetInd[connp->id];
8158 use_esp_link(&player, LINKF_OBJ);
8159 p_ptr = Players[player];
8160 }
8161
8162 // if ((n = Packet_scanf(&connp->r, "%c%c%hd", &ch, &dir, &item)) <= 0)
8163 if ((n = Packet_scanf(&connp->r, "%c%c", &ch, &dir)) <= 0) {
8164 if (n == -1)
8165 Destroy_connection(ind, "read error");
8166 return n;
8167 }
8168
8169 /* Check confusion */
8170 if (p_ptr->confused) {
8171 /* Change firing direction */
8172 /* no targetted shooting anymore while confused! */
8173 dir = randint(8);
8174 if (dir >= 5) dir++;
8175 }
8176
8177 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos) / p_ptr->num_fire) {
8178 /* Sanity check */
8179 if (bad_dir1(player, &dir)) return 1;
8180
8181 if (p_ptr->shoot_till_kill && dir == 5) p_ptr->shooty_till_kill = TRUE;
8182 // do_cmd_fire(player, dir, item);
8183 do_cmd_fire(player, dir);
8184 if (!(p_ptr->shoot_till_kill && dir == 5 && !p_ptr->shooting_till_kill)) {
8185 if (p_ptr->ranged_double) do_cmd_fire(player, dir);
8186 }
8187 p_ptr->shooty_till_kill = FALSE;
8188 return 2;
8189 } else if (p_ptr) {
8190 // Packet_printf(&connp->q, "%c%c%hd", ch, dir, item);
8191 Packet_printf(&connp->q, "%c%c", ch, dir);
8192 return 0;
8193 }
8194
8195 return 1;
8196 }
8197
8198 static int Receive_observe(int ind)
8199 {
8200 connection_t *connp = Conn[ind];
8201 player_type *p_ptr = NULL;
8202
8203 char ch;
8204
8205 s16b item;
8206
8207 int n, player = -1;
8208
8209 if (connp->id != -1)
8210 {
8211 player = GetInd[connp->id];
8212 p_ptr = Players[player];
8213 }
8214
8215 if ((n = Packet_scanf(&connp->r, "%c%hd", &ch, &item)) <= 0)
8216 {
8217 if (n == -1)
8218 Destroy_connection(ind, "read error");
8219 return n;
8220 }
8221
8222 /* Sanity check - mikaelh */
8223 if (item >= INVEN_TOTAL)
8224 return 1;
8225
8226 if (p_ptr)
8227 do_cmd_observe(player, item);
8228
8229 return 1;
8230 }
8231
8232 static int Receive_stand(int ind)
8233 {
8234 connection_t *connp = Conn[ind];
8235 player_type *p_ptr = NULL;
8236 char ch;
8237 int n, player = -1;
8238
8239 if (connp->id != -1) {
8240 player = GetInd[connp->id];
8241 use_esp_link(&player, LINKF_MOV);
8242 p_ptr = Players[player];
8243 }
8244
8245 if ((n = Packet_scanf(&connp->r, "%c", &ch)) <= 0) {
8246 if (n == -1) Destroy_connection(ind, "read error");
8247 return n;
8248 }
8249
8250 // if (p_ptr) { /* disallow picking up items while paralyzed: */
8251 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
8252 do_cmd_stay(player, 1);
8253 return 2;
8254 } else if (p_ptr) {
8255 Packet_printf(&connp->q, "%c", ch);
8256 return 0;
8257 }
8258
8259 return -1;
8260 }
8261
8262 static int Receive_destroy(int ind)
8263 {
8264 connection_t *connp = Conn[ind];
8265 player_type *p_ptr = NULL;
8266 char ch;
8267 s16b item, amt;
8268 int n, player = -1;
8269
8270 if (connp->id != -1)
8271 {
8272 player = GetInd[connp->id];
8273 use_esp_link(&player, LINKF_OBJ);
8274 p_ptr = Players[player];
8275 }
8276
8277 if ((n = Packet_scanf(&connp->r, "%c%hd%hd", &ch, &item, &amt)) <= 0)
8278 {
8279 if (n == -1)
8280 Destroy_connection(ind, "read error");
8281 return n;
8282 }
8283
8284 /* Sanity check - mikaelh */
8285 if (item >= INVEN_TOTAL)
8286 return 1;
8287
8288 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
8289 item = replay_inven_changes(player, item);
8290 if (item == 0xFF) {
8291 msg_print(player, "Command failed because item is gone.");
8292 return 1;
8293 }
8294
8295 do_cmd_destroy(player, item, amt);
8296 return 2;
8297 } else if (p_ptr) {
8298 Packet_printf(&connp->q, "%c%hd%hd", ch, item, amt);
8299 return 0;
8300 }
8301
8302 return 1;
8303 }
8304
8305 static int Receive_look(int ind)
8306 {
8307 connection_t *connp = Conn[ind];
8308 player_type *p_ptr = NULL;
8309 char ch;
8310 s16b dir;
8311 int n, player = -1;
8312
8313 if (connp->id != -1) {
8314 player = GetInd[connp->id];
8315 use_esp_link(&player, LINKF_OBJ);
8316 p_ptr = Players[player];
8317 }
8318
8319 if (is_older_than(&p_ptr->version, 4, 4, 9, 4, 0, 0)) {
8320 char old_dir;
8321 if ((n = Packet_scanf(&connp->r, "%c%c", &ch, &old_dir)) <= 0) {
8322 if (n == -1) Destroy_connection(ind, "read error");
8323 return n;
8324 }
8325 dir = old_dir;
8326 } else { /* for 'p' feature (manual ground-targetting) */
8327 if ((n = Packet_scanf(&connp->r, "%c%hd", &ch, &dir)) <= 0) {
8328 if (n == -1) Destroy_connection(ind, "read error");
8329 return n;
8330 }
8331 }
8332
8333 /* Sanity check */
8334 if (bad_dir(dir) && bad_dir2(dir)) return 1;
8335
8336 if (p_ptr) {
8337 do_cmd_look(player, dir);
8338 }
8339
8340 return 1;
8341 }
8342
8343 /*
8344 * Possibly, most of Receive_* functions can be bandled into one function
8345 * like this; that'll make the client *MUCH* more generic. - Jir -
8346 */
8347 static int Receive_activate_skill(int ind) {
8348 connection_t *connp = Conn[ind];
8349 player_type *p_ptr = NULL;
8350 char ch, mkey, dir;
8351 int n, player = -1, old = -1;
8352 s16b book, spell, item, aux;
8353
8354 if (connp->id != -1) {
8355 player = GetInd[connp->id];
8356 old = player;
8357 use_esp_link(&player, LINKF_OBJ);
8358 p_ptr = Players[player];
8359 }
8360
8361 if ((n = Packet_scanf(&connp->r, "%c%c%hd%hd%c%hd%hd", &ch, &mkey, &book, &spell, &dir, &item, &aux)) <= 0) {
8362 if (n == -1) Destroy_connection(ind, "read error");
8363 return n;
8364 }
8365
8366 /* Not by class nor by item; by skill */
8367 if (p_ptr &&
8368 (p_ptr->energy >= level_speed(&p_ptr->wpos) ||
8369 /* some abilities don't require energy: */
8370 mkey == MKEY_DODGE || mkey == MKEY_PARRYBLOCK ||
8371 mkey == MKEY_SHOOT_TILL_KILL || mkey == MKEY_DUAL_MODE)) {
8372 /* Sanity check - mikaelh */
8373 if (item >= INVEN_TOTAL) return 1;
8374 if (bad_dir3(player, &dir)) return 1;
8375
8376
8377 p_ptr->current_char = (old == player) ? TRUE : FALSE;
8378
8379 if (p_ptr->ghost && !is_admin(p_ptr)) {
8380 msg_print(player, "\377oYou need your body to use a skill.");
8381 return 2;
8382 }
8383
8384 #if 0
8385 /* Break goi/manashield */
8386 if (mkey != MKEY_DODGE) { // it's not real 'activation'
8387 if (p_ptr->invuln) set_invuln(player, 0);
8388 if (p_ptr->tim_manashield) set_tim_manashield(player, 0);
8389 }
8390 #endif
8391
8392 switch (mkey) {
8393 case MKEY_MIMICRY:
8394 if (get_skill(p_ptr, SKILL_MIMIC)) {
8395 if (spell == 20000 && dir) {
8396 switch (dir) {
8397 case 1:
8398 switch (p_ptr->mimic_immunity) {
8399 case 0:
8400 msg_print(player, "\377WCurrently you don't have any preferred form immunity.");
8401 break;
8402 case 1:
8403 msg_print(player, "\377WYour current immunity preference is \377blightning.");
8404 break;
8405 case 2:
8406 msg_print(player, "\377WYour current immunity preference is \377wfrost.");
8407 break;
8408 case 3:
8409 msg_print(player, "\377WYour current immunity preference is \377sacid.");
8410 break;
8411 case 4:
8412 msg_print(player, "\377WYour current immunity preference is \377rfire.");
8413 break;
8414 case 5:
8415 msg_print(player, "\377WYour current immunity preference is \377gpoison.");
8416 break;
8417 case 6:
8418 msg_print(player, "\377WYour current immunity preference is \377Bwater.");
8419 break;
8420 }
8421 break;
8422 case 2:
8423 p_ptr->mimic_immunity = 0;
8424 msg_print(player, "\377WYou no longer have any preferred form immunity.");
8425 break;
8426 case 3:
8427 p_ptr->mimic_immunity = 1;
8428 msg_print(player, "\377WPreferred form immunity is now \377blightning.");
8429 if (p_ptr->body_monster &&
8430 (r_info[p_ptr->body_monster].flags3 & RF3_IM_ELEC))
8431 calc_boni(player);
8432 break;
8433 case 4:
8434 p_ptr->mimic_immunity = 2;
8435 msg_print(player, "\377WPreferred form immunity is now \377wfrost.");
8436 if (p_ptr->body_monster &&
8437 (r_info[p_ptr->body_monster].flags3 & RF3_IM_COLD))
8438 calc_boni(player);
8439 break;
8440 case 5:
8441 p_ptr->mimic_immunity = 3;
8442 msg_print(player, "\377WPreferred form immunity is now \377sacid.");
8443 if (p_ptr->body_monster &&
8444 (r_info[p_ptr->body_monster].flags3 & RF3_IM_ACID))
8445 calc_boni(player);
8446 break;
8447 case 6:
8448 p_ptr->mimic_immunity = 4;
8449 msg_print(player, "\377WPreferred form immunity is now \377rfire.");
8450 if (p_ptr->body_monster &&
8451 (r_info[p_ptr->body_monster].flags3 & RF3_IM_FIRE))
8452 calc_boni(player);
8453 break;
8454 case 7:
8455 p_ptr->mimic_immunity = 5;
8456 msg_print(player, "\377WPreferred form immunity is now \377gpoison.");
8457 if (p_ptr->body_monster &&
8458 (r_info[p_ptr->body_monster].flags3 & RF3_IM_POIS))
8459 calc_boni(player);
8460 break;
8461 case 8:
8462 p_ptr->mimic_immunity = 6;
8463 msg_print(player, "\377WPreferred form immunity is now \377Bwater.");
8464 if (p_ptr->body_monster &&
8465 (r_info[p_ptr->body_monster].flags9 & RF9_IM_WATER))
8466 calc_boni(player);
8467 break;
8468 default:
8469 msg_print(player, "\377yThat immunity does not exist.");
8470 break;
8471 }
8472 return 2;
8473 }
8474 if (p_ptr->shoot_till_kill && dir == 5) p_ptr->shooty_till_kill = TRUE;
8475 do_cmd_mimic(player, spell, dir);
8476 p_ptr->shooty_till_kill = FALSE;
8477 }
8478 break;
8479
8480 case MKEY_DODGE:
8481 use_ability_blade(player);
8482 break;
8483 case MKEY_FLETCHERY:
8484 do_cmd_fletchery(player);
8485 break;
8486 #ifdef ENABLE_STANCES
8487 case MKEY_STANCE:
8488 do_cmd_stance(player, book);
8489 break;
8490 #endif
8491 #ifdef ENABLE_NEW_MELEE
8492 case MKEY_PARRYBLOCK:
8493 check_parryblock(player);
8494 break;
8495 #endif
8496 case MKEY_TRAP:
8497 do_cmd_set_trap(player, book, spell);
8498 break;
8499 case MKEY_SCHOOL:
8500 book = replay_inven_changes(player, book);
8501 if (book == 0xFF) {
8502 msg_print(player, "Command failed because item is gone.");
8503 return 1;
8504 }
8505 item = replay_inven_changes(player, item);
8506 if (item == 0xFF) {
8507 msg_print(player, "Command failed because item is gone.");
8508 return 1;
8509 }
8510
8511 /* Sanity check #2 */
8512 if (dir == -1) dir = 5;
8513
8514 if (p_ptr->shoot_till_kill && dir == 5) p_ptr->shooty_till_kill = TRUE;
8515 cast_school_spell(player, book, spell, dir, item, aux);
8516 p_ptr->shooty_till_kill = FALSE;
8517 break;
8518
8519 case MKEY_RCRAFT:
8520 /* Sanity check #2 */
8521 if (dir == -1) dir = 5;
8522
8523 if (p_ptr->shoot_till_kill && dir == 5) p_ptr->shooty_till_kill = TRUE;
8524 (void)cast_rune_spell(player, dir, (u16b)book, (u16b)spell, (u16b)item, 0);
8525 p_ptr->shooty_till_kill = FALSE;
8526 break;
8527
8528 case MKEY_AURA_FEAR:
8529 toggle_aura(player, 0);
8530 break;
8531 case MKEY_AURA_SHIVER:
8532 toggle_aura(player, 1);
8533 break;
8534 case MKEY_AURA_DEATH:
8535 toggle_aura(player, 2);
8536 break;
8537
8538 case MKEY_MELEE:
8539 do_cmd_melee_technique(player, spell);
8540 break;
8541 case MKEY_RANGED:
8542 do_cmd_ranged_technique(player, spell);
8543 break;
8544 case MKEY_SHOOT_TILL_KILL:
8545 toggle_shoot_till_kill(player);
8546 break;
8547 #ifdef DUAL_WIELD
8548 case MKEY_DUAL_MODE:
8549 toggle_dual_mode(player);
8550 break;
8551 #endif
8552 case MKEY_BREATH:
8553 /* Sanity check #2 */
8554 if (dir == -1) dir = 5;
8555
8556 //do_cmd_breathe(player);
8557 do_cmd_breathe_aux(player, dir);
8558 break;
8559 }
8560 return 2;
8561 } else if (p_ptr) {
8562 p_ptr->current_spell = -1;
8563 p_ptr->current_mind = -1;
8564 Packet_printf(&connp->q, "%c%c%hd%hd%c%hd%hd", ch, mkey, book, spell, dir, item, aux);
8565 return 0;
8566 }
8567
8568
8569 return 1;
8570 }
8571
8572 static int Receive_open(int ind)
8573 {
8574 connection_t *connp = Conn[ind];
8575 player_type *p_ptr = NULL;
8576 char ch, dir;
8577 int n, player = -1;
8578
8579 if (connp->id != -1) {
8580 player = GetInd[connp->id];
8581 use_esp_link(&player, LINKF_OBJ);
8582 p_ptr = Players[player];
8583 }
8584
8585 if ((n = Packet_scanf(&connp->r, "%c%c", &ch, &dir)) <= 0) {
8586 if (n == -1)
8587 Destroy_connection(ind, "read error");
8588 return n;
8589 }
8590
8591 /* Sanity check */
8592 if (bad_dir(dir)) return 1;
8593
8594 /* all this is temp just to make it work */
8595 if (p_ptr->command_rep == -1) {
8596 p_ptr->command_rep = 0;
8597 return 0;
8598 }
8599 if (p_ptr && p_ptr->command_rep != PKT_OPEN)
8600 p_ptr->command_rep = -1;
8601
8602 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
8603 do_cmd_open(player, dir);
8604 if (p_ptr->command_rep) Packet_printf(&connp->q, "%c%c", ch, dir);
8605 return 2;
8606 } else if (p_ptr) {
8607 Packet_printf(&connp->q, "%c%c", ch, dir);
8608 return 0;
8609 }
8610
8611 return 1;
8612 }
8613
8614 static int Receive_mind(int ind)
8615 {
8616 connection_t *connp = Conn[ind];
8617 char ch;
8618 int n, player = 0;
8619
8620 if (connp->id != -1) player = GetInd[connp->id];
8621
8622 if ((n = Packet_scanf(&connp->r, "%c", &ch)) <= 0) {
8623 if (n == -1) Destroy_connection(ind, "read error");
8624 return n;
8625 }
8626
8627 if (player) {
8628 change_mind(player, TRUE);
8629 return 2;
8630 }
8631 return 1;
8632 }
8633
8634 static int Receive_ghost(int ind)
8635 {
8636 connection_t *connp = Conn[ind];
8637 player_type *p_ptr = NULL;
8638
8639 char ch;
8640
8641 int n, player = -1;
8642
8643 s16b ability;
8644
8645 if (connp->id != -1)
8646 {
8647 player = GetInd[connp->id];
8648 p_ptr = Players[player];
8649 }
8650
8651 if ((n = Packet_scanf(&connp->r, "%c%hd", &ch, &ability)) <= 0)
8652 {
8653 if (n == -1)
8654 Destroy_connection(ind, "read error");
8655 return n;
8656 }
8657
8658 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos))
8659 {
8660 do_cmd_ghost_power(player, ability);
8661 return 2;
8662 }
8663 else if (p_ptr)
8664 {
8665 Packet_printf(&connp->q, "%c%hd", ch, ability);
8666 return 0;
8667 }
8668
8669 return 1;
8670 }
8671
8672 static int Receive_quaff(int ind)
8673 {
8674 connection_t *connp = Conn[ind];
8675 player_type *p_ptr = NULL;
8676 char ch;
8677 s16b item;
8678 int n, player = -1;
8679
8680 if (connp->id != -1)
8681 {
8682 player = GetInd[connp->id];
8683 use_esp_link(&player, LINKF_OBJ);
8684 p_ptr = Players[player];
8685 }
8686
8687 if ((n = Packet_scanf(&connp->r, "%c%hd", &ch, &item)) <= 0)
8688 {
8689 if (n == -1)
8690 Destroy_connection(ind, "read error");
8691 return n;
8692 }
8693
8694 /* Sanity check - mikaelh */
8695 if (item >= INVEN_TOTAL)
8696 return 1;
8697
8698 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos))
8699 {
8700 item = replay_inven_changes(player, item);
8701 if (item == 0xFF)
8702 {
8703 msg_print(player, "Command failed because item is gone.");
8704 return 1;
8705 }
8706
8707 do_cmd_quaff_potion(player, item);
8708 return 2;
8709 }
8710 else if (p_ptr)
8711 {
8712 Packet_printf(&connp->q, "%c%hd", ch, item);
8713 return 0;
8714 }
8715
8716 return 1;
8717 }
8718
8719 static int Receive_read(int ind)
8720 {
8721 connection_t *connp = Conn[ind];
8722 player_type *p_ptr = NULL;
8723 char ch;
8724 s16b item;
8725 int n, player = -1;
8726
8727 if (connp->id != -1)
8728 {
8729 player = GetInd[connp->id];
8730 use_esp_link(&player, LINKF_OBJ);
8731 p_ptr = Players[player];
8732 }
8733
8734 if ((n = Packet_scanf(&connp->r, "%c%hd", &ch, &item)) <= 0)
8735 {
8736 if (n == -1)
8737 Destroy_connection(ind, "read error");
8738 return n;
8739 }
8740
8741 /* Sanity check - mikaelh */
8742 if (item >= INVEN_TOTAL)
8743 return 1;
8744
8745 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos))
8746 {
8747 item = replay_inven_changes(player, item);
8748 if (item == 0xFF)
8749 {
8750 msg_print(player, "Command failed because item is gone.");
8751 return 1;
8752 }
8753
8754 do_cmd_read_scroll(player, item);
8755 return 2;
8756 }
8757 else if (p_ptr)
8758 {
8759 Packet_printf(&connp->q, "%c%hd", ch, item);
8760 return 0;
8761 }
8762
8763 return 1;
8764 }
8765
8766 static int Receive_search(int ind)
8767 {
8768 connection_t *connp = Conn[ind];
8769 player_type *p_ptr = NULL;
8770 char ch;
8771 int n, player = -1;
8772
8773 if (connp->id != -1) {
8774 player = GetInd[connp->id];
8775 use_esp_link(&player, LINKF_MOV);
8776 p_ptr = Players[player];
8777 }
8778
8779 if ((n = Packet_scanf(&connp->r, "%c", &ch)) <= 0) {
8780 if (n == -1)
8781 Destroy_connection(ind, "read error");
8782 return n;
8783 }
8784
8785 /* all this is temp just to make it work */
8786 if (p_ptr->command_rep == -1) {
8787 p_ptr->command_rep = 0;
8788 return(0);
8789 }
8790 if (p_ptr && p_ptr->command_rep != PKT_SEARCH) {
8791 p_ptr->command_rep = -1;
8792 }
8793
8794 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
8795 do_cmd_search(player);
8796 if (p_ptr->command_rep) Packet_printf(&connp->q, "%c", ch);
8797 return 2;
8798 } else if (p_ptr) {
8799 Packet_printf(&connp->q, "%c", ch);
8800 return 0;
8801 }
8802
8803 return 1;
8804 }
8805
8806 static int Receive_take_off(int ind)
8807 {
8808 connection_t *connp = Conn[ind];
8809 player_type *p_ptr = NULL;
8810 char ch;
8811 s16b item;
8812 int n, player = -1;
8813
8814 if (connp->id != -1) {
8815 player = GetInd[connp->id];
8816 use_esp_link(&player, LINKF_OBJ);
8817 p_ptr = Players[player];
8818 }
8819
8820 if ((n = Packet_scanf(&connp->r, "%c%hd", &ch, &item)) <= 0) {
8821 if (n == -1) Destroy_connection(ind, "read error");
8822 return n;
8823 }
8824
8825 /* Sanity check - mikaelh */
8826 if (item >= INVEN_TOTAL)
8827 return 1;
8828
8829 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos))
8830 {
8831 item = replay_inven_changes(player, item);
8832 if (item == 0xFF)
8833 {
8834 msg_print(player, "Command failed because item is gone.");
8835 return 1;
8836 }
8837
8838 do_cmd_takeoff(player, item, 255);
8839 return 2;
8840 }
8841 else if (p_ptr)
8842 {
8843 Packet_printf(&connp->q, "%c%hd", ch, item);
8844 return 0;
8845 }
8846
8847 return 1;
8848 }
8849
8850 static int Receive_take_off_amt(int ind)
8851 {
8852 connection_t *connp = Conn[ind];
8853 player_type *p_ptr = NULL;
8854 char ch;
8855 s16b item, amt;
8856 int n, player = -1;
8857
8858 if (connp->id != -1)
8859 {
8860 player = GetInd[connp->id];
8861 use_esp_link(&player, LINKF_OBJ);
8862 p_ptr = Players[player];
8863 }
8864
8865 if ((n = Packet_scanf(&connp->r, "%c%hd%hd", &ch, &item, &amt)) <= 0)
8866 {
8867 if (n == -1)
8868 Destroy_connection(ind, "read error");
8869 return n;
8870 }
8871
8872 /* Sanity check - mikaelh */
8873 if (item >= INVEN_TOTAL)
8874 return 1;
8875
8876 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos))
8877 {
8878 item = replay_inven_changes(player, item);
8879 if (item == 0xFF)
8880 {
8881 msg_print(player, "Command failed because item is gone.");
8882 return 1;
8883 }
8884
8885 do_cmd_takeoff(player, item, amt);
8886 return 2;
8887 }
8888 else if (p_ptr)
8889 {
8890 Packet_printf(&connp->q, "%c%hd%hd", ch, item, amt);
8891 return 0;
8892 }
8893
8894 return 1;
8895 }
8896
8897 static int Receive_use(int ind)
8898 {
8899 connection_t *connp = Conn[ind];
8900 player_type *p_ptr = NULL;
8901 char ch;
8902 s16b item;
8903 int n, player = -1;
8904
8905 if (connp->id != -1)
8906 {
8907 player = GetInd[connp->id];
8908 use_esp_link(&player, LINKF_OBJ);
8909 p_ptr = Players[player];
8910 }
8911
8912 if ((n = Packet_scanf(&connp->r, "%c%hd", &ch, &item)) <= 0)
8913 {
8914 if (n == -1)
8915 Destroy_connection(ind, "read error");
8916 return n;
8917 }
8918
8919 /* Sanity check - mikaelh */
8920 if (item >= INVEN_TOTAL)
8921 return 1;
8922
8923 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos))
8924 {
8925 item = replay_inven_changes(player, item);
8926 if (item == 0xFF)
8927 {
8928 msg_print(player, "Command failed because item is gone.");
8929 return 1;
8930 }
8931
8932 do_cmd_use_staff(player, item);
8933 return 2;
8934 }
8935 else if (p_ptr)
8936 {
8937 Packet_printf(&connp->q, "%c%hd", ch, item);
8938 return 0;
8939 }
8940
8941 return 1;
8942 }
8943
8944 static int Receive_throw(int ind)
8945 {
8946 connection_t *connp = Conn[ind];
8947 player_type *p_ptr = NULL;
8948 char ch, dir;
8949 int n, player = -1;
8950 s16b item;
8951
8952 if (connp->id != -1) {
8953 player = GetInd[connp->id];
8954 use_esp_link(&player, LINKF_OBJ);
8955 p_ptr = Players[player];
8956 }
8957
8958 if ((n = Packet_scanf(&connp->r, "%c%c%hd", &ch, &dir, &item)) <= 0) {
8959 if (n == -1)
8960 Destroy_connection(ind, "read error");
8961 return n;
8962 }
8963
8964 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
8965 /* Sanity check - mikaelh */
8966 if (item >= INVEN_TOTAL) return 1;
8967 if (bad_dir1(player, &dir)) return 1;
8968
8969 item = replay_inven_changes(player, item);
8970 if (item == 0xFF) {
8971 msg_print(player, "Command failed because item is gone.");
8972 return 1;
8973 }
8974
8975 do_cmd_throw(player, dir, item, 0);
8976 return 2;
8977 } else if (p_ptr) {
8978 Packet_printf(&connp->q, "%c%c%hd", ch, dir, item);
8979 return 0;
8980 }
8981
8982 return 1;
8983 }
8984
8985 static int Receive_wield(int ind)
8986 {
8987 connection_t *connp = Conn[ind];
8988 player_type *p_ptr = NULL;
8989 char ch;
8990 s16b item;
8991 int n, player = -1;
8992
8993 if (connp->id != -1)
8994 {
8995 player = GetInd[connp->id];
8996 use_esp_link(&player, LINKF_OBJ);
8997 p_ptr = Players[player];
8998 }
8999
9000 if ((n = Packet_scanf(&connp->r, "%c%hd", &ch, &item)) <= 0)
9001 {
9002 if (n == -1)
9003 Destroy_connection(ind, "read error");
9004 return n;
9005 }
9006
9007 /* Sanity check - mikaelh */
9008 if (item >= INVEN_TOTAL) return 1;
9009
9010 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos))
9011 {
9012 item = replay_inven_changes(player, item);
9013 if (item == 0xFF)
9014 {
9015 msg_print(player, "Command failed because item is gone.");
9016 return 1;
9017 }
9018
9019 do_cmd_wield(player, item, 0x0);
9020 return 2;
9021 }
9022 else if (p_ptr)
9023 {
9024 Packet_printf(&connp->q, "%c%hd", ch, item);
9025 return 0;
9026 }
9027
9028 return 1;
9029 }
9030
9031 static int Receive_zap(int ind)
9032 {
9033 connection_t *connp = Conn[ind];
9034 player_type *p_ptr = NULL;
9035 char ch;
9036 s16b item;
9037 int n, player = -1;
9038
9039 if (connp->id != -1)
9040 {
9041 player = GetInd[connp->id];
9042 use_esp_link(&player, LINKF_OBJ);
9043 p_ptr = Players[player];
9044 }
9045
9046 if ((n = Packet_scanf(&connp->r, "%c%hd", &ch, &item)) <= 0)
9047 {
9048 if (n == -1)
9049 Destroy_connection(ind, "read error");
9050 return n;
9051 }
9052
9053 /* Sanity check - mikaelh */
9054 if (item >= INVEN_TOTAL)
9055 return 1;
9056
9057 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos))
9058 {
9059 item = replay_inven_changes(player, item);
9060 if (item == 0xFF)
9061 {
9062 msg_print(player, "Command failed because item is gone.");
9063 return 1;
9064 }
9065
9066 do_cmd_zap_rod(player, item, 0);
9067 return 2;
9068 }
9069 else if (p_ptr)
9070 {
9071 Packet_printf(&connp->q, "%c%hd", ch, item);
9072 return 0;
9073 }
9074
9075 return 1;
9076 }
9077
9078 static int Receive_zap_dir(int ind)
9079 {
9080 connection_t *connp = Conn[ind];
9081 player_type *p_ptr = NULL;
9082 char ch, dir;
9083 s16b item;
9084 int n, player = -1;
9085
9086 if (connp->id != -1) {
9087 player = GetInd[connp->id];
9088 use_esp_link(&player, LINKF_OBJ);
9089 p_ptr = Players[player];
9090 }
9091
9092 if ((n = Packet_scanf(&connp->r, "%c%hd%c", &ch, &item, &dir)) <= 0) {
9093 if (n == -1)
9094 Destroy_connection(ind, "read error");
9095 return n;
9096 }
9097
9098 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
9099 /* Sanity check - mikaelh */
9100 if (item >= INVEN_TOTAL) return 1;
9101 if (bad_dir1(player, &dir)) return 1;
9102
9103 item = replay_inven_changes(player, item);
9104 if (item == 0xFF) {
9105 msg_print(player, "Command failed because item is gone.");
9106 return 1;
9107 }
9108
9109 do_cmd_zap_rod(player, item, dir);
9110 return 2;
9111 } else if (p_ptr) {
9112 Packet_printf(&connp->q, "%c%hd%c", ch, item, dir);
9113 return 0;
9114 }
9115
9116 return 1;
9117 }
9118
9119 static int Receive_target(int ind)
9120 {
9121 connection_t *connp = Conn[ind];
9122 player_type *p_ptr = NULL;
9123 char ch;
9124 s16b dir;
9125 int n, player = -1;
9126
9127 if (connp->id != -1)
9128 {
9129 player = GetInd[connp->id];
9130 use_esp_link(&player, LINKF_OBJ);
9131 p_ptr = Players[player];
9132 }
9133
9134 if ((n = Packet_scanf(&connp->r, "%c%hd", &ch, &dir)) <= 0)
9135 {
9136 if (n == -1)
9137 Destroy_connection(ind, "read error");
9138 return n;
9139 }
9140
9141 /* Sanity check */
9142 if (bad_dir(dir) && bad_dir2(dir)) return 1;
9143
9144 if (p_ptr)
9145 do_cmd_target(player, dir);
9146
9147 return 1;
9148 }
9149
9150 static int Receive_target_friendly(int ind)
9151 {
9152 connection_t *connp = Conn[ind];
9153 player_type *p_ptr = NULL;
9154
9155 char ch;
9156
9157 s16b dir;
9158 int n, player = -1;
9159
9160 if (connp->id != -1)
9161 {
9162 player = GetInd[connp->id];
9163 use_esp_link(&player, LINKF_OBJ);
9164 p_ptr = Players[player];
9165 }
9166
9167 if ((n = Packet_scanf(&connp->r, "%c%hd", &ch, &dir)) <= 0)
9168 {
9169 if (n == -1)
9170 Destroy_connection(ind, "read error");
9171 return n;
9172 }
9173
9174 /* Sanity check */
9175 if (bad_dir(dir) && bad_dir2(dir)) return 1;
9176
9177 if (p_ptr)
9178 do_cmd_target_friendly(player, dir);
9179
9180 return 1;
9181 }
9182
9183
9184 static int Receive_inscribe(int ind)
9185 {
9186 connection_t *connp = Conn[ind];
9187 player_type *p_ptr = NULL;
9188 char ch;
9189 int n, player = -1;
9190 s16b item;
9191 char inscription[MAX_CHARS];
9192
9193 if (connp->id != -1)
9194 {
9195 player = GetInd[connp->id];
9196 use_esp_link(&player, LINKF_OBJ);
9197 p_ptr = Players[player];
9198 }
9199
9200 if ((n = Packet_scanf(&connp->r, "%c%hd%s", &ch, &item, inscription)) <= 0)
9201 {
9202 if (n == -1)
9203 Destroy_connection(ind, "read error");
9204 return n;
9205 }
9206 /* paranoia? */
9207 inscription[MAX_CHARS - 1] = '\0';
9208
9209 /* Sanity check - mikaelh */
9210 if (item >= INVEN_TOTAL)
9211 return 1;
9212
9213 if (p_ptr)
9214 {
9215 item = replay_inven_changes(player, item);
9216 if (item == 0xFF)
9217 {
9218 msg_print(player, "Command failed because item is gone.");
9219 return 1;
9220 }
9221
9222 do_cmd_inscribe(player, item, inscription);
9223 }
9224
9225 return 1;
9226 }
9227
9228 static int Receive_uninscribe(int ind)
9229 {
9230 connection_t *connp = Conn[ind];
9231 char ch;
9232 int n, player = -1;
9233 s16b item;
9234 player_type *p_ptr = NULL;
9235
9236 if (connp->id != -1)
9237 {
9238 player = GetInd[connp->id];
9239 use_esp_link(&player, LINKF_OBJ);
9240 p_ptr = Players[player];
9241 }
9242
9243 if ((n = Packet_scanf(&connp->r, "%c%hd", &ch, &item)) <= 0)
9244 {
9245 if (n == -1)
9246 Destroy_connection(ind, "read error");
9247 return n;
9248 }
9249
9250 /* Sanity check - mikaelh */
9251 if (item >= INVEN_TOTAL)
9252 return 1;
9253
9254 if (p_ptr)
9255 {
9256 item = replay_inven_changes(player, item);
9257 if (item == 0xFF)
9258 {
9259 msg_print(player, "Command failed because item is gone.");
9260 return 1;
9261 }
9262
9263 do_cmd_uninscribe(player, item);
9264 }
9265
9266 return 1;
9267 }
9268
9269 static int Receive_autoinscribe(int ind) {
9270 connection_t *connp = Conn[ind];
9271 char ch;
9272 int n, player = -1;
9273 s16b item;
9274 player_type *p_ptr = NULL;
9275
9276 if (connp->id != -1) {
9277 player = GetInd[connp->id];
9278 use_esp_link(&player, LINKF_OBJ);
9279 p_ptr = Players[player];
9280 }
9281
9282 if ((n = Packet_scanf(&connp->r, "%c%hd", &ch, &item)) <= 0) {
9283 if (n == -1) Destroy_connection(ind, "read error");
9284 return n;
9285 }
9286
9287 /* Sanity check - mikaelh */
9288 if (item >= INVEN_TOTAL) return 1;
9289
9290 if (p_ptr) {
9291 item = replay_inven_changes(player, item);
9292 if (item == 0xFF) {
9293 msg_print(player, "Command failed because item is gone.");
9294 return 1;
9295 }
9296
9297 auto_inscribe(player, &(p_ptr->inventory[item]), TRUE);
9298 p_ptr->window |= PW_INVEN;
9299 }
9300
9301 return 1;
9302 }
9303
9304 static int Receive_activate(int ind)
9305 {
9306 connection_t *connp = Conn[ind];
9307 player_type *p_ptr = NULL;
9308 char ch;
9309 s16b item;
9310 int n, player = -1;
9311
9312 if (connp->id != -1)
9313 {
9314 player = GetInd[connp->id];
9315 use_esp_link(&player, LINKF_OBJ);
9316 p_ptr = Players[player];
9317 }
9318
9319 if ((n = Packet_scanf(&connp->r, "%c%hd", &ch, &item)) <= 0)
9320 {
9321 if (n == -1)
9322 Destroy_connection(ind, "read error");
9323 return n;
9324 }
9325
9326 /* Sanity check - mikaelh */
9327 if (item >= INVEN_TOTAL)
9328 return 1;
9329
9330 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos))
9331 {
9332 item = replay_inven_changes(player, item);
9333 if (item == 0xFF)
9334 {
9335 msg_print(player, "Command failed because item is gone.");
9336 return 1;
9337 }
9338
9339 do_cmd_activate(player, item, 0);
9340 return 2;
9341 }
9342 else if (p_ptr)
9343 {
9344 Packet_printf(&connp->q, "%c%hd", ch, item);
9345 return 0;
9346 }
9347
9348 return 1;
9349 }
9350
9351 static int Receive_activate_dir(int ind)
9352 {
9353 connection_t *connp = Conn[ind];
9354 player_type *p_ptr = NULL;
9355 char ch, dir;
9356 s16b item;
9357 int n, player = -1;
9358
9359 if (connp->id != -1) {
9360 player = GetInd[connp->id];
9361 use_esp_link(&player, LINKF_OBJ);
9362 p_ptr = Players[player];
9363 }
9364
9365 if ((n = Packet_scanf(&connp->r, "%c%hd%c", &ch, &item, &dir)) <= 0) {
9366 if (n == -1) Destroy_connection(ind, "read error");
9367 return n;
9368 }
9369
9370 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
9371 /* Sanity check - mikaelh */
9372 if (item >= INVEN_TOTAL) return 1;
9373 if (bad_dir1(player, &dir)) return 1;
9374
9375 item = replay_inven_changes(player, item);
9376 if (item == 0xFF) {
9377 msg_print(player, "Command failed because item is gone.");
9378 return 1;
9379 }
9380
9381 do_cmd_activate(player, item, dir);
9382 return 2;
9383 } else if (p_ptr) {
9384 Packet_printf(&connp->q, "%c%hd%c", ch, item, dir);
9385 return 0;
9386 }
9387
9388 return 1;
9389 }
9390
9391 static int Receive_bash(int ind)
9392 {
9393 connection_t *connp = Conn[ind];
9394 player_type *p_ptr = NULL;
9395 char ch, dir;
9396 int n, player = -1;
9397
9398 if (connp->id != -1) {
9399 player = GetInd[connp->id];
9400 use_esp_link(&player, LINKF_MOV);
9401 p_ptr = Players[player];
9402 }
9403
9404 if ((n = Packet_scanf(&connp->r, "%c%c", &ch, &dir)) <= 0) {
9405 if (n == -1) Destroy_connection(ind, "read error");
9406 return n;
9407 }
9408
9409 /* Sanity check */
9410 if (bad_dir(dir)) return 1;
9411
9412 /* all this is temp just to make it work */
9413 if (p_ptr->command_rep == -1) {
9414 p_ptr->command_rep = 0;
9415 return(0);
9416 }
9417
9418 if (p_ptr && p_ptr->command_rep != PKT_BASH) {
9419 p_ptr->command_rep = -1;
9420 }
9421 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
9422 do_cmd_bash(player, dir);
9423 if (p_ptr->command_rep) Packet_printf(&connp->q, "%c%c", ch, dir);
9424 return 2;
9425 } else if (p_ptr) {
9426 Packet_printf(&connp->q, "%c%c", ch, dir);
9427 return 0;
9428 }
9429
9430 return 1;
9431 }
9432
9433 static int Receive_disarm(int ind)
9434 {
9435 connection_t *connp = Conn[ind];
9436 player_type *p_ptr = NULL;
9437 char ch, dir;
9438 int n, player = -1;
9439
9440 if (connp->id != -1) {
9441 player = GetInd[connp->id];
9442 use_esp_link(&player, LINKF_MOV);
9443 p_ptr = Players[player];
9444 }
9445
9446 if ((n = Packet_scanf(&connp->r, "%c%c", &ch, &dir)) <= 0) {
9447 if (n == -1) Destroy_connection(ind, "read error");
9448 return n;
9449 }
9450
9451 /* Sanity check */
9452 if (bad_dir(dir)) return 1;
9453
9454 /* all this is temp just to make it work */
9455 if (p_ptr->command_rep == -1) {
9456 p_ptr->command_rep = 0;
9457 return(0);
9458 }
9459 if (p_ptr && p_ptr->command_rep != PKT_DISARM) p_ptr->command_rep = -1;
9460
9461 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
9462 do_cmd_disarm(player, dir);
9463 if (p_ptr->command_rep) Packet_printf(&connp->q, "%c%c", ch, dir);
9464 return 2;
9465 } else if (p_ptr) {
9466 Packet_printf(&connp->q, "%c%c", ch, dir);
9467 return 0;
9468 }
9469 return 1;
9470 }
9471
9472 static int Receive_eat(int ind)
9473 {
9474 connection_t *connp = Conn[ind];
9475 player_type *p_ptr = NULL;
9476 char ch;
9477 s16b item;
9478 int n, player = -1;
9479
9480 if (connp->id != -1) {
9481 player = GetInd[connp->id];
9482 use_esp_link(&player, LINKF_OBJ);
9483 p_ptr = Players[player];
9484 }
9485
9486 if ((n = Packet_scanf(&connp->r, "%c%hd", &ch, &item)) <= 0) {
9487 if (n == -1) Destroy_connection(ind, "read error");
9488 return n;
9489 }
9490
9491 /* Sanity check - mikaelh */
9492 if (item >= INVEN_TOTAL)
9493 return 1;
9494
9495 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
9496 item = replay_inven_changes(player, item);
9497 if (item == 0xFF) {
9498 msg_print(player, "Command failed because item is gone.");
9499 return 1;
9500 }
9501
9502 do_cmd_eat_food(player, item);
9503 return 2;
9504 } else if (p_ptr) {
9505 Packet_printf(&connp->q, "%c%hd", ch, item);
9506 return 0;
9507 }
9508 return 1;
9509 }
9510
9511 static int Receive_fill(int ind)
9512 {
9513 connection_t *connp = Conn[ind];
9514 player_type *p_ptr = NULL;
9515 char ch;
9516 s16b item;
9517 int n, player = -1;
9518
9519 if (connp->id != -1) {
9520 player = GetInd[connp->id];
9521 use_esp_link(&player, LINKF_OBJ);
9522 p_ptr = Players[player];
9523 }
9524
9525 if ((n = Packet_scanf(&connp->r, "%c%hd", &ch, &item)) <= 0) {
9526 if (n == -1) Destroy_connection(ind, "read error");
9527 return n;
9528 }
9529
9530 /* Sanity check - mikaelh */
9531 if (item >= INVEN_TOTAL)
9532 return 1;
9533
9534 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
9535 item = replay_inven_changes(player, item);
9536 if (item == 0xFF) {
9537 msg_print(player, "Command failed because item is gone.");
9538 return 1;
9539 }
9540 do_cmd_refill(player, item);
9541 return 2;
9542 } else if (p_ptr) {
9543 Packet_printf(&connp->q, "%c%hd", ch, item);
9544 return 0;
9545 }
9546 return 1;
9547 }
9548
9549 static int Receive_locate(int ind)
9550 {
9551 connection_t *connp = Conn[ind];
9552 player_type *p_ptr = NULL;
9553 char ch, dir;
9554 int n, player = -1;
9555
9556 if (connp->id != -1) {
9557 player = GetInd[connp->id];
9558 use_esp_link(&player, LINKF_MOV);
9559 p_ptr = Players[player];
9560 }
9561
9562 if ((n = Packet_scanf(&connp->r, "%c%c", &ch, &dir)) <= 0) {
9563 if (n == -1) Destroy_connection(ind, "read error");
9564 return n;
9565 }
9566
9567 /* Sanity check */
9568 if (bad_dir(dir)) return 1;
9569
9570 if (p_ptr) {
9571 #if 0 /* too much slowdown of the game play ~~ */
9572 if (!is_admin(p_ptr) && p_ptr->redraw_cooldown) {
9573 Packet_printf(&connp->q, "%c%c", ch, dir);
9574 return 0;
9575 }
9576 /* have a small cooldown, albeit less than like from CTRL+R'ing directly */
9577 p_ptr->redraw_cooldown = 1;
9578 #endif
9579 do_cmd_locate(player, dir);
9580 }
9581
9582 return 1;
9583 }
9584
9585 static int Receive_map(int ind)
9586 {
9587 connection_t *connp = Conn[ind];
9588 char ch, mode;
9589 int n, player = -1;
9590 player_type *p_ptr = NULL;
9591
9592 if (connp->id != -1) {
9593 player = GetInd[connp->id];
9594 use_esp_link(&player, LINKF_OBJ);
9595 p_ptr = Players[player];
9596 }
9597
9598 if ((n = Packet_scanf(&connp->r, "%c%c", &ch, &mode)) <= 0) {
9599 if (n == -1) Destroy_connection(ind, "read error");
9600 return n;
9601 }
9602
9603 if (p_ptr) do_cmd_view_map(player, mode);
9604 return 1;
9605 }
9606
9607 static int Receive_search_mode(int ind)
9608 {
9609 connection_t *connp = Conn[ind];
9610 char ch;
9611 int n, player = -1;
9612 player_type *p_ptr = NULL;
9613
9614 if (connp->id != -1) {
9615 player = GetInd[connp->id];
9616 use_esp_link(&player, LINKF_OBJ);
9617 p_ptr = Players[player];
9618 }
9619
9620 if ((n = Packet_scanf(&connp->r, "%c", &ch)) <= 0) {
9621 if (n == -1) Destroy_connection(ind, "read error");
9622 return n;
9623 }
9624
9625 if (p_ptr) do_cmd_toggle_search(player);
9626 return 1;
9627 }
9628
9629 static int Receive_close(int ind)
9630 {
9631 connection_t *connp = Conn[ind];
9632 player_type *p_ptr = NULL;
9633 char ch, dir;
9634 int n, player = -1;
9635
9636 if (connp->id != -1) {
9637 player = GetInd[connp->id];
9638 use_esp_link(&player, LINKF_OBJ);
9639 p_ptr = Players[player];
9640 }
9641
9642 if ((n = Packet_scanf(&connp->r, "%c%c", &ch, &dir)) <= 0) {
9643 if (n == -1) Destroy_connection(ind, "read error");
9644 return n;
9645 }
9646
9647 /* Sanity check */
9648 if (bad_dir(dir)) return 1;
9649
9650 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
9651 do_cmd_close(player, dir);
9652 return 2;
9653 } else if (p_ptr) {
9654 Packet_printf(&connp->q, "%c%c", ch, dir);
9655 return 0;
9656 }
9657 return 1;
9658 }
9659
9660 static int Receive_skill_mod(int ind)
9661 {
9662 connection_t *connp = Conn[ind];
9663 player_type *p_ptr = NULL;
9664 char ch;
9665 s32b i;
9666 int n, player = -1;
9667
9668 if (connp->id != -1) {
9669 player = GetInd[connp->id];
9670 p_ptr = Players[player];
9671 }
9672
9673 if ((n = Packet_scanf(&connp->r, "%c%d", &ch, &i)) <= 0) {
9674 if (n == -1) Destroy_connection(ind, "read error");
9675 return n;
9676 }
9677
9678 if (p_ptr) increase_skill(player, i, FALSE);
9679 return 1;
9680 }
9681
9682 static int Receive_skill_dev(int ind) {
9683 connection_t *connp = Conn[ind];
9684 player_type *p_ptr = NULL;
9685 char ch;
9686 s32b i;
9687 bool dev;
9688 int n, player = -1;
9689
9690 if (connp->id != -1) {
9691 player = GetInd[connp->id];
9692 p_ptr = Players[player];
9693 }
9694
9695 if ((n = Packet_scanf(&connp->r, "%c%d%c", &ch, &i, &dev)) <= 0) {
9696 if (n == -1) Destroy_connection(ind, "read error");
9697 return n;
9698 }
9699
9700 if (p_ptr) {
9701 if (i == -1) {
9702 /* do it for whole skill tree? */
9703 for (i = 0; i < MAX_SKILLS; i++) {
9704 p_ptr->s_info[i].dev = (dev == 0 ? FALSE : TRUE);
9705 }
9706 } else {
9707 /* only do it for one skill */
9708 p_ptr->s_info[i].dev = (dev == 0 ? FALSE : TRUE);
9709 }
9710 }
9711 return 1;
9712 }
9713
9714 static int Receive_go_up(int ind)
9715 {
9716 connection_t *connp = Conn[ind];
9717 player_type *p_ptr = NULL;
9718 char ch;
9719 int n, player = -1;
9720
9721 if (connp->id != -1) {
9722 player = GetInd[connp->id];
9723 use_esp_link(&player, LINKF_OBJ);
9724 p_ptr = Players[player];
9725 }
9726
9727 if ((n = Packet_scanf(&connp->r, "%c", &ch)) <= 0) {
9728 if (n == -1) Destroy_connection(ind, "read error");
9729 return n;
9730 }
9731
9732 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
9733 do_cmd_go_up(player);
9734 return 2;
9735 } else if (p_ptr) {
9736 Packet_printf(&connp->q, "%c", ch);
9737 return 0;
9738 }
9739 return 1;
9740 }
9741
9742 static int Receive_go_down(int ind)
9743 {
9744 connection_t *connp = Conn[ind];
9745 player_type *p_ptr = NULL;
9746 char ch;
9747 int n, player = -1;
9748
9749 if (connp->id != -1) {
9750 player = GetInd[connp->id];
9751 use_esp_link(&player, LINKF_OBJ);
9752 p_ptr = Players[player];
9753 }
9754
9755 if ((n = Packet_scanf(&connp->r, "%c", &ch)) <= 0) {
9756 if (n == -1) Destroy_connection(ind, "read error");
9757 return n;
9758 }
9759
9760 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
9761 do_cmd_go_down(player);
9762 return 2;
9763 } else if (p_ptr) {
9764 Packet_printf(&connp->q, "%c", ch);
9765 return 0;
9766 }
9767 return 1;
9768 }
9769
9770
9771 static int Receive_direction(int ind)
9772 {
9773 connection_t *connp = Conn[ind];
9774 char ch, dir;
9775 int n, player = -1;
9776 player_type *p_ptr = NULL;
9777
9778 if (connp->id != -1) {
9779 player = GetInd[connp->id];
9780 use_esp_link(&player, LINKF_OBJ);
9781 p_ptr = Players[player];
9782 }
9783 else player = 0;
9784
9785 if ((n = Packet_scanf(&connp->r, "%c%c", &ch, &dir)) <= 0) {
9786 if (n == -1) Destroy_connection(ind, "read error");
9787 return n;
9788 }
9789
9790 /* Sanity check */
9791 if (bad_dir1(player, &dir)) return 1;
9792
9793 if (p_ptr) Handle_direction(player, dir);
9794
9795 return 1;
9796 }
9797
9798 static int Receive_item(int ind)
9799 {
9800 connection_t *connp = Conn[ind];
9801 char ch;
9802 s16b item;
9803 int n, player = -1;
9804 player_type *p_ptr = NULL;
9805
9806 if (connp->id != -1) {
9807 player = GetInd[connp->id];
9808 use_esp_link(&player, LINKF_OBJ);
9809 p_ptr = Players[player];
9810 }
9811 else player = 0;
9812
9813 if ((n = Packet_scanf(&connp->r, "%c%hd", &ch, &item)) <= 0) {
9814 if (n == -1) Destroy_connection(ind, "read error");
9815 return n;
9816 }
9817
9818 /* Sanity check - mikaelh */
9819 if (item >= INVEN_TOTAL)
9820 return 1;
9821
9822 if (p_ptr) {
9823 item = replay_inven_changes(player, item);
9824 if (item == 0xFF) {
9825 msg_print(player, "Command failed because item is gone.");
9826 return 1;
9827 }
9828 Handle_item(player, item);
9829 }
9830 return 1;
9831 }
9832
9833 /* for DISCRETE_SPELL_SYSTEM: DSS_EXPANDED_SCROLLS */
9834 static int Receive_spell(int ind) {
9835 connection_t *connp = Conn[ind];
9836 char ch;
9837 s16b item, spell;
9838 int n, player = -1;
9839 player_type *p_ptr = NULL;
9840
9841 if (connp->id != -1) {
9842 player = GetInd[connp->id];
9843 use_esp_link(&player, LINKF_OBJ);
9844 p_ptr = Players[player];
9845 }
9846 else player = 0;
9847
9848 if ((n = Packet_scanf(&connp->r, "%c%hd%hd", &ch, &item, &spell)) <= 0) {
9849 if (n == -1) Destroy_connection(ind, "read error");
9850 return n;
9851 }
9852
9853 /* Sanity check - mikaelh */
9854 if (item >= INVEN_TOTAL)
9855 return 1;
9856 if (spell > max_spells) return 1;
9857
9858 if (p_ptr) {
9859 item = replay_inven_changes(player, item);
9860 if (item == 0xFF) {
9861 msg_print(player, "Command failed because item is gone.");
9862 return 1;
9863 }
9864 //Handle_item(player, item);
9865 //TODO: finish tome_creation_aux() here
9866 }
9867 return 1;
9868 }
9869
9870
9871 static int Receive_message(int ind)
9872 {
9873 connection_t *connp = Conn[ind];
9874 char ch, buf[MSG_LEN];
9875 int n, player = -1;
9876 if (connp->id != -1) player = GetInd[connp->id];
9877 else player = 0;
9878
9879 if ((n = Packet_scanf(&connp->r, "%c%S", &ch, buf)) <= 0) {
9880 if (n == -1) Destroy_connection(ind, "read error");
9881 return n;
9882 }
9883
9884 /* A message longer than 159 characters will certainly cause problems - mikaelh
9885 (Changed it to MSG_LEN - C. Blue) */
9886 buf[MSG_LEN - 1] = '\0';
9887 player_talk(player, buf);
9888 return 1;
9889 }
9890
9891 static int Receive_admin_house(int ind) {
9892 connection_t *connp = Conn[ind];
9893 char ch;
9894 s16b dir;
9895 int n,player = -1;
9896 char buf[MAX_CHARS];
9897
9898 if (connp->id != -1) {
9899 player = GetInd[connp->id];
9900 // use_esp_link(&player, LINKF_OBJ);
9901 }
9902 else player = 0;
9903
9904 if ((n = Packet_scanf(&connp->r, "%c%hd%s", &ch, &dir, buf)) <= 0) {
9905 if (n == -1) Destroy_connection(ind, "read error");
9906 return n;
9907 }
9908
9909 /* Sanity check */
9910 if (bad_dir(dir)) return 1;
9911
9912 house_admin(player, dir, buf);
9913 return(1);
9914 }
9915
9916 static int Receive_purchase(int ind)
9917 {
9918 connection_t *connp = Conn[ind];
9919 player_type *p_ptr = NULL;
9920
9921 char ch;
9922 int n, player = -1;
9923 s16b item, amt;
9924
9925 if (connp->id != -1) {
9926 player = GetInd[connp->id];
9927 // use_esp_link(&player, LINKF_OBJ);
9928 p_ptr = Players[player];
9929 }
9930 else player = 0;
9931
9932 if ((n = Packet_scanf(&connp->r, "%c%hd%hd", &ch, &item, &amt)) <= 0) {
9933 if (n == -1) Destroy_connection(ind, "read error");
9934 return n;
9935 }
9936
9937 if (player && p_ptr->store_num != -1)
9938 store_purchase(player, item, amt);
9939 else if (p_ptr)
9940 do_cmd_purchase_house(player, item);
9941
9942 return 1;
9943 }
9944
9945 static int Receive_sell(int ind)
9946 {
9947 connection_t *connp = Conn[ind];
9948
9949 char ch;
9950 int n, player = -1;
9951 s16b item, amt;
9952
9953 if (connp->id != -1) {
9954 player = GetInd[connp->id];
9955 // use_esp_link(&player, LINKF_OBJ);
9956 }
9957 else player = 0;
9958
9959 if ((n = Packet_scanf(&connp->r, "%c%hd%hd", &ch, &item, &amt)) <= 0) {
9960 if (n == -1) Destroy_connection(ind, "read error");
9961 return n;
9962 }
9963
9964 if (player) store_sell(player, item, amt);
9965
9966 return 1;
9967 }
9968
9969 static int Receive_store_leave(int ind)
9970 {
9971 connection_t *connp = Conn[ind];
9972 #ifdef MINDLINK_STORE
9973 connection_t *connp2;
9974 #endif
9975 player_type *p_ptr = NULL;
9976
9977 char ch;
9978 int n, player = -1;
9979
9980 if (connp->id != -1) {
9981 player = GetInd[connp->id];
9982 // use_esp_link(&player, LINKF_OBJ);
9983 p_ptr = Players[player];
9984 #ifdef MINDLINK_STORE
9985 if (get_esp_link(GetInd[connp->id], LINKF_OBJ, &p_ptr)) {
9986 connp2 = Conn[p_ptr->conn];
9987 Packet_printf(&connp2->c, "%c", PKT_STORE_LEAVE); /* not working */
9988 }
9989 #endif
9990 } else player = 0;
9991
9992 if (player) p_ptr = Players[player];
9993
9994 if ((n = Packet_scanf(&connp->r, "%c", &ch)) <= 0) {
9995 if (n == -1) Destroy_connection(ind, "read error");
9996 return n;
9997 }
9998
9999 if (!player) return -1;
10000
10001 /* Update stuff */
10002 p_ptr->update |= (PU_VIEW | PU_LITE);
10003 p_ptr->update |= (PU_MONSTERS);
10004
10005 /* Redraw stuff */
10006 p_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA);
10007
10008 /* Window stuff */
10009 p_ptr->window |= (PW_OVERHEAD);
10010
10011 /* Update store info */
10012 if (p_ptr->store_num != -1) {
10013 #ifdef PLAYER_STORES
10014 /* Player stores aren't entered such as normal stores,
10015 instead, the customer just stays in front of it. */
10016 if (p_ptr->store_num > -2)
10017 #endif
10018 /* Hack -- don't stand in the way */
10019 teleport_player_force(player, 1);
10020
10021 handle_store_leave(player);
10022 }
10023
10024 #if 0
10025 #if 0
10026 /* hack -- update night/day in wilderness levels */
10027 /* XXX it's not so good place to do such things -
10028 * prolly we'll need PU_SUN or sth. - Jir - */
10029 if (!p_ptr->wpos.wz) {
10030 if (IS_DAY) world_surface_day(&p_ptr->wpos);
10031 else world_surface_night(&p_ptr->wpos);
10032 }
10033 #else
10034 if (!p_ptr->wpos.wz) {
10035 if (IS_DAY) player_day(player);
10036 else player_night(player);
10037 }
10038 #endif
10039 #endif
10040
10041 return 1;
10042 }
10043
10044 static int Receive_store_confirm(int ind) {
10045 connection_t *connp = Conn[ind];
10046 char ch;
10047 int n, player = -1;
10048
10049 if (connp->id != -1) {
10050 player = GetInd[connp->id];
10051 // use_esp_link(&player, LINKF_OBJ);
10052 }
10053 else player = 0;
10054
10055 if ((n = Packet_scanf(&connp->r, "%c", &ch)) <= 0) {
10056 if (n == -1) Destroy_connection(ind, "read error");
10057 return n;
10058 }
10059
10060 if (!player) return -1;
10061
10062 store_confirm(player);
10063 return 1;
10064 }
10065
10066 /* Store code should be written to allow more kinds of actions in general..
10067 */
10068 static int Receive_store_examine(int ind)
10069 {
10070 connection_t *connp = Conn[ind];
10071 player_type *p_ptr = NULL;
10072
10073 char ch;
10074 int n, player = -1;
10075 s16b item;
10076
10077 if (connp->id != -1) {
10078 player = GetInd[connp->id];
10079 // use_esp_link(&player, LINKF_OBJ);
10080 p_ptr = Players[player];
10081 }
10082 else player = 0;
10083
10084 if ((n = Packet_scanf(&connp->r, "%c%hd", &ch, &item)) <= 0) {
10085 if (n == -1) Destroy_connection(ind, "read error");
10086 return n;
10087 }
10088
10089 if (player && p_ptr->store_num != -1)
10090 store_examine(player, item);
10091
10092 return 1;
10093 }
10094
10095 static int Receive_store_command(int ind)
10096 {
10097 connection_t *connp = Conn[ind];
10098 player_type *p_ptr = NULL;
10099
10100 char ch;
10101 int n, player = 0, gold;
10102 u16b action;
10103 s16b item, item2, amt;
10104
10105 if (connp->id != -1) {
10106 player = GetInd[connp->id];
10107 // use_esp_link(&player, LINKF_OBJ);
10108 p_ptr = Players[player];
10109 }
10110 else player = 0;
10111
10112 if ((n = Packet_scanf(&connp->r, "%c%hd%hd%hd%hd%d", &ch, &action, &item, &item2, &amt, &gold)) <= 0) {
10113 if (n == -1) Destroy_connection(ind, "read error");
10114 return n;
10115 }
10116
10117 if (player && p_ptr->store_num != -1)
10118 store_exec_command(player, action, item, item2, amt, gold);
10119
10120 return 1;
10121 }
10122
10123 static int Receive_drop_gold(int ind)
10124 {
10125 connection_t *connp = Conn[ind];
10126 player_type *p_ptr = NULL;
10127 char ch;
10128 int n, player = -1;
10129 s32b amt;
10130
10131 if (connp->id != -1) {
10132 player = GetInd[connp->id];
10133 // use_esp_link(&player, LINKF_OBJ);
10134 p_ptr = Players[player];
10135 }
10136
10137 if ((n = Packet_scanf(&connp->r, "%c%d", &ch, &amt)) <= 0) {
10138 if (n == -1) Destroy_connection(ind, "read error");
10139 return n;
10140 }
10141
10142 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
10143 do_cmd_drop_gold(player, amt);
10144 return 2;
10145 } else if (p_ptr) {
10146 Packet_printf(&connp->q, "%c%d", ch, amt);
10147 return 0;
10148 }
10149 return 1;
10150 }
10151
10152 static int Receive_steal(int ind)
10153 {
10154 connection_t *connp = Conn[ind];
10155 player_type *p_ptr = NULL;
10156 char ch, dir;
10157 int n, player = -1;
10158
10159 if (connp->id != -1) {
10160 player = GetInd[connp->id];
10161 // use_esp_link(&player, LINKF_OBJ);
10162 p_ptr = Players[player];
10163 }
10164
10165 if ((n = Packet_scanf(&connp->r, "%c%c", &ch, &dir)) <= 0) {
10166 if (n == -1) Destroy_connection(ind, "read error");
10167 return n;
10168 }
10169
10170 /* Sanity check */
10171 if (bad_dir(dir)) return 1;
10172
10173 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
10174 do_cmd_steal(player, dir);
10175 return 2;
10176 } else if (p_ptr) {
10177 Packet_printf(&connp->q, "%c%c", ch, dir);
10178 return 0;
10179 }
10180 return 1;
10181 }
10182
10183
10184 static int Receive_King(int ind)
10185 {
10186 connection_t *connp = Conn[ind];
10187 player_type *p_ptr = NULL;
10188
10189 byte type;
10190 char ch;
10191
10192 int n, player = -1;
10193
10194 if (connp->id != -1) {
10195 player = GetInd[connp->id];
10196 // use_esp_link(&player, LINKF_OBJ);
10197 p_ptr = Players[player];
10198 }
10199
10200 if ((n = Packet_scanf(&connp->r, "%c%c", &ch, &type)) <= 0) {
10201 if (n == -1) Destroy_connection(ind, "read error");
10202 return n;
10203 }
10204
10205 if (p_ptr) {
10206 switch(type) {
10207 #if 0 /* DGDGDGDG -- Cause fucking up of levels */
10208 case KING_OWN:
10209 do_cmd_own(player);
10210 break;
10211 #endif
10212 }
10213 return 2;
10214 } else if (p_ptr) {
10215 Packet_printf(&connp->q, "%c%c", ch, type);
10216 return 0;
10217 }
10218 return 1;
10219 }
10220
10221 static int Receive_redraw(int ind)
10222 {
10223 connection_t *connp = Conn[ind];
10224 player_type *p_ptr = NULL;
10225 int player = -1, n;
10226 char ch, mode;
10227
10228 if (connp->id != -1) {
10229 player = GetInd[connp->id];
10230 p_ptr = Players[player];
10231
10232 if (p_ptr->esp_link_type && p_ptr->esp_link) {
10233 int Ind2 = find_player(p_ptr->esp_link);
10234
10235 if (!Ind2)
10236 end_mind(ind, TRUE);
10237 else {
10238 if (Players[Ind2]->esp_link_flags & LINKF_VIEW) {
10239 player = Ind2;
10240 p_ptr = Players[Ind2];
10241 }
10242 }
10243 }
10244 }
10245 else player = 0;
10246
10247 if ((n = Packet_scanf(&connp->r, "%c%c", &ch, &mode)) <= 0) {
10248 if (n == -1) Destroy_connection(ind, "read error");
10249 return n;
10250 }
10251
10252 if (player && !p_ptr->redraw_cooldown) {
10253 if (!is_admin(p_ptr)) p_ptr->redraw_cooldown = 3;
10254
10255 // p_ptr->store_num = -1;
10256 p_ptr->redraw |= (PR_BASIC | PR_EXTRA | PR_MAP);
10257 p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
10258 p_ptr->update |= (PU_BONUS | PU_VIEW | PU_MANA | PU_HP | PU_SANITY);
10259
10260 /* Do 'Heavy' redraw if requested.
10261 * TODO: One might wish to add more detailed modes
10262 */
10263 if (mode) {
10264 /* Tell the server to redraw the player's display */
10265 p_ptr->redraw |= PR_MAP | PR_EXTRA | PR_BASIC | PR_HISTORY | PR_VARIOUS | PR_STATE;
10266 p_ptr->redraw |= PR_PLUSSES;
10267 if (is_older_than(&p_ptr->version, 4, 4, 8, 5, 0, 0)) p_ptr->redraw |= PR_STUDY;
10268
10269 /* Update his view, light, bonuses, and torch radius */
10270 #ifdef ORIG_SKILL_EVIL /* not to be defined */
10271 p_ptr->update |= (PU_VIEW | PU_LITE | PU_BONUS | PU_TORCH | PU_DISTANCE
10272 | PU_SKILL_INFO | PU_SKILL_MOD);
10273 #else
10274 p_ptr->update |= (PU_VIEW | PU_LITE | PU_BONUS | PU_TORCH | PU_DISTANCE );
10275 #endif
10276 p_ptr->update |= (PU_MANA | PU_HP | PU_SANITY);
10277
10278 /* Update his inventory, equipment, and spell info */
10279 p_ptr->window |= (PW_INVEN | PW_EQUIP);
10280 }
10281 }
10282
10283 return 1;
10284 }
10285
10286 static int Receive_rest(int ind)
10287 {
10288 connection_t *connp = Conn[ind];
10289 player_type *p_ptr = NULL;
10290 int player = -1, n;
10291 char ch;
10292
10293 if (connp->id != -1) {
10294 player = GetInd[connp->id];
10295 use_esp_link(&player, LINKF_MOV);
10296 p_ptr = Players[player];
10297 }
10298 else player = 0;
10299
10300 if ((n = Packet_scanf(&connp->r, "%c", &ch)) <= 0) {
10301 if (n == -1) Destroy_connection(ind, "read error");
10302 return n;
10303 }
10304
10305 if (player) {
10306 cave_type **zcave;
10307
10308 /* If we are already resting, cancel the rest. */
10309 /* Waking up takes no energy, although we will still be drowsy... */
10310 if (p_ptr->resting) {
10311 disturb(player, 0, 0);
10312 return 2;
10313 }
10314
10315 /* Don't rest if we are poisoned or at max hit points and max spell points
10316 and max stamina */
10317 if ((p_ptr->poisoned) || (p_ptr->cut) || (p_ptr->sun_burn) ||
10318 ((p_ptr->chp == p_ptr->mhp) &&
10319 (p_ptr->csp == p_ptr->msp) &&
10320 (p_ptr->cst == p_ptr->mst)
10321 && !(p_ptr->prace == RACE_ENT && p_ptr->food < PY_FOOD_FULL)
10322 ))
10323 return 2;
10324
10325 if (!(zcave = getcave(&p_ptr->wpos))) return 2;
10326
10327 #if 0 /* why? don't see a reason atm */
10328 /* Can't rest on a Void Jumpgate -- too dangerous */
10329 if (zcave[p_ptr->py][p_ptr->px].feat == FEAT_BETWEEN) {
10330 msg_print(player, "Resting on a Void Jumpgate is too dangerous!");
10331 return 2;
10332 }
10333 #endif
10334
10335 /* Resting takes a lot of energy! */
10336 if ((p_ptr->energy) >= (level_speed(&p_ptr->wpos) * 2) - 1) {
10337 /* Set flag */
10338 p_ptr->resting = TRUE;
10339 p_ptr->warning_rest = 3;
10340
10341 /* Make sure we aren't running */
10342 p_ptr->running = FALSE;
10343 break_shadow_running(player);
10344 stop_precision(player);
10345 stop_shooting_till_kill(player);
10346
10347 /* Take a lot of energy to enter "rest mode" */
10348 p_ptr->energy -= (level_speed(&p_ptr->wpos) * 2) - 1;
10349
10350 /* Redraw */
10351 p_ptr->redraw |= (PR_STATE);
10352 return 2;
10353 }
10354 /* If we don't have enough energy to rest, disturb us (to stop
10355 * us from running) and queue the command.
10356 */
10357 else
10358 {
10359 disturb(player, 0, 0);
10360 Packet_printf(&connp->q, "%c", ch);
10361 return 0;
10362 }
10363 }
10364
10365 return 1;
10366 }
10367
10368 void Handle_clear_buffer(int Ind)
10369 {
10370 player_type *p_ptr = Players[Ind];
10371 connection_t *connp = Conn[p_ptr->conn];
10372
10373 /* Clear the buffer */
10374
10375 /* No energy commands are placed in 'q' */
10376 Sockbuf_clear(&connp->q);
10377
10378 /* New commands are in 'r' - clear this and its gone. */
10379 /* Sockbuf_clear(&connp->r); */
10380
10381 /* Clear 'current spell' */
10382 p_ptr->current_spell = -1;
10383 }
10384
10385 static void Handle_clear_actions(int Ind) {
10386 player_type *p_ptr = Players[Ind];
10387
10388 /* Stop ranged auto-retaliation (fire-till-kill) */
10389 p_ptr->shooting_till_kill = FALSE;
10390
10391 /* Stop automatically executed repeated actions */
10392 p_ptr->command_rep = 0;
10393 #ifdef ENABLE_XID_SPELL
10394 p_ptr->current_item = -1; //unnecessary?
10395 #endif
10396
10397 /* Stop preparing shooting techniques */
10398 stop_precision(Ind);
10399 if (p_ptr->ranged_flare) {
10400 msg_print(Ind, "You dispose of the flare missile.");
10401 p_ptr->ranged_flare = FALSE;
10402 }
10403 if (p_ptr->ranged_barrage) {
10404 msg_print(Ind, "You cancel preparations for barrage.");
10405 p_ptr->ranged_barrage = FALSE;
10406 }
10407
10408 /* Stop resting */
10409 disturb(Ind, 0, 0);
10410 }
10411
10412 static int Receive_clear_buffer(int ind) {
10413 connection_t *connp = Conn[ind];
10414 int player = -1, n;
10415 char ch;
10416
10417 if (connp->id != -1) {
10418 player = GetInd[connp->id];
10419 // use_esp_link(&player, LINKF_OBJ);
10420 }
10421 else player = 0;
10422
10423 if ((n = Packet_scanf(&connp->r, "%c", &ch)) <= 0) {
10424 if (n == -1) Destroy_connection(ind, "read error");
10425 return n;
10426 }
10427
10428 if (player) Handle_clear_buffer(player);
10429
10430 return 1;
10431 }
10432
10433 static int Receive_clear_actions(int ind) {
10434 connection_t *connp = Conn[ind];
10435 int player = -1, n;
10436 char ch;
10437
10438 if (connp->id != -1) {
10439 player = GetInd[connp->id];
10440 // use_esp_link(&player, LINKF_OBJ);
10441 }
10442 else player = 0;
10443
10444 if ((n = Packet_scanf(&connp->r, "%c", &ch)) <= 0) {
10445 if (n == -1) Destroy_connection(ind, "read error");
10446 return n;
10447 }
10448
10449 if (player) Handle_clear_actions(player);
10450
10451 return 1;
10452 }
10453
10454 static int Receive_special_line(int ind)
10455 {
10456 connection_t *connp = Conn[ind];
10457 int player = -1, n;
10458 char ch, type;
10459 s32b line;
10460
10461 if (connp->id != -1) player = GetInd[connp->id];
10462 else player = 0;
10463
10464 if (is_newer_than(&connp->version, 4, 4, 7, 0, 0, 0)) {
10465 if ((n = Packet_scanf(&connp->r, "%c%c%d", &ch, &type, &line)) <= 0) {
10466 if (n == -1)
10467 Destroy_connection(ind, "read error");
10468 return n;
10469 }
10470 } else {
10471 s16b old_line;
10472 if ((n = Packet_scanf(&connp->r, "%c%c%hd", &ch, &type, &old_line)) <= 0) {
10473 if (n == -1)
10474 Destroy_connection(ind, "read error");
10475 return n;
10476 }
10477 line = old_line;
10478 }
10479
10480 if (player) {
10481 char kludge[2] = "", minlev = 0;
10482 /* abuse 'line' to encode both, type and minlev (for monster knowledge) */
10483 minlev = line / 100000;
10484 line = line % 100000;
10485 kludge[0] = (char) line;
10486 kludge[1] = '\0';
10487 switch (type) {
10488 case SPECIAL_FILE_NONE:
10489 Players[player]->special_file_type = FALSE;
10490 /* Remove the file */
10491 /* if (!strcmp(Players[player]->infofile,
10492 Players[player]->cur_file)) */
10493 fd_kill(Players[player]->infofile);
10494 break;
10495 case SPECIAL_FILE_UNIQUE:
10496 do_cmd_check_uniques(player, line);
10497 break;
10498 case SPECIAL_FILE_ARTIFACT:
10499 do_cmd_check_artifacts(player, line);
10500 break;
10501 case SPECIAL_FILE_PLAYER:
10502 do_cmd_check_players(player, line);
10503 break;
10504 case SPECIAL_FILE_PLAYER_EQUIP:
10505 do_cmd_check_player_equip(player, line);
10506 break;
10507 case SPECIAL_FILE_OTHER:
10508 do_cmd_check_other(player, line);
10509 break;
10510 case SPECIAL_FILE_SCORES:
10511 display_scores(player, line);
10512 break;
10513 case SPECIAL_FILE_HELP:
10514 do_cmd_help(player, line);
10515 break;
10516 /* Obsolete, just left for compatibility (DELETEME) */
10517 case SPECIAL_FILE_LOG:
10518 if (is_admin(Players[player]))
10519 do_cmd_view_rfe(player, "tomenet.log", line);
10520 break;
10521 case SPECIAL_FILE_RFE:
10522 if (is_admin(Players[player]) || cfg.public_rfe)
10523 do_cmd_view_rfe(player, "tomenet.rfe", line);
10524 break;
10525 case SPECIAL_FILE_MOTD2:
10526 show_motd2(player);
10527 break;
10528 /*
10529 * Hack -- those special files actually use do_cmd_check_other
10530 * XXX redesign it
10531 */
10532 case SPECIAL_FILE_SERVER_SETTING:
10533 do_cmd_check_server_settings(player);
10534 break;
10535 case SPECIAL_FILE_MONSTER:
10536 do_cmd_show_monster_killed_letter(player, kludge, minlev);
10537 break;
10538 case SPECIAL_FILE_OBJECT:
10539 do_cmd_show_known_item_letter(player, kludge);
10540 break;
10541 case SPECIAL_FILE_HOUSE:
10542 do_cmd_show_houses(player, FALSE, FALSE);
10543 break;
10544 case SPECIAL_FILE_TRAP:
10545 do_cmd_knowledge_traps(player);
10546 break;
10547 case SPECIAL_FILE_RECALL:
10548 do_cmd_knowledge_dungeons(player);
10549 break;
10550 }
10551 }
10552
10553 return 1;
10554 }
10555
10556 static int Receive_options(int ind) {
10557 connection_t *connp = Conn[ind];
10558 int player = -1, i, n;
10559 char ch;
10560
10561 if (connp->id != -1) {
10562 player = GetInd[connp->id];
10563 } else {
10564 player = 0;
10565 }
10566
10567 if ((n = Packet_scanf(&connp->r, "%c", &ch)) <= 0) {
10568 if (n == -1) Destroy_connection(ind, "read error");
10569 return n;
10570 }
10571
10572 if (player) {
10573 bool options[OPT_MAX];
10574
10575 if (is_newer_than(&connp->version, 4, 5, 8, 1, 0, 1)) {
10576 for (i = 0; i < OPT_MAX; i++) {
10577 n = Packet_scanf(&connp->r, "%c", &options[i]);
10578 if (n <= 0) {
10579 Destroy_connection(ind, "read error");
10580 return n;
10581 }
10582 }
10583 } else if (is_newer_than(&connp->version, 4, 5, 5, 0, 0, 0)) {
10584 for (i = 0; i < OPT_MAX_COMPAT; i++) {
10585 n = Packet_scanf(&connp->r, "%c", &options[i]);
10586 if (n <= 0) {
10587 Destroy_connection(ind, "read error");
10588 return n;
10589 }
10590 }
10591 } else {
10592 for (i = 0; i < OPT_MAX_OLD; i++) {
10593 n = Packet_scanf(&connp->r, "%c", &options[i]);
10594 if (n <= 0) {
10595 Destroy_connection(ind, "read error");
10596 return n;
10597 }
10598 }
10599 }
10600
10601 /* Sync named options */
10602 sync_options(player, options);
10603 }
10604
10605 return 1;
10606 }
10607
10608 static int Receive_screen_dimensions(int ind) {
10609 connection_t *connp = Conn[ind];
10610 player_type *p_ptr = NULL;
10611 int player = -1, n;
10612 char ch;
10613
10614 if (connp->id != -1) {
10615 player = GetInd[connp->id];
10616 p_ptr = Players[player];
10617 } else {
10618 player = 0;
10619 p_ptr = NULL;
10620 }
10621
10622 if ((n = Packet_scanf(&connp->r, "%c", &ch)) <= 0) {
10623 if (n == -1) Destroy_connection(ind, "read error");
10624 return n;
10625 }
10626
10627 if (player) {
10628 n = Packet_scanf(&connp->r, "%d%d", &p_ptr->screen_wid, &p_ptr->screen_hgt);
10629 if (n <= 0) {
10630 Destroy_connection(ind, "read error");
10631 return n;
10632 }
10633 #ifndef BIG_MAP
10634 return 1;
10635 #endif
10636
10637
10638 /* fix limits */
10639 #ifdef BIG_MAP
10640 if (p_ptr->screen_wid > MAX_SCREEN_WID) p_ptr->screen_wid = MAX_SCREEN_WID;
10641 if (p_ptr->screen_wid < MIN_SCREEN_WID) p_ptr->screen_wid = MIN_SCREEN_WID;
10642 if (p_ptr->screen_hgt > MAX_SCREEN_HGT) p_ptr->screen_hgt = MAX_SCREEN_HGT;
10643 if (p_ptr->screen_hgt < MIN_SCREEN_HGT) p_ptr->screen_hgt = MIN_SCREEN_HGT;
10644 /* for now until resolved: avoid dimensions whose half values aren't divisors of MAX_WID/HGT */
10645 if (MAX_WID % (p_ptr->screen_wid / 2)) p_ptr->screen_wid = SCREEN_WID;
10646 if (MAX_HGT % (p_ptr->screen_hgt / 2)) p_ptr->screen_hgt = SCREEN_HGT;
10647 #else
10648 p_ptr->screen_wid = SCREEN_WID;
10649 p_ptr->screen_hgt = SCREEN_HGT;
10650 #endif
10651
10652 connp->Client_setup.screen_wid = p_ptr->screen_wid;
10653 connp->Client_setup.screen_hgt = p_ptr->screen_hgt;
10654
10655
10656 /* Recalculate panel */
10657
10658 if (p_ptr->wpos.wz) {
10659 dun_level *l_ptr = getfloor(&p_ptr->wpos);
10660 p_ptr->max_panel_rows = MAX_PANEL_ROWS_L;
10661 p_ptr->max_panel_cols = MAX_PANEL_COLS_L;
10662
10663 } else {
10664 p_ptr->max_panel_rows = MAX_PANEL_ROWS;
10665 p_ptr->max_panel_cols = MAX_PANEL_COLS;
10666 }
10667 #ifdef BIG_MAP
10668 if (p_ptr->max_panel_rows < 0) p_ptr->max_panel_rows = 0;
10669 if (p_ptr->max_panel_cols < 0) p_ptr->max_panel_cols = 0;
10670 #endif
10671
10672 p_ptr->panel_row = ((p_ptr->py - p_ptr->screen_hgt / 4) / (p_ptr->screen_hgt / 2));
10673 if (p_ptr->panel_row > p_ptr->max_panel_rows) p_ptr->panel_row = p_ptr->max_panel_rows;
10674 else if (p_ptr->panel_row < 0) p_ptr->panel_row = 0;
10675
10676 p_ptr->panel_col = ((p_ptr->px - p_ptr->screen_wid / 4) / (p_ptr->screen_wid / 2));
10677 if (p_ptr->panel_col > p_ptr->max_panel_cols) p_ptr->panel_col = p_ptr->max_panel_cols;
10678 else if (p_ptr->panel_col < 0) p_ptr->panel_col = 0;
10679
10680 #ifdef ALERT_OFFPANEL_DAM
10681 /* For alert-beeps on damage: Reset remembered panel */
10682 p_ptr->panel_row_old = p_ptr->panel_row;
10683 p_ptr->panel_col_old = p_ptr->panel_col;
10684 #endif
10685
10686 panel_bounds(player);
10687
10688
10689 /* Heavy redraw (just to make sure) */
10690
10691 p_ptr->redraw |= PR_MAP | PR_EXTRA | PR_BASIC | PR_HISTORY | PR_VARIOUS | PR_STATE | PR_PLUSSES;
10692 if (is_older_than(&p_ptr->version, 4, 4, 8, 5, 0, 0)) p_ptr->redraw |= PR_STUDY;
10693
10694 #ifdef ORIG_SKILL_EVIL /* not to be defined */
10695 p_ptr->update |= (PU_LITE | PU_TORCH | PU_DISTANCE | PU_SKILL_INFO | PU_SKILL_MOD);
10696 #else
10697 p_ptr->update |= (PU_LITE | PU_TORCH | PU_DISTANCE );
10698 #endif
10699 p_ptr->update |= (PU_BONUS | PU_VIEW | PU_MANA | PU_HP | PU_SANITY);
10700 p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
10701 }
10702
10703 return 1;
10704 }
10705
10706 static int Receive_suicide(int ind)
10707 {
10708 connection_t *connp = Conn[ind];
10709 int player = -1, n;
10710 char ch;
10711 char extra1 = 1, extra2 = 4;
10712
10713 if (connp->id != -1)
10714 player = GetInd[connp->id];
10715 else player = 0;
10716
10717 /* Newer clients send couple of extra bytes to prevent accidental
10718 * suicides due to network mishaps. - mikaelh */
10719 if (is_newer_than(&connp->version, 4, 4, 2, 3, 0, 0)) {
10720 if ((n = Packet_scanf(&connp->r, "%c%c%c", &ch, &extra1, &extra2)) <= 0)
10721 {
10722 if (n == -1)
10723 Destroy_connection(ind, "read error");
10724 return n;
10725 }
10726 }
10727 else
10728 {
10729 if ((n = Packet_scanf(&connp->r, "%c", &ch)) <= 0)
10730 {
10731 if (n == -1)
10732 Destroy_connection(ind, "read error");
10733 return n;
10734 }
10735 }
10736
10737 if (extra1 != 1 || extra2 != 4)
10738 {
10739 /* Invalid suicide command detected, clear the buffer now */
10740 Sockbuf_clear(&connp->r);
10741 return 1;
10742 }
10743
10744 /* Commit suicide */
10745 do_cmd_suicide(player);
10746
10747 return 1;
10748 }
10749
10750 static int Receive_party(int ind) {
10751 connection_t *connp = Conn[ind];
10752 int player = -1, n;
10753 char ch, buf[MAX_CHARS];
10754 s16b command;
10755
10756 if (connp->id != -1) player = GetInd[connp->id];
10757 else return 1;
10758
10759 if ((n = Packet_scanf(&connp->r, "%c%hd%s", &ch, &command, buf)) <= 0) {
10760 if (n == -1) Destroy_connection(ind, "read error");
10761 return n;
10762 }
10763
10764 /* sanitize input - C. Blue */
10765 if (strlen(buf) > 40) *(buf + 40) = 0;
10766 for (n = 0; n < (int)strlen(buf); n++)
10767 if (*(buf + n) < 32) *(buf + n) = '_';
10768
10769 switch (command) {
10770 case PARTY_CREATE:
10771 party_create(player, buf);
10772 break;
10773 case PARTY_CREATE_IRONTEAM:
10774 party_create_ironteam(player, buf);
10775 break;
10776 case PARTY_ADD:
10777 if (!Players[player]->party) party_add_self(player, buf);
10778 else party_add(player, buf);
10779 break;
10780 case PARTY_DELETE:
10781 party_remove(player, buf);
10782 break;
10783 case PARTY_REMOVE_ME:
10784 party_leave(player, TRUE);
10785 break;
10786 case PARTY_HOSTILE:
10787 add_hostility(player, buf, TRUE);
10788 break;
10789 case PARTY_PEACE:
10790 remove_hostility(player, buf);
10791 break;
10792 }
10793
10794 return 1;
10795 }
10796
10797 static int Receive_guild(int ind) {
10798 connection_t *connp = Conn[ind];
10799 int player = -1, n;
10800 char ch, buf[MAX_CHARS];
10801 s16b command;
10802 player_type *p_ptr = NULL;
10803
10804 if (connp->id != -1) {
10805 player = GetInd[connp->id];
10806 p_ptr = Players[player];
10807 }
10808 else return 1;
10809
10810 if ((n = Packet_scanf(&connp->r, "%c%hd%s", &ch, &command, buf)) <= 0) {
10811 if (n == -1) Destroy_connection(ind, "read error");
10812 return n;
10813 }
10814
10815 switch (command) {
10816 case GUILD_CREATE:
10817 strcpy(p_ptr->cur_file_title, buf);//hack: abuse cur_file_title
10818 Send_request_cfr(player, RID_GUILD_CREATE, format("Creating a guild costs %d Au. Are you sure?", GUILD_PRICE), FALSE);
10819 break;
10820 case GUILD_ADD:
10821 if (!p_ptr->guild) guild_add_self(player, buf);
10822 else guild_add(player, buf);
10823 break;
10824 case GUILD_DELETE:
10825 guild_remove(player, buf);
10826 break;
10827 case GUILD_REMOVE_ME:
10828 guild_leave(player, TRUE);
10829 break;
10830 }
10831
10832 return 1;
10833 }
10834
10835 static int Receive_guild_config(int ind) {
10836 connection_t *connp = Conn[ind];
10837 int player = 0, n, j;
10838 char ch, adder[MAX_CHARS];
10839 int command;
10840 u32b flags;
10841 guild_type *guild;
10842 player_type *p_ptr, *q_ptr;
10843
10844 if (connp->id != -1) player = GetInd[connp->id];
10845 if ((n = Packet_scanf(&connp->r, "%c%d%d%s", &ch, &command, &flags, adder)) <= 0) {
10846 if (n == -1) Destroy_connection(ind, "read error");
10847 return n;
10848 }
10849 if (!player) return 1;
10850 p_ptr = Players[player];
10851
10852 /* Must be a guild master */
10853 if (!p_ptr->guild) {
10854 s_printf("GUILDCFG_EXPLOIT: (noguild) %s(%s) - %d, %d, %s\n", p_ptr->name, p_ptr->accountname, command, flags, adder);
10855 return 1;
10856 }
10857 guild = &guilds[p_ptr->guild];
10858 if (guild->master != p_ptr->id) {
10859 s_printf("GUILDCFG_EXPLOIT: (nomaster) %s(%s) - %d, %d, %s\n", p_ptr->name, p_ptr->accountname, command, flags, adder);
10860 return 1;
10861 }
10862
10863 switch (command) {
10864 case 0: /* set flags */
10865 guild->flags = flags;
10866 break;
10867 case 1: /* set minlev */
10868 // if (flags < 0) flags = 0; // always false because flags is unsigned
10869 if (flags > 100) flags = 100;
10870 //msg_format(player, "Minimum level required to join the guild so far was %d..", guild->minlev);
10871 guild->minlev = flags;
10872 //msg_format(player, "..and has now been set to %d.", guild->minlev);
10873 break;
10874 case 2: /* set/remove adder */
10875 if (!adder[0]) break;
10876 adder[0] = toupper(adder[0]); /* be helpful */
10877 n = name_lookup_loose(player, adder, FALSE, FALSE);
10878 if (!n) {
10879 #ifdef GUILD_ADDERS_LIST
10880 /* Handle de-authorization */
10881 for (j = 0; j < 5; j++) if (streq(guild->adder[j], adder)) break;
10882 if (j == 5) {
10883 msg_print(player, "Player must be online to become an adder.");
10884 return 1;
10885 }
10886 if (streq(p_ptr->name, adder)) {
10887 msg_print(player, "As guild master you can always add others.");
10888 return 1;
10889 }
10890 guild->adder[j][0] = '\0';
10891 msg_format(player, "Player \377r%s\377w is no longer authorized to add others.", adder);
10892 break;
10893 #else
10894 msg_print(player, "Player not online.");
10895 return 1;
10896 #endif
10897 }
10898 if (n == player) {
10899 msg_print(player, "As guild master you can always add others.");
10900 return 1;
10901 }
10902 q_ptr = Players[n];
10903 if (q_ptr->guild != p_ptr->guild) {
10904 msg_print(player, "That player is not in your guild.");
10905 return 1;
10906 }
10907
10908 if ((q_ptr->guild_flags & PGF_ADDER)) {
10909 #ifdef GUILD_ADDERS_LIST
10910 for (j = 0; j < 5; j++) if (streq(guild->adder[j], q_ptr->name)) {
10911 guild->adder[j][0] = '\0';
10912 break;
10913 }
10914 #endif
10915
10916 q_ptr->guild_flags &= ~PGF_ADDER;
10917 //msg_format(player, "Player \377r%s\377w is no longer authorized to add others.", q_ptr->name);
10918 msg_format(n, "\374\377%cGuild master %s \377rretracted\377%c your authorization to add others.", COLOUR_CHAT_GUILD, p_ptr->name, COLOUR_CHAT_GUILD);
10919 } else {
10920 #ifdef GUILD_ADDERS_LIST
10921 /* look if we have less than 5 adders still */
10922 for (j = 0; j < 5; j++) if (guild->adder[j][0] == '\0') break; /* found a vacant slot? */
10923 if (j == 5) {
10924 msg_print(player, "You cannot designate more than 5 adders.");
10925 return 1;
10926 }
10927 strcpy(guild->adder[j], q_ptr->name);
10928 #endif
10929
10930 q_ptr->guild_flags |= PGF_ADDER;
10931 //msg_format(player, "Player \377G%s\377w is now authorized to add other players.", q_ptr->name);
10932 msg_format(n, "\374\377%cGuild master %s \377Gauthorized\377%c you to add other players.", COLOUR_CHAT_GUILD, p_ptr->name, COLOUR_CHAT_GUILD);
10933 if (!(guild->flags & GFLG_ALLOW_ADDERS)) {
10934 //spam msg_print(player, "Note that currently the guild configuration prevents 'adders'!");
10935 //msg_print(player, "However, note that currently the guild configuration still prevent this!");
10936 //msg_print(player, "To toggle the corresponding flag, use '/guild_cfg adders' command.");
10937 }
10938 }
10939 break;
10940 }
10941
10942 Send_guild_config(p_ptr->guild);
10943 return 1;
10944 }
10945
10946 void Handle_direction(int Ind, int dir) {
10947 player_type *p_ptr = Players[Ind];//, *p_ptr2 = NULL;
10948 //int Ind2;
10949 //s_printf("hd dir,current_spell,current_realm=%d,%d,%d\n", dir, p_ptr->current_spell, p_ptr->current_realm);
10950
10951 /* New '+' feat in 4.4.6.2 */
10952 if (dir == 11) { /* repeat forever, if we keep pressing '+', yay.. */
10953 get_aim_dir(Ind);
10954 return;
10955 }
10956
10957 if (!dir) {
10958 p_ptr->current_char = 0;
10959 p_ptr->current_spell = -1;
10960 p_ptr->current_mind = -1;
10961 p_ptr->current_rod = -1;
10962 p_ptr->current_activation = -1;
10963 p_ptr->current_rcraft = -1;
10964 p_ptr->current_wand = -1;
10965 p_ptr->current_item = -1;
10966 p_ptr->current_book = -1;
10967 p_ptr->current_aux = -1;
10968 p_ptr->current_realm = -1;
10969 p_ptr->current_fire = -1;
10970 p_ptr->current_throw = -1;
10971 p_ptr->current_breath = 0;
10972 return;
10973 }
10974
10975 //Ind2 = get_esp_link(Ind, LINKF_MISC, &p_ptr2);
10976
10977 if (p_ptr->current_spell != -1) {
10978 // if (p_ptr->current_realm == REALM_GHOST)
10979 if (p_ptr->ghost)
10980 do_cmd_ghost_power_aux(Ind, dir);
10981 else if (p_ptr->current_realm == REALM_MIMIC)
10982 do_mimic_power_aux(Ind, dir);
10983 else if (p_ptr->current_realm == REALM_SCHOOL)
10984 cast_school_spell(Ind, p_ptr->current_book, p_ptr->current_spell,
10985 dir, p_ptr->current_item, p_ptr->current_aux);
10986 else p_ptr->current_spell = -1;
10987 }
10988 else if (p_ptr->current_rcraft != -1)
10989 (void)cast_rune_spell(Ind, dir, p_ptr->current_rcraft_e_flags, p_ptr->current_rcraft_m_flags, 0, 0);
10990 else if (p_ptr->current_rod != -1)
10991 do_cmd_zap_rod_dir(Ind, dir);
10992 else if (p_ptr->current_activation != -1)
10993 do_cmd_activate_dir(Ind, dir);
10994 else if (p_ptr->current_wand != -1)
10995 do_cmd_aim_wand(Ind, p_ptr->current_wand, dir);
10996 else if (p_ptr->current_fire != -1)
10997 do_cmd_fire(Ind, dir);
10998 else if (p_ptr->current_throw != -1)
10999 do_cmd_throw(Ind, dir, p_ptr->current_throw, 0);
11000 else if (p_ptr->current_breath != 0)
11001 do_cmd_breathe_aux(Ind, dir);
11002 }
11003
11004 void Handle_item(int Ind, int item) {
11005 player_type *p_ptr = Players[Ind];
11006 int i;
11007
11008 if ((p_ptr->current_enchant_h > 0) || (p_ptr->current_enchant_d > 0) ||
11009 (p_ptr->current_enchant_a > 0)) {
11010 enchant_spell_aux(Ind, item, p_ptr->current_enchant_h,
11011 p_ptr->current_enchant_d, p_ptr->current_enchant_a,
11012 p_ptr->current_enchant_flag);
11013 } else if (p_ptr->current_identify) {
11014 ident_spell_aux(Ind, item);
11015 } else if (p_ptr->current_star_identify) {
11016 identify_fully_item(Ind, item);
11017 } else if (p_ptr->current_recharge) {
11018 recharge_aux(Ind, item, p_ptr->current_recharge);
11019 } else if (p_ptr->current_artifact) {
11020 create_artifact_aux(Ind, item);
11021 } else if (p_ptr->current_telekinesis != NULL) {
11022 telekinesis_aux(Ind, item);
11023 } else if (p_ptr->current_curse != 0) {
11024 curse_spell_aux(Ind, item);
11025 } else if (p_ptr->current_tome_creation) {
11026 /* swap-hack: activating a custom tome uses up
11027 the TARGET item, not the tome, of course */
11028 i = p_ptr->using_up_item;
11029 p_ptr->using_up_item = item;
11030 tome_creation_aux(Ind, i);
11031 } else if (p_ptr->current_rune) {
11032 rune_combine_aux(Ind, item);
11033 }
11034
11035 /* to be safe, clean up; just in case our item was used up */
11036 for (i = 0; i < INVEN_PACK; i++) inven_item_optimize(Ind, i);
11037 }
11038
11039 /* Is it a king and on his land ? */
11040 bool player_is_king(int Ind) {
11041 player_type *p_ptr = Players[Ind];
11042
11043 return FALSE;
11044
11045 if (p_ptr->total_winner && ((inarea(&p_ptr->own1, &p_ptr->wpos)) || (inarea(&p_ptr->own2, &p_ptr->wpos))))
11046 return TRUE;
11047
11048 /* Assume false */
11049 return FALSE;
11050 }
11051
11052 /* receive a dungeon master command */
11053 static int Receive_master(int ind) {
11054 connection_t *connp = Conn[ind];
11055 int player = -1, n;
11056 char ch, buf[MAX_CHARS];
11057 s16b command;
11058
11059 if (connp->id != -1) player = GetInd[connp->id];
11060 else player = 0;
11061
11062 /* Make sure this came from the dungeon master. Note that it may be
11063 * possible to spoof this, so probably in the future more advanced
11064 * authentication schemes will be neccecary. -APD
11065 */
11066
11067 /* Is this necessary here? Maybe (evileye) */
11068 if (!admin_p(player) &&
11069 !player_is_king(player) && !guild_build(player)) {
11070 /* Hack -- clear the receive and queue buffers since we won't be
11071 * reading in the dungeon master parameters that were sent.
11072 */
11073 Sockbuf_clear(&connp->r);
11074 Sockbuf_clear(&connp->c);
11075 return 2;
11076 }
11077
11078 if ((n = Packet_scanf(&connp->r, "%c%hd%s", &ch, &command, buf)) <= 0) {
11079 if (n == -1) Destroy_connection(ind, "read error");
11080 return n;
11081 }
11082
11083 if (player) {
11084 switch (command) {
11085 case MASTER_LEVEL:
11086 master_level(player, buf);
11087 break;
11088 case MASTER_BUILD:
11089 master_build(player, buf);
11090 break;
11091 case MASTER_SUMMON:
11092 master_summon(player, buf);
11093 break;
11094 case MASTER_GENERATE:
11095 master_generate(player, buf);
11096 break;
11097 case MASTER_PLAYER:
11098 master_player(player, buf);
11099 break;
11100 case MASTER_SCRIPTS:
11101 master_script_exec(player, buf);
11102 break;
11103 case MASTER_SCRIPTB:
11104 master_script_begin(buf + 1, *buf);
11105 break;
11106 case MASTER_SCRIPTE:
11107 master_script_end();
11108 break;
11109 case MASTER_SCRIPTL:
11110 master_script_line(buf);
11111 break;
11112 }
11113 }
11114
11115 return 2;
11116 }
11117
11118 /* automatic phase command, will try to phase door
11119 * in the best way possobile.
11120 *
11121 * This function should probably be improved a lot, I am just
11122 * doing a basic version for now.
11123 */
11124
11125 static int Receive_autophase(int ind) {
11126 player_type *p_ptr = NULL;
11127 connection_t *connp = Conn[ind];
11128 object_type *o_ptr;
11129 int player = -1, n;
11130
11131 if (connp->id != -1) player = GetInd[connp->id];
11132 else player = 0;
11133
11134 /* a valid player was found, try to do the autophase */
11135 if (player) {
11136 p_ptr = Players[player];
11137 /* first, check the inventory for phase scrolls */
11138 /* check every item of his inventory */
11139 for (n = 0; n < INVEN_PACK; n++) {
11140 o_ptr = &p_ptr->inventory[n];
11141 if ((o_ptr->tval == TV_SCROLL) && (o_ptr->sval == SV_SCROLL_PHASE_DOOR)) {
11142 /* found a phase scroll, read it! */
11143 do_cmd_read_scroll(player, n);
11144 return 1;
11145 }
11146 }
11147 }
11148
11149 /* Failure! We are in trouble... */
11150
11151 return -1;
11152 }
11153
11154 void end_mind(int Ind, bool update) {
11155 // int Ind2;
11156 player_type *p_ptr = Players[Ind];//, *p_ptr2;
11157
11158 #if 0 /* end_mind() is called by get_esp_link() ! -> infinite recursion in a rare case */
11159 if ((Ind2 = get_esp_link(Ind, LINKF_VIEW, &p_ptr2))) p_ptr2->update |= PU_MUSIC;
11160 #endif
11161 if (p_ptr->esp_link_flags & LINKF_VIEW_DEDICATED) p_ptr->update |= PU_MUSIC;
11162
11163 #if 1 /* in addition, end link on viewee's side -- at least if it's a hidden link, for now */
11164 if (p_ptr->esp_link_type &&
11165 p_ptr->esp_link &&
11166 (p_ptr->esp_link_flags & LINKF_HIDDEN)) { //add LINKF_VIEW too?
11167 int Ind2 = find_player(p_ptr->esp_link);
11168 if (Ind2) {
11169 player_type *p2_ptr = Players[Ind2];
11170
11171 if (!(p2_ptr->esp_link_flags & LINKF_HIDDEN)) msg_print(Ind2, "\377REnding mind link.");
11172
11173 p2_ptr->esp_link = 0;
11174 p2_ptr->esp_link_type = 0;
11175 //p2_ptr->esp_link_flags = 0;
11176 p2_ptr->esp_link_flags &= ~(LINKF_VIEW | LINKF_HIDDEN);
11177 p2_ptr->esp_link_end = 0; //obsolete? (not saved anyway)
11178 }
11179 }
11180 #endif
11181
11182 /* end link on viewer's side */
11183 if (!(p_ptr->esp_link_flags & LINKF_HIDDEN)) msg_print(Ind, "\377REnding mind link.");
11184 p_ptr->esp_link = 0;
11185 p_ptr->esp_link_type = 0;
11186 p_ptr->esp_link_flags = 0;
11187 if (update) {
11188 p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
11189 p_ptr->update |= (PU_BONUS | PU_VIEW | PU_MANA | PU_HP);
11190 p_ptr->redraw |= (PR_BASIC | PR_EXTRA | PR_MAP);
11191 }
11192 }
11193
11194 static int Receive_spike(int ind) {
11195 connection_t *connp = Conn[ind];
11196 player_type *p_ptr = NULL;
11197 char ch, dir;
11198 int n, player = -1;
11199
11200 if (connp->id != -1) {
11201 player = GetInd[connp->id];
11202 use_esp_link(&player, LINKF_OBJ);
11203 p_ptr = Players[player];
11204 }
11205
11206 if ((n = Packet_scanf(&connp->r, "%c%c", &ch, &dir)) <= 0) {
11207 if (n == -1) Destroy_connection(ind, "read error");
11208 return n;
11209 }
11210
11211 /* Sanity check */
11212 if (bad_dir(dir)) return 1;
11213
11214 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
11215 do_cmd_spike(player, dir);
11216 return 2;
11217 } else if (p_ptr) {
11218 Packet_printf(&connp->q, "%c%c", ch, dir);
11219 return 0;
11220 }
11221
11222 return 1;
11223 }
11224
11225 /*
11226 * Lazy way to add a new command - Jir -
11227 */
11228 static int Receive_raw_key(int ind)
11229 {
11230 connection_t *connp = Conn[ind];
11231 player_type *p_ptr = NULL;
11232
11233 char ch, key;
11234 int n, player = -1;
11235
11236 if (connp->id != -1)
11237 {
11238 player = GetInd[connp->id];
11239 // use_esp_link(&player, LINKF_OBJ); /* might be bad, depending on actual command */
11240 p_ptr = Players[player];
11241 }
11242
11243 if ((n = Packet_scanf(&connp->r, "%c%c", &ch, &key)) <= 0)
11244 {
11245 if (n == -1)
11246 Destroy_connection(ind, "read error");
11247 return n;
11248 }
11249
11250 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos))
11251 {
11252 if (p_ptr->store_num != -1)
11253 {
11254 switch (key)
11255 {
11256 default:
11257 msg_format(player, "'%c' key does not work in this building.", key);
11258 break;
11259 }
11260 }
11261 else
11262 {
11263 switch (key)
11264 {
11265 #if 0 /* all in client 4.4.1 or 4.4.0d now! #if 0 this when released */
11266 /* Drink from a fountain (test passed:) */
11267 case '_':
11268 do_cmd_drink_fountain(player);
11269 break;
11270 /* Open/close mind to receive items via telekinesis */
11271 case 'p':
11272 /* But we can also use this for telekinesis! - C. Blue
11273 (mostly to avoid PK exploits */
11274 if (p_ptr->esp_link_flags & LINKF_TELEKIN) {
11275 msg_print(player, "\377RYou stop concentrating on telekinesis.");
11276 p_ptr->esp_link_flags &= ~LINKF_TELEKIN;
11277 } else {
11278 msg_print(player, "\377RYou concentrate on telekinesis!");
11279 p_ptr->esp_link_flags |= LINKF_TELEKIN;
11280 }
11281 break;
11282 case '!':
11283 /* Look at in-game bbs - C. Blue */
11284 msg_print(player, "\377wBulletin board (type '/bbs <text>' in chat to write something) :");
11285 censor_message = TRUE;
11286 for (n = 0; n < BBS_LINES; n++)
11287 if (strcmp(bbs_line[n], "")) {
11288 censor_length = strlen(bbs_line[i]) + bbs_line[i] - strchr(bbs_line[i], ':') - 4;
11289 msg_format(player, "\377s %s", bbs_line[n]);
11290 bbs_empty = FALSE;
11291 }
11292 censor_message = FALSE;
11293 if (bbs_empty) msg_print(player, "\377s <nothing has been written on the board so far>");
11294 break;
11295 // return 1; /* consume no energy/don't disturb character (resting mode) */
11296 #else
11297 case '_':
11298 case '!':
11299 case 'p':
11300 msg_print(player, "\377RYour client is outdated (probably version 4.4.0).");
11301 msg_print(player, "\377RPlease download latest client from www.tomenet.eu");
11302 break;
11303 #endif
11304 default:
11305 msg_format(player, "'%c' key is currently not used. Hit '?' for help.", key);
11306 break;
11307 }
11308 }
11309 return 2;
11310 }
11311 else if (p_ptr)
11312 {
11313 Packet_printf(&connp->q, "%c%c", ch, key);
11314 return 0;
11315 }
11316
11317 return 1;
11318 }
11319
11320 /* Reply to ping packets - mikaelh */
11321 static int Receive_ping(int ind) {
11322 connection_t *connp = Conn[ind];
11323 char ch, pong, buf[MSG_LEN];
11324 int n, id, tim, utim, Ind;
11325 player_type *p_ptr;
11326
11327 if ((n = Packet_scanf(&connp->r, "%c%c%d%d%d%S", &ch, &pong, &id, &tim, &utim, &buf)) <= 0) {
11328 if (n == -1) Destroy_connection(ind, "read error");
11329 return n;
11330 }
11331
11332 if (!pong) {
11333 connp->inactive_ping++;
11334
11335 if (connp->id != -1) {
11336 Ind = GetInd[connp->id];
11337 p_ptr = Players[Ind];
11338
11339 p_ptr->idle++;
11340 p_ptr->idle_char++;
11341
11342 #if (MAX_PING_RECVS_LOGGED > 0)
11343 /* Get the exact time and save it */
11344 p_ptr->pings_received_head = (p_ptr->pings_received_head + 1) % MAX_PING_RECVS_LOGGED;
11345 gettimeofday(&p_ptr->pings_received[(int) p_ptr->pings_received_head], NULL);
11346 #endif
11347
11348 /* Kick a starving player */
11349 if (p_ptr->idle_starve_kick && p_ptr->food < PY_FOOD_WEAK && connp->inactive_ping > STARVE_KICK_TIMER) {
11350 Destroy_connection(ind, STARVING_AUTOKICK_MSG);
11351 return 2;
11352 }
11353
11354 else if (!p_ptr->afk && p_ptr->auto_afk && connp->inactive_ping > AUTO_AFK_TIMER) { /* dont oscillate ;) */
11355 /* auto AFK timer (>1 min) */
11356 // if (!p_ptr->resting) toggle_afk(Ind, ""); /* resting can take quite long sometimes */
11357 toggle_afk(Ind, "");
11358 }
11359 }
11360
11361 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) {
11362 errno = 0;
11363 plog(format("Connection not ready for pong (%d.%d.%d)",
11364 ind, connp->state, connp->id));
11365 return 1;
11366 }
11367
11368 pong = 1;
11369
11370 Packet_printf(&connp->c, "%c%c%d%d%d%S", PKT_PING, pong, id, tim, utim, buf);
11371 }
11372
11373 return 2;
11374 }
11375
11376 static int Receive_sip(int ind) {
11377 connection_t *connp = Conn[ind];
11378 player_type *p_ptr = NULL;
11379 char ch;
11380 int n, player = -1;
11381
11382 if (connp->id != -1)
11383 {
11384 player = GetInd[connp->id];
11385 use_esp_link(&player, LINKF_OBJ);
11386 p_ptr = Players[player];
11387 }
11388 if ((n = Packet_scanf(&connp->r, "%c", &ch)) <= 0) {
11389 if (n == -1) Destroy_connection(ind, "read error");
11390 return n;
11391 }
11392 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
11393 do_cmd_drink_fountain(player);
11394 return 2;
11395 } else if (p_ptr) {
11396 Packet_printf(&connp->q, "%c", ch);
11397 return 0;
11398 }
11399 return 1;
11400 }
11401
11402
11403 static int Receive_telekinesis(int ind) {
11404 #if 1 /* taken over by Receive_mind() now, that mindcrafters got fusion */
11405 return Receive_mind(ind);
11406 #else
11407 connection_t *connp = Conn[ind];
11408 player_type *p_ptr = NULL;
11409 char ch;
11410 int n, player = -1;
11411
11412 if (connp->id != -1)
11413 {
11414 player = GetInd[connp->id];
11415 use_esp_link(&player, LINKF_OBJ);
11416 p_ptr = Players[player];
11417 }
11418 if ((n = Packet_scanf(&connp->r, "%c", &ch)) <= 0) {
11419 if (n == -1) Destroy_connection(ind, "read error");
11420 return n;
11421 }
11422 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
11423 /* Open/close mind to receive items via telekinesis */
11424 /* But we can also use this for telekinesis! - C. Blue
11425 (mostly to avoid PK exploits */
11426 if (p_ptr->esp_link_flags & LINKF_TELEKIN) {
11427 msg_print(player, "\377yYou stop concentrating on telekinesis.");
11428 p_ptr->esp_link_flags &= ~LINKF_TELEKIN;
11429 } else {
11430 msg_print(player, "\377RYou concentrate on telekinesis!");
11431 p_ptr->esp_link_flags |= LINKF_TELEKIN;
11432 }
11433 return 2;
11434 } else if (p_ptr) {
11435 Packet_printf(&connp->q, "%c", ch);
11436 return 0;
11437 }
11438 return 1;
11439 #endif
11440 }
11441
11442 static int Receive_BBS(int ind) {
11443 connection_t *connp = Conn[ind];
11444 player_type *p_ptr = NULL;
11445 char ch;
11446 int n, player = -1;
11447 bool bbs_empty = TRUE;
11448
11449 if (connp->id != -1)
11450 {
11451 player = GetInd[connp->id];
11452 p_ptr = Players[player];
11453 }
11454 if ((n = Packet_scanf(&connp->r, "%c", &ch)) <= 0) {
11455 if (n == -1) Destroy_connection(ind, "read error");
11456 return n;
11457 }
11458 if (p_ptr) {
11459 /* Look at in-game bbs - C. Blue */
11460 msg_print(player, "\377sBulletin board (type '/bbs <text>' in chat to write something):");
11461 censor_message = TRUE;
11462 for (n = 0; n < BBS_LINES; n++)
11463 if (strcmp(bbs_line[n], "")) {
11464 censor_length = strlen(bbs_line[n]) + bbs_line[n] - strchr(bbs_line[n], ':') - 4;
11465 msg_format(player, "\377s %s", bbs_line[n]);
11466 bbs_empty = FALSE;
11467 }
11468 censor_message = FALSE;
11469 if (bbs_empty) msg_print(player, "\377s <nothing has been written on the board so far>");
11470 return 2; /* consume no energy/don't disturb character (resting mode) */
11471 } else if (p_ptr) {
11472 Packet_printf(&connp->q, "%c", ch);
11473 return 0;
11474 }
11475 return 1;
11476 }
11477
11478 static int Receive_wield2(int ind) {
11479 connection_t *connp = Conn[ind];
11480 player_type *p_ptr = NULL;
11481
11482 char ch;
11483 s16b item;
11484 int n, player = -1;
11485
11486 if (connp->id != -1) {
11487 player = GetInd[connp->id];
11488 use_esp_link(&player, LINKF_OBJ);
11489 p_ptr = Players[player];
11490 }
11491 if ((n = Packet_scanf(&connp->r, "%c%hd", &ch, &item)) <= 0) {
11492 if (n == -1) Destroy_connection(ind, "read error");
11493 return n;
11494 }
11495
11496 /* Sanity check - mikaelh */
11497 if (item >= INVEN_TOTAL)
11498 return 1;
11499
11500 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
11501 item = replay_inven_changes(player, item);
11502 if (item == 0xFF)
11503 {
11504 msg_print(player, "Command failed because item is gone.");
11505 return 1;
11506 }
11507
11508 do_cmd_wield(player, item, 0x2);
11509 return 2;
11510 } else if (p_ptr) {
11511 Packet_printf(&connp->q, "%c%hd", ch, item);
11512 return 0;
11513 }
11514 return 1;
11515 }
11516
11517 static int Receive_cloak(int ind) {
11518 connection_t *connp = Conn[ind];
11519 player_type *p_ptr = NULL;
11520 char ch;
11521 int n, player = -1;
11522
11523 if (connp->id != -1)
11524 {
11525 player = GetInd[connp->id];
11526 use_esp_link(&player, LINKF_OBJ);
11527 p_ptr = Players[player];
11528 }
11529 if ((n = Packet_scanf(&connp->r, "%c", &ch)) <= 0) {
11530 if (n == -1) Destroy_connection(ind, "read error");
11531 return n;
11532 }
11533 if (p_ptr && p_ptr->energy >= level_speed(&p_ptr->wpos)) {
11534 do_cmd_cloak(player);
11535 return 2;
11536 } else if (p_ptr) {
11537 Packet_printf(&connp->q, "%c", ch);
11538 return 0;
11539 }
11540 return 1;
11541 }
11542
11543 void change_mind(int Ind, bool open_or_close) {
11544 int Ind2;
11545 player_type *p_ptr = Players[Ind], *p_ptr2 = NULL;
11546 bool d = TRUE;
11547
11548 /* 'hidden link' is unaffected by 'passive' change_mind() calls */
11549 if ((p_ptr->esp_link_flags & LINKF_HIDDEN) && !open_or_close) return;
11550
11551 if ((Ind2 = get_esp_link(Ind, 0x0, &p_ptr2)) &&
11552 !(p_ptr->esp_link_flags & LINKF_HIDDEN)) {
11553 if (p_ptr->esp_link_type == LINK_DOMINATED) {
11554 if (!p_ptr->esp_link_end) {
11555 p_ptr->esp_link_end = rand_int(6) + 15;
11556 } else {
11557 /* can't stabilize link while on different floors! */
11558 if (!inarea(&p_ptr->wpos, &p_ptr2->wpos)) return;
11559
11560 p_ptr->esp_link_end = 0;
11561 d = FALSE;
11562 }
11563 }
11564 if (p_ptr2->esp_link_type == LINK_DOMINATED) {
11565 if (!p_ptr2->esp_link_end) {
11566 p_ptr2->esp_link_end = rand_int(6) + 15;
11567 } else {
11568 /* can't stabilize link while on different floors! */
11569 if (!inarea(&p_ptr->wpos, &p_ptr2->wpos)) return;
11570
11571 p_ptr2->esp_link_end = 0;
11572 d = FALSE;
11573 }
11574 }
11575
11576 if (d) {
11577 if (!(p_ptr->esp_link_flags & LINKF_HIDDEN)) {
11578 msg_format(Ind, "\377RThe mind link with %s begins to break.", p_ptr2->name);
11579 msg_format(Ind2, "\377RThe mind link with %s begins to break.", p_ptr->name);
11580 }
11581 } else {
11582 if (!(p_ptr->esp_link_flags & LINKF_HIDDEN)) {
11583 msg_format(Ind, "\377yThe mind link with %s stabilizes.", p_ptr2->name);
11584 msg_format(Ind2, "\377yThe mind link with %s stabilizes.", p_ptr->name);
11585 }
11586 }
11587 } else {
11588 if (p_ptr->esp_link_flags & LINKF_OPEN) {
11589 msg_print(Ind, "\377yYou close your mind.");
11590 p_ptr->esp_link_flags &= ~(LINKF_OPEN | LINKF_TELEKIN);
11591 } else {
11592 msg_print(Ind, "\377RYou open your mind..");
11593 p_ptr->esp_link_flags |= (LINKF_OPEN | LINKF_TELEKIN);
11594 }
11595 }
11596 }
11597
11598 static int Receive_inventory_revision(int ind) {
11599 connection_t *connp = Conn[ind];
11600 player_type *p_ptr = NULL;
11601 char ch;
11602 int n, player = -1;
11603 int revision;
11604
11605 if (connp->id != -1)
11606 {
11607 player = GetInd[connp->id];
11608 p_ptr = Players[player];
11609 }
11610 if ((n = Packet_scanf(&connp->r, "%c%d", &ch, &revision)) <= 0) {
11611 if (n == -1) Destroy_connection(ind, "read error");
11612 return n;
11613 }
11614 if (p_ptr) {
11615 if (connp->q.len) {
11616 /* There are some queued packets, block any further
11617 * packets until the queue is empty
11618 */
11619 Packet_printf(&connp->q, "%c%d", ch, revision);
11620 return 3; /* special return code */
11621 } else {
11622 inven_confirm_revision(player, revision);
11623 return 2;
11624 }
11625 } else if (p_ptr) {
11626 Packet_printf(&connp->q, "%c%d", ch, revision);
11627 return 0;
11628 }
11629 return 1;
11630 }
11631
11632 static int Receive_account_info(int ind) {
11633 connection_t *connp = Conn[ind];
11634 char ch;
11635 int n, player = -1;
11636
11637 if (connp->id != -1)
11638 {
11639 player = GetInd[connp->id];
11640 }
11641 if ((n = Packet_scanf(&connp->r, "%c", &ch)) <= 0) {
11642 if (n == -1) Destroy_connection(ind, "read error");
11643 return n;
11644 }
11645
11646 if (player > 0) {
11647 Send_account_info(player);
11648 }
11649
11650 return 1;
11651 }
11652
11653 static int Receive_change_password(int ind) {
11654 connection_t *connp = Conn[ind];
11655 char ch;
11656 int n, player = -1;
11657 char old_pass[MAX_CHARS], new_pass[MAX_CHARS];
11658
11659 if (connp->id != -1)
11660 {
11661 player = GetInd[connp->id];
11662 }
11663 if ((n = Packet_scanf(&connp->r, "%c%s%s", &ch, old_pass, new_pass)) <= 0) {
11664 if (n == -1) Destroy_connection(ind, "read error");
11665 return n;
11666 }
11667
11668 if (player > 0) {
11669 /* Obfuscation */
11670 my_memfrob(old_pass, strlen(old_pass));
11671 my_memfrob(new_pass, strlen(new_pass));
11672
11673 account_change_password(player, old_pass, new_pass);
11674
11675 /* Wipe the passwords from memory */
11676 memset(old_pass, 0, MAX_CHARS);
11677 memset(new_pass, 0, MAX_CHARS);
11678 }
11679
11680 return 1;
11681 }
11682
11683 static int Receive_force_stack(int ind) {
11684 connection_t *connp = Conn[ind];
11685 char ch;
11686 int n, player = -1;
11687 s16b item;
11688 player_type *p_ptr = NULL;
11689
11690 if (connp->id != -1)
11691 {
11692 player = GetInd[connp->id];
11693 use_esp_link(&player, LINKF_OBJ);
11694 p_ptr = Players[player];
11695 }
11696
11697 if ((n = Packet_scanf(&connp->r, "%c%hd", &ch, &item)) <= 0)
11698 {
11699 if (n == -1)
11700 Destroy_connection(ind, "read error");
11701 return n;
11702 }
11703
11704 /* Sanity check - mikaelh */
11705 if (item >= INVEN_PACK)
11706 return 1;
11707
11708 if (p_ptr) {
11709 item = replay_inven_changes(player, item);
11710 if (item == 0xFF)
11711 {
11712 msg_print(player, "Command failed because item is gone.");
11713 return 1;
11714 }
11715
11716 do_cmd_force_stack(player, item);
11717 }
11718
11719 return 1;
11720 }
11721
11722 static int Receive_request_key(int ind) {
11723 connection_t *connp = Conn[ind];
11724 player_type *p_ptr = NULL;
11725
11726 char ch, key;
11727 int n, id, player = -1;
11728 if (connp->id != -1) {
11729 player = GetInd[connp->id];
11730 // use_esp_link(&player, LINKF_OBJ);
11731 p_ptr = Players[player];
11732 }
11733
11734 if ((n = Packet_scanf(&connp->r, "%c%d%c", &ch, &id, &key)) <= 0) {
11735 if (n == -1) Destroy_connection(ind, "read error");
11736 return n;
11737 }
11738 if (!p_ptr) return 1;
11739
11740 handle_request_return_key(player, id, key);
11741 return 2;
11742 }
11743 static int Receive_request_num(int ind) {
11744 connection_t *connp = Conn[ind];
11745 player_type *p_ptr = NULL;
11746
11747 char ch;
11748 int n, id, player = -1, num;
11749 if (connp->id != -1) {
11750 player = GetInd[connp->id];
11751 // use_esp_link(&player, LINKF_OBJ);
11752 p_ptr = Players[player];
11753 }
11754
11755 if ((n = Packet_scanf(&connp->r, "%c%d%d", &ch, &id, &num)) <= 0) {
11756 if (n == -1) Destroy_connection(ind, "read error");
11757 return n;
11758 }
11759 if (!p_ptr) return 1;
11760
11761 handle_request_return_num(player, id, num);
11762 return 2;
11763 }
11764 static int Receive_request_str(int ind) {
11765 connection_t *connp = Conn[ind];
11766 player_type *p_ptr = NULL;
11767
11768 char ch, str[MSG_LEN];
11769 int n, id, player = -1;
11770 if (connp->id != -1) {
11771 player = GetInd[connp->id];
11772 // use_esp_link(&player, LINKF_OBJ);
11773 p_ptr = Players[player];
11774 }
11775
11776 if ((n = Packet_scanf(&connp->r, "%c%d%s", &ch, &id, str)) <= 0) {
11777 if (n == -1) Destroy_connection(ind, "read error");
11778 return n;
11779 }
11780 if (!p_ptr) return 1;
11781
11782 handle_request_return_str(player, id, str);
11783 return 2;
11784 }
11785 static int Receive_request_cfr(int ind) {
11786 connection_t *connp = Conn[ind];
11787 player_type *p_ptr = NULL;
11788
11789 char ch;
11790 int n, id, player = -1, cfr;
11791 if (connp->id != -1) {
11792 player = GetInd[connp->id];
11793 // use_esp_link(&player, LINKF_OBJ);
11794 p_ptr = Players[player];
11795 }
11796
11797 if ((n = Packet_scanf(&connp->r, "%c%d%d", &ch, &id, &cfr)) <= 0) {
11798 if (n == -1) Destroy_connection(ind, "read error");
11799 return n;
11800 }
11801 if (!p_ptr) return 1;
11802
11803 handle_request_return_cfr(player, id, (cfr != 0));
11804 return 2;
11805 }
11806
11807
11808 /* return some connection data for improved log handling - C. Blue */
11809 char *get_conn_userhost(int ind) {
11810 return(format("%s@%s", Conn[ind]->real, Conn[ind]->host));
11811 }
11812
11813 char *get_player_ip(int Ind) {
11814 return(Conn[Players[Ind]->conn]->addr);
11815 }
11816
11817 bool get_conn_state_ok(int Ind) {
11818 connection_t *connp = Conn[Players[Ind]->conn];
11819 if (!BIT(connp->state, CONN_PLAYING | CONN_READY)) return FALSE;
11820 return TRUE;
11821 }
11822
11823 sockbuf_t *get_conn_q(int Ind) {
11824 return &Conn[Players[Ind]->conn]->q;
11825 }
11826