Go to the documentation of this file.
73 size_t namelen = strlen(plname);
80 if (
map != NULL &&
pl->ob->map !=
map)
85 if (!strcmp(
name, plname))
90 if (strlen(
pl->ob->name) < namelen)
93 if (!strcmp(
pl->ob->name, plname))
96 if (!strncasecmp(
pl->ob->name, plname, namelen)) {
127 if (
pl->socket == ns)
146 fp = fopen(
buf,
"r");
177 fp = fopen(
buf,
"r");
214 fp = fopen(
buf,
"r");
259 if (*cp ==
'-' || *cp ==
'_')
262 for (; *cp !=
'\0'; cp++)
303 while (
tmp != NULL &&
tmp->next != NULL)
328 p->last_save_tick = 9999999;
335 op->speed_left = 0.5;
359 strncpy(p->
title,
op->arch->clone.name,
sizeof(p->
title)-1);
509 players.push_back(at);
549 for (ol =
list, lastdist = 1000; ol != NULL; ol = ol->
next) {
603 #define DETOUR_AMOUNT 2
618 #define MAX_SPACES 50
654 int lastx, lasty, dir, i, diff, firstdir = 0, lastdir,
max =
MAX_SPACES, mflags, blocked;
672 while (diff > 1 &&
max > 0) {
785 if (
pl->randomitems != NULL)
835 LOG(
llevError,
"give_initial_items: Removing duplicate object %s\n",
op->name);
908 op->chosen_skill = NULL;
914 if (
op->contr->socket->login_method == 0) {
943 if (
op->contr->socket->login_method > 0) {
957 if (
key ==
'q' ||
key ==
'Q') {
961 }
else if (
key ==
'a' ||
key ==
'A') {
963 const char *
name =
op->name;
971 op->contr->password[0] =
'~';
974 if (
pl->socket->login_method >= 1 &&
pl->socket->account_name != NULL) {
1027 op->contr->party_to_join = party;
1039 int roll[4], i, low_index, k;
1041 for (i = 0; i < 4; ++i)
1042 roll[i] = (
int)
RANDOM()%6+1;
1044 for (i = 0, low_index = 0, k = 7; i < 4; ++i)
1049 for (i = 0, k = 0; i < 4; ++i) {
1073 int sum =
op->stats.Str+
op->stats.Dex+
op->stats.Int+
op->stats.Con+
op->stats.Wis+
op->stats.Pow+
op->stats.Cha;
1075 op->stats.Str = roundf(scale *
op->stats.Str);
1076 op->stats.Dex = roundf(scale *
op->stats.Dex);
1077 op->stats.Int = roundf(scale *
op->stats.Int);
1078 op->stats.Con = roundf(scale *
op->stats.Con);
1079 op->stats.Wis = roundf(scale *
op->stats.Wis);
1080 op->stats.Pow = roundf(scale *
op->stats.Pow);
1081 op->stats.Cha = roundf(scale *
op->stats.Cha);
1084 statsort[0] =
op->stats.Str;
1085 statsort[1] =
op->stats.Dex;
1086 statsort[2] =
op->stats.Int;
1087 statsort[3] =
op->stats.Con;
1088 statsort[4] =
op->stats.Wis;
1089 statsort[5] =
op->stats.Pow;
1090 statsort[6] =
op->stats.Cha;
1094 if (statsort[i] < statsort[i+1]) {
1096 statsort[i] = statsort[i+1];
1104 op->stats.Str = statsort[0];
1105 op->stats.Dex = statsort[1];
1106 op->stats.Con = statsort[2];
1107 op->stats.Int = statsort[3];
1108 op->stats.Wis = statsort[4];
1109 op->stats.Pow = statsort[5];
1110 op->stats.Cha = statsort[6];
1112 op->contr->orig_stats.Str =
op->stats.Str;
1113 op->contr->orig_stats.Dex =
op->stats.Dex;
1114 op->contr->orig_stats.Int =
op->stats.Int;
1115 op->contr->orig_stats.Con =
op->stats.Con;
1116 op->contr->orig_stats.Wis =
op->stats.Wis;
1117 op->contr->orig_stats.Pow =
op->stats.Pow;
1118 op->contr->orig_stats.Cha =
op->stats.Cha;
1124 op->contr->levhp[1] = 9;
1125 op->contr->levsp[1] = 6;
1126 op->contr->levgrace[1] = 3;
1129 op->stats.hp =
op->stats.maxhp;
1130 op->stats.sp =
op->stats.maxsp;
1131 op->stats.grace =
op->stats.maxgrace;
1132 op->contr->orig_stats =
op->stats;
1158 if (
op->contr->swap_first == -1) {
1159 LOG(
llevError,
"player.c:swap_stat() - swap_first is -1\n");
1173 op->stats.Str =
op->contr->orig_stats.Str;
1174 op->stats.Dex =
op->contr->orig_stats.Dex;
1175 op->stats.Con =
op->contr->orig_stats.Con;
1176 op->stats.Int =
op->contr->orig_stats.Int;
1177 op->stats.Wis =
op->contr->orig_stats.Wis;
1178 op->stats.Pow =
op->contr->orig_stats.Pow;
1179 op->stats.Cha =
op->contr->orig_stats.Cha;
1186 op->contr->levhp[1] = 9;
1187 op->contr->levsp[1] = 6;
1188 op->contr->levgrace[1] = 3;
1191 op->stats.hp =
op->stats.maxhp;
1192 op->stats.sp =
op->stats.maxsp;
1193 op->stats.grace =
op->stats.maxgrace;
1194 op->contr->orig_stats =
op->stats;
1195 op->contr->swap_first = -1;
1214 int keynum =
key-
'0';
1215 static const int8_t stat_trans[] = {
1226 if (keynum > 0 && keynum <= 7) {
1227 if (
op->contr->swap_first == -1) {
1228 op->contr->swap_first = stat_trans[keynum];
1242 if (
op->map == NULL) {
1292 if (
key ==
'q' ||
key ==
'Q') {
1297 if (
key ==
'd' ||
key ==
'D') {
1320 op->contr->last_save_tick =
pticks;
1324 "Welcome to Crossfire!\n Press `?' for help\n");
1328 "%s entered the game.",
op->name);
1354 if (oldmap !=
op->map) {
1356 op->contr->bed_x =
op->x;
1357 op->contr->bed_y =
op->y;
1375 int x =
op->x,
y =
op->y;
1384 op->stats =
op->contr->orig_stats;
1391 strncpy(
op->contr->title,
op->arch->clone.name,
sizeof(
op->contr->title)-1);
1392 op->contr->title[
sizeof(
op->contr->title)-1] =
'\0';
1399 op->stats.hp =
op->stats.maxhp;
1400 op->stats.sp =
op->stats.maxsp;
1401 op->stats.grace = 0;
1431 int i, stat, failure=0;
1503 strlcpy(
op->contr->title,
op->arch->clone.name,
sizeof(
op->contr->title));
1531 op->stats.hp =
op->stats.maxhp;
1532 op->stats.sp =
op->stats.maxsp;
1533 op->stats.grace = 0;
1569 op->contr->last_save_tick =
pticks;
1603 if (
key !=
'y' &&
key !=
'Y' &&
key !=
'q' &&
key !=
'Q') {
1606 "OK, continuing to play.");
1615 "%s quits the game.",
1618 strcpy(
op->contr->killer,
"quit");
1639 if (
op->contr->socket->account_chars != NULL) {
1644 op->contr->socket->account_chars = NULL;
1662 if (
op->stats.hp < 0) {
1668 if (
op->enemy == NULL) {
1678 if (
op->enemy->map == NULL) {
1696 for (diff = 0; diff < 3; diff++) {
1720 int j, k, wvratio, current_ratio;
1721 char putstring[128], tmpstr[16];
1748 switch (
op->contr->mode) {
1794 "item name: %s item type: %d weight/value: %d",
1799 snprintf(putstring,
sizeof(putstring),
"...flags: ");
1800 for (k = 0; k < 4; k++) {
1801 for (j = 0; j < 32; j++) {
1802 if ((
tmp->flags[k]>>j)&0x01) {
1803 snprintf(tmpstr,
sizeof(tmpstr),
"%d ", k*32+j);
1804 strcat(putstring, tmpstr);
1852 static int checks[] = {
1880 for (
int m = 0; checks[
m] != 0;
m++) {
1900 if (current_ratio >= wvratio) {
1955 object *
tmp = NULL, *ntmp;
1956 int attacknum, attacktype, betterby = 0, i;
1963 && arrow->race ==
type
1971 }
else if (arrow->type ==
ARROW && arrow->race ==
type) {
1973 if (target->
race != NULL
1974 && arrow->slaying != NULL
1975 && strstr(arrow->slaying, target->
race)) {
1982 betterby = (arrow->magic+arrow->stats.dam)*2;
1985 for (attacknum = 0; attacknum <
NROFATTACKS; attacknum++) {
1986 attacktype = 1<<attacknum;
1987 if ((arrow->attacktype&attacktype) && (target->
arch->
clone.
resist[attacknum]) < 0)
1988 if (((arrow->magic+arrow->stats.dam)*(100-target->
arch->
clone.
resist[attacknum])/100) > betterby) {
1990 betterby = (arrow->magic+arrow->stats.dam)*(100-target->
arch->
clone.
resist[attacknum])/100;
1993 if ((2+arrow->magic+arrow->stats.dam) > betterby) {
1995 betterby = 2+arrow->magic+arrow->stats.dam;
1997 if (arrow->title && (1+arrow->magic+arrow->stats.dam) > betterby) {
1999 betterby = 1+arrow->magic+arrow->stats.dam;
2027 int i, mflags,
found, number;
2030 if (
op->map == NULL)
2035 if (number > (
op->stats.Dex+(
op->chosen_skill ?
op->chosen_skill->level :
op->level)))
2043 for (i = 0,
found = 0; i < 20; i++) {
2093 int fire_bow(
object *
op,
object *arrow,
int dir,
int wc_mod, int16_t sx, int16_t sy) {
2096 int bowspeed, mflags;
2101 "You can't shoot yourself!");
2112 "You cannot use %s without the skill %s", bow->
name, bow->
skill);
2122 LOG(
llevError,
"Range: bow without activated bow (%s).\n",
op->name);
2128 "Your %s is broken.",
2141 if (arrow == NULL) {
2143 if (arrow == NULL) {
2147 "You have no %s left.",
2164 if (arrow->
nrof == 0) {
2171 if (arrow == NULL) {
2173 "You have no %s left.",
2185 op->speed_left = 0.01-(float)
FABS(
op->speed)*100/bowspeed;
2220 int mod = bow->
magic
2227 int plmod = (
op->chosen_skill ?
op->chosen_skill->level :
op->level);
2228 if (plmod+mod > 140)
2230 else if (plmod+mod < -100)
2232 arrow->
stats.
wc = 20-(int8_t)plmod-(int8_t)mod;
2234 arrow->
level =
op->chosen_skill ?
op->chosen_skill->level :
op->level;
2287 if ((
a % 8) + 1 ==
b || (
a + 6 % 8) + 1 ==
b)
2309 int ret = 0, wcmod = 0;
2313 }
else if (
op->contr->bowtype >=
bow_n &&
op->contr->bowtype <=
bow_nw) {
2351 "You have no range item readied.");
2359 if (
item->stats.food <= 0) {
2363 "The %s goes poof.",
2367 }
else if (
item->type ==
ROD) {
2372 "The %s whines for a while, but nothing happens.",
2382 }
else if (
item->type ==
ROD) {
2402 switch (
op->contr->shoottype) {
2423 op->contr->golem_count = 0;
2429 if (!
op->chosen_skill) {
2432 "You have no applicable skill to use.");
2444 "Illegal shoot type.");
2472 if (container->
inv == NULL)
2506 if (
pl != container) {
2525 || (
pl->contr->usekeys ==
keyrings && (!container->
race || strcmp(container->
race,
"keys")))) {
2532 "The %s in your %s vibrates as you approach the door",
2533 name_tmp, name_cont);
2572 "You open the door with the %s",
2589 if (door->
msg && *door->
msg) {
2596 if (door->
type ==
DOOR &&
op->contr && !
op->contr->run_on) {
2624 object *
mon, *tpl, *mon_owner;
2626 int on_battleground;
2629 if (
op->contr->transport)
2630 tpl =
op->contr->transport;
2633 assert(tpl->
map != NULL);
2712 if (
op->contr->braced)
2716 if (
op->contr->tmp_invis ||
op->hide)
2728 && (
op->contr->peaceful && !on_battleground)) {
2729 if (!
op->contr->braced) {
2734 "You withhold your attack");
2736 if (
op->contr->tmp_invis ||
op->hide)
2762 if (
op->weapon_speed_left < 0) {
2763 op->speed_left = -0.01;
2766 op->weapon_speed_left -= 1.0;
2789 else if (bef != tpl->
map) {
2807 if (dir == 1 || dir == 5) {
2809 for (
y = 0;
y <= sy;
y++) {
2810 for (
x = 0;
x < sx;
x++) {
2817 }
else if (dir == 3 || dir == 7) {
2819 for (
y = 0;
y < sy;
y++) {
2820 for (
x = 0;
x <= sx;
x++) {
2830 for (part = transport; part; part = part->
more) {
2846 int x,
y, scroll_dir = 0;
2853 if (transport->
direction == 1 && dir == 8) {
2855 }
else if (transport->
direction == 2 && dir == 3) {
2857 }
else if (transport->
direction == 3 && dir == 2) {
2859 }
else if (transport->
direction == 5 && dir == 6) {
2861 }
else if (transport->
direction == 6 && dir == 5) {
2863 }
else if (transport->
direction == 7 && dir == 8) {
2865 }
else if (transport->
direction == 8 && dir == 7) {
2867 }
else if (transport->
direction == 8 && dir == 1) {
2879 if (
x != transport->
x ||
y != transport->
y) {
2884 pl->contr->do_los = 1;
2885 pl->map = transport->
map;
2889 pl->contr->socket->update_look = 1;
2890 pl->contr->socket->look_position = 0;
2949 object *transport =
op->contr->transport;
2955 if ((dir < 0) || (dir >= 9)) {
2956 LOG(
llevError,
"move_player: invalid direction %d\n", dir);
2969 if (transport->
contr !=
op->contr)
2982 if (
op->speed_left < 0.0)
2983 op->speed_left = -0.01;
2999 if (
op->contr->fire_on) {
3009 if (
op->contr->fire_on || (
op->contr->run_on && pick != 0)) {
3010 op->direction = dir;
3028 object *transport =
op->contr->transport;
3034 if ((dir < 0) || (dir >= 9)) {
3035 LOG(
llevError,
"move_player: invalid direction %d\n", dir);
3048 if (transport->
contr !=
op->contr)
3066 if (
op->contr->fire_on ||
op->contr->run_on) {
3067 op->direction = dir;
3087 if (
op->contr->hidden) {
3088 op->invisible = 1000;
3097 if (!
op->invisible) {
3100 "Your invisibility spell runs out.");
3121 op->contr->golem_count = 0;
3133 "You can stretch your stiff joints once more.");
3137 if (
op->direction && (
op->contr->run_on ||
op->contr->fire_on)) {
3146 if (
op->speed_left > 0)
3177 "Your %s vibrates violently, then evaporates.",
3182 if (
op->stats.hp < 0)
3183 op->stats.hp =
op->stats.maxhp;
3184 if (
op->stats.food < 0)
3189 LOG(
llevError,
"Error: LIFESAVE set without applied object.\n");
3241 strncpy(buf2,
" R.I.P.\n\n", len);
3243 snprintf(
buf,
sizeof(
buf),
"%s the %s\n",
op->name,
op->contr->title);
3245 snprintf(
buf,
sizeof(
buf),
"%s\n",
op->name);
3246 strncat(buf2,
" ", 20-strlen(
buf)/2);
3247 strncat(buf2,
buf, len-strlen(buf2)-1);
3249 snprintf(
buf,
sizeof(
buf),
"who was in level %d when killed\n",
op->level);
3251 snprintf(
buf,
sizeof(
buf),
"who was in level %d when died.\n\n",
op->level);
3252 strncat(buf2,
" ", 20-strlen(
buf)/2);
3253 strncat(buf2,
buf, len-strlen(buf2)-1);
3255 snprintf(
buf,
sizeof(
buf),
"by %s.\n\n",
op->contr->killer);
3256 strncat(buf2,
" ", 21-strlen(
buf)/2);
3257 strncat(buf2,
buf, len-strlen(buf2)-1);
3260 strncat(buf2,
" ", 20-strlen(
buf)/2);
3261 strncat(buf2,
buf, len-strlen(buf2)-1);
3273 int last_food =
op->stats.food;
3274 int gen_hp, gen_sp, gen_grace;
3277 int rate_grace = 2000;
3282 if (
op->contr->gen_hp >= 0)
3283 gen_hp = (
op->contr->gen_hp+1)*
op->stats.maxhp;
3285 gen_hp =
op->stats.maxhp;
3286 rate_hp -= rate_hp/2*
op->contr->gen_hp;
3288 if (
op->contr->gen_sp >= 0)
3289 gen_sp = (
op->contr->gen_sp+1)*
op->stats.maxsp;
3291 gen_sp =
op->stats.maxsp;
3292 rate_sp -= rate_sp/2*
op->contr->gen_sp;
3294 if (
op->contr->gen_grace >= 0)
3295 gen_grace = (
op->contr->gen_grace+1)*
op->stats.maxgrace;
3297 gen_grace =
op->stats.maxgrace;
3298 rate_grace -= rate_grace/2*
op->contr->gen_grace;
3303 gen_sp = gen_sp*10/
MAX(
op->contr->gen_sp_armour, 10);
3304 if (
op->stats.sp <
op->stats.maxsp) {
3309 if (
op->contr->digestion < 0)
3310 op->stats.food +=
op->contr->digestion;
3311 else if (
op->contr->digestion > 0
3313 op->stats.food = last_food;
3316 op->last_sp = rate_sp/(
MAX(gen_sp, 20)+10);
3321 if (--
op->last_grace < 0) {
3322 if (
op->stats.grace <
op->stats.maxgrace/2)
3324 op->last_grace = rate_grace/(
MAX(gen_grace, 20)+10);
3330 if (
op->stats.hp <
op->stats.maxhp) {
3335 if (
op->contr->digestion < 0)
3336 op->stats.food +=
op->contr->digestion;
3337 else if (
op->contr->digestion > 0
3339 op->stats.food = last_food;
3342 op->last_heal = rate_hp/(
MAX(gen_hp, 20)+10);
3346 if (--
op->last_eat < 0) {
3348 int penalty =
MAX(-
op->contr->digestion, 0);
3349 if (
op->contr->gen_hp > 0)
3350 op->last_eat = 25*(1+
bonus)/(
op->contr->gen_hp+penalty+1);
3352 op->last_eat = 25*(1+
bonus)/(penalty+1);
3359 if (
op->contr->state ==
ST_PLAYING &&
op->stats.food < 0 &&
op->stats.hp >= 0) {
3366 object *flesh = NULL;
3372 "You blindly grab for a bite of food.");
3374 if (
op->stats.food >= 0 ||
op->stats.hp < 0)
3383 if (
op->stats.food < 0 &&
op->stats.hp >= 0 && flesh) {
3385 "You blindly grab for a bite of food.");
3394 if (
op->stats.food < 0 &&
op->stats.hp > 0){
3396 int32_t adjust_by =
MIN(-(
op->stats.food),
op->stats.hp);
3397 op->stats.food += adjust_by;
3398 op->stats.hp -= adjust_by;
3414 if (
op->container) {
3429 if (
tmp->nrof > 1) {
3459 "Your body feels cleansed");
3470 "Your mind feels clearer");
3504 assert(trophy != NULL);
3506 "You have been defeated in combat!\n"
3507 "Local medics have saved your life...");
3512 op->stats.hp =
op->stats.maxhp;
3513 if (
op->stats.food <= 0)
3519 snprintf(
buf,
sizeof(
buf),
"%s's %s",
op->name,
tmp->name);
3522 snprintf(
buf,
sizeof(
buf),
3523 "This %s was %s %s the %s, who was defeated at level %d by %s.\n",
3524 tmp->name,
tmp->type ==
FLESH ?
"cut off" :
"taken from",
3525 op->name,
op->contr->title,
3526 (
int)(
op->level),
op->contr->killer);
3532 tmp->materialname = NULL;
3538 op->contr->braced = 0;
3546 if (
op->stats.food < 0) {
3547 snprintf(
buf,
sizeof(
buf),
"%s starved to death.",
op->name);
3548 strcpy(
op->contr->killer,
"starvation");
3550 snprintf(
buf,
sizeof(
buf),
"%s died.",
op->name);
3571 int will_kill_again;
3599 for (
z = 0;
z < num_stats_lose;
z++) {
3618 if (deparch == NULL) {
3638 if (this_stat < 0) {
3640 int keep_chance = this_stat*this_stat;
3642 if (keep_chance < 1)
3658 if (lose_this_stat) {
3668 if (this_stat >= -50) {
3684 if (god && (strcmp(god,
"none")))
3687 "For a brief moment you feel the holy presence of %s protecting you",
3692 "For a brief moment you feel a holy presence protecting you.");
3701 snprintf(
buf,
sizeof(
buf),
"%s's gravestone",
op->name);
3703 snprintf(
buf,
sizeof(
buf),
"%s's gravestones",
op->name);
3705 snprintf(
buf,
sizeof(
buf),
"RIP\nHere rests the hero %s the %s,\n"
3708 op->name,
op->contr->title,
3722 if (
op->stats.food < 100)
3723 op->stats.food = 900;
3724 op->stats.hp =
op->stats.maxhp;
3725 op->stats.sp =
MAX(
op->stats.sp,
op->stats.maxsp);
3726 op->stats.grace =
MAX(
op->stats.grace,
op->stats.maxgrace);
3744 op->contr->braced = 0;
3750 op->contr->mode = 0;
3760 will_kill_again = 0;
3763 will_kill_again |=
tmp->attacktype;
3765 if (will_kill_again) {
3772 force->speed_left = -5.0;
3775 if (will_kill_again&(1<<at))
3776 force->resist[at] = 100;
3819 op->contr->golem_count = 0;
3831 op->stats.hp =
op->stats.maxhp;
3837 sizeof(
op->contr->maplevel));
3838 if (
op->map != NULL)
3850 if (
op->contr->socket->account_chars != NULL) {
3855 op->contr->socket->account_chars = NULL;
3867 snprintf(
buf,
sizeof(
buf),
"%s",
op->name);
3870 tmp->level =
op->level;
3877 snprintf(ac_buf,
sizeof(ac_buf),
"%s",
op->contr->socket->account_name);
3899 LOG(
llevDebug,
"Fixed inventory in %s (%d -> %d)\n",
pl->ob->name, old, sum);
3910 if (!
pl->ob->contr->state)
3928 object *skop, *spob;
3934 LOG(
llevError,
"Player %s lacks critical skill use_magic_item!\n",
op->name);
3937 spob = throw_ob->
inv;
3960 op->contr->tmp_invis = 0;
3961 if (
op->contr->invis_race)
3982 if (
tmp->type == 44 &&
tmp->stats.Wis)
4001 int i,
level = 0, mflag;
4004 if (!
ob || !
ob->map)
4015 level = -(10+(2*
ob->map->darkness));
4045 if (!
op || !
op->map)
4051 if (
op->type ==
PLAYER &&
op->contr->run_on) {
4052 if (!skop || num >= skop->
level) {
4054 "You ran too much! You are no longer hidden!");
4060 num +=
op->map->difficulty;
4064 || ((
op->invisible -= num) <= 0)) {
4068 "You moved out of hiding! You are visible!");
4069 }
else if (
op->type ==
PLAYER && skop) {
4096 for (i = 1; i < 9; i++) {
4158 LOG(
llevError,
"player_can_view() called for non-player object\n");
4180 if (
FABS(dx) <= (
pl->contr->socket->mapx/2)
4181 &&
FABS(dy) <= (
pl->contr->socket->mapy/2)
4182 && !
pl->contr->blocked_los[dx+(
pl->contr->socket->mapx/2)][dy+(
pl->contr->socket->mapy/2)])
4207 if (
op->contr &&
op->contr->tmp_invis == 0)
4211 if (
op->hide || !
op->contr || (
op->contr &&
op->contr->tmp_invis)) {
4214 op->hide ?
"unhidden" :
"visible");
4253 && strcmp(
tmp->name,
"battleground") == 0
4262 if (invtmp != NULL) {
4263 if (
x != NULL &&
y != NULL)
4269 if (
x != NULL &&
y != NULL)
4274 if (trophy != NULL) {
4275 if (
tmp->other_arch) {
4276 *trophy =
tmp->other_arch;
4317 if (trlist == NULL ||
who->type !=
PLAYER)
4323 if (tr == NULL || tr->
item == NULL) {
4337 "You gained the ability of %s",
4351 if (
item->invisible) {
4354 "You gained the ability of %s",
4373 if (
item->msg != NULL)
4379 if (
item->animation) {
4381 who->animation =
item->animation;
4382 who->anim_speed =
item->anim_speed;
4403 snprintf(
buf,
sizeof(
buf),
"You feel attuned to ");
4405 if (
item->path_attuned&(1<<i)) {
4407 strcat(
buf,
" and ");
4428 if (
item->msg != NULL)
4460 for (i = 0; i < static_cast<int>(
range_size); i++) {
4461 if (
pl->ranges[i] ==
ob) {
4462 pl->ranges[i] = NULL;
4463 if (
pl->shoottype == i) {
4491 if (
pl->delayed_buffers_used ==
pl->delayed_buffers_allocated) {
4492 pl->delayed_buffers_allocated += 5;
4493 pl->delayed_buffers =
static_cast<SockList **
>(realloc(
pl->delayed_buffers,
pl->delayed_buffers_allocated *
sizeof(
pl->delayed_buffers[0])));
4494 if (!
pl->delayed_buffers) {
4495 LOG(
llevError,
"Unable to allocated %d delayed buffers, aborting\n",
pl->delayed_buffers_allocated);
4498 for (uint8_t s =
pl->delayed_buffers_allocated - 5; s < pl->delayed_buffers_allocated; s++) {
4502 sl =
pl->delayed_buffers[
pl->delayed_buffers_used];
4503 pl->delayed_buffers_used++;
#define object_was_destroyed(op, old_tag)
#define ADD_PLAYER_NO_STATS_ROLL
bool object_value_set(const object *op, const char *const key)
int op_on_battleground(object *op, int *x, int *y, archetype **trophy)
#define GET_MAP_OB(M, X, Y)
#define MSG_TYPE_COMMAND_NEWPLAYER
int do_skill(object *op, object *part, object *skill, int dir, const char *string)
void apply_changes_to_player(object *pl, object *change, int limit_stats)
int check_pick(object *op)
void make_visible(object *op)
object * object_get_owner(object *op)
static void kill_player_permadeath(object *op)
void SockList_AddInt(SockList *sl, uint32_t data)
object * object_find_by_type_subtype(const object *who, int type, int subtype)
TIPS on SURVIVING Crossfire is populated with a wealth of different monsters These monsters can have varying immunities and attack types In some of them can be quite a bit smarter than others It will be important for new players to learn the abilities of different monsters and learn just how much it will take to kill them This section discusses how monsters can interact with players Most monsters in the game are out to mindlessly kill and destroy the players These monsters will help boost a player s after he kills them When fighting a large amount of monsters in a single attempt to find a narrower hallway so that you are not being attacked from all sides Charging into a room full of Beholders for instance would not be open the door and fight them one at a time For there are several maps designed for them Find these areas and clear them out All throughout these a player can find signs and books which they can read by stepping onto them and hitting A to apply the book sign These messages will help the player to learn the system One more always keep an eye on your food If your food drops to your character will soon so BE CAREFUL ! NPCs Non Player Character are special monsters which have intelligence Players may be able to interact with these monsters to help solve puzzles and find items of interest To speak with a monster you suspect to be a simply move to an adjacent square to them and push the double ie Enter your and press< Return > You can also use say if you feel like typing a little extra Other NPCs may not speak to but display intelligence with their movement Some monsters can be friendly
void object_update_turn_face(object *op)
void remove_friendly_object(object *op)
void pets_terminate_all(object *owner)
int face_player(object *op, int dir)
static struct Command_Line_Options options[]
#define MSG_TYPE_COMMAND_SUCCESS
const char * unarmed_skill
static int player_fire_bow(object *op, int dir)
void kill_player(object *op, const object *killer)
int get_randomized_dir(int dir)
void command_search_items(object *op, const char *params)
static archetype * get_player_archetype(archetype *at)
#define MSG_TYPE_ADMIN_PLAYER
void LOG(LogLevel logLevel, const char *format,...)
int monster_can_detect_enemy(object *op, object *enemy, rv_vector *rv)
int path_to_player(object *mon, object *pl, unsigned mindiff)
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
int blocked_link(object *ob, mapstruct *m, int16_t sx, int16_t sy)
void recursive_roll(object *op, int dir, object *pusher)
void safe_strcat(char *dest, const char *orig, size_t *curlen, size_t maxlen)
char first_map_path[MAX_BUF]
#define QUERY_FLAG(xyz, p)
void remove_locked_door(object *op)
const char *const spellpathnames[NRSPELLPATHS]
void do_learn_spell(object *op, object *spell, int special_prayer)
char first_map_ext_path[MAX_BUF]
void esrv_new_player(player *pl, uint32_t weight)
uint64_t price_base(const object *obj)
SockList * player_get_delayed_buffer(player *pl)
objectlink * get_friends_of(const object *owner)
void esrv_send_inventory(object *pl, object *op)
void roll_again(object *op)
player * find_player_socket(const socket_struct *ns)
int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg)
static object * find_better_arrow(object *op, object *target, const char *type, int *better)
void SockList_AddString(SockList *sl, const char *data)
#define FOR_BELOW_PREPARE(op_, it_)
void object_set_enemy(object *op, object *enemy)
#define MSG_TYPE_VICTIM_DIED
static int turn_transport(object *transport, object *captain, int dir)
void spring_trap(object *trap, object *victim)
object * get_nearest_player(object *mon)
void apply_map_builder(object *pl, int dir)
object * arch_present_in_ob(const archetype *at, const object *op)
void object_set_owner(object *op, object *owner)
void esrv_send_pickup(player *pl)
living last_applied_stats
#define MSG_TYPE_ATTRIBUTE
void player_set_own_title(struct player *pl, const char *title)
#define SET_ANIMATION(ob, newanim)
non standard information is not specified or uptime this means how long since the executable has been started A particular host may have been running a server for quite a long time
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
#define CS_QUERY_SINGLECHAR
void play_sound_player_only(player *pl, int8_t sound_type, object *emitter, int dir, const char *action)
int allowed_class(const object *op)
void play_sound_map(int8_t sound_type, object *emitter, int dir, const char *action)
static const flag_definition flags[]
int change_skill(object *who, object *new_skill, int flag)
void object_copy(const object *src_ob, object *dest_ob)
char savebed_map[MAX_BUF]
treasurelist * find_treasurelist(const char *name)
void fix_object(object *op)
object * object_find_by_flag_applied(const object *who, int flag)
int player_can_view(object *pl, object *op)
void confirm_password(object *op)
void get_name(object *op)
#define SOUND_TYPE_LIVING
#define BALSL_LOSS_CHANCE_RATIO
void send_account_players(socket_struct *ns)
#define MSG_TYPE_COMMAND_ERROR
void esrv_add_spells(player *pl, object *spell)
int apply_manual(object *op, object *tmp, int aflag)
void create_treasure(treasurelist *t, object *op, int flag, int difficulty, int tries)
int events_execute_object_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
#define BALSL_MAX_LOSS_RATIO
void hiscore_check(object *op, int quiet)
AssetsManager * getManager()
object * object_insert_in_ob(object *op, object *where)
int handle_newcs_player(object *op)
int16_t resist[NROFATTACKS]
#define MSG_TYPE_SPELL_END
const char *const lose_msg[NUM_STATS]
Plugin animator file specs[Config] name
void player_set_state(player *pl, uint8_t state)
#define FOR_BELOW_FINISH()
void add_statbonus(object *op)
void esrv_send_item(object *pl, object *op)
const char *const short_stat_name[NUM_STATS]
#define MSG_TYPE_COMMAND_DEBUG
void set_player_socket(player *p, socket_struct *ns)
void remove_door(object *op)
static event_registration m
void clear_los(player *pl)
Account_Chars * account_chars
void object_free_drop_inventory(object *ob)
static int turn_one_transport(object *transport, object *captain, int dir)
void object_update(object *op, int action)
int get_party_password(object *op, partylist *party)
void player_unready_range_ob(player *pl, object *ob)
#define object_decrease_nrof_by_one(xyz)
#define BALSL_NUMBER_LOSSES_RATIO
static void flee_player(object *op)
#define MSG_TYPE_ATTRIBUTE_STAT_LOSS
#define MSG_TYPE_ADMIN_NEWS
bool is_criminal(object *op)
sstring add_refcount(sstring str)
int check_race_and_class(living *stats, archetype *race, archetype *opclass)
void enter_player_savebed(object *op)
const char * determine_god(object *op)
#define MSG_TYPE_ATTRIBUTE_RACE
short freearr_y[SIZEOFFREE]
#define ST_CHANGE_PASSWORD_CONFIRM
int move_ob(object *op, int dir, object *originator)
#define MSG_TYPE_APPLY_SUCCESS
void query_name(const object *op, char *buf, size_t size)
player * find_player_options(const char *plname, int options, const mapstruct *map)
void do_hidden_move(object *op)
#define FLAG_KNOWN_CURSED
static object * pick_arrow_target(object *op, const char *type, int dir)
static int action_makes_visible(object *op)
#define ADD_PLAYER_NO_MAP
int64_t calc_skill_exp(const object *who, const object *op, const object *skill)
void account_char_free(Account_Chars *chars)
static void fire_misc_object(object *op, int dir)
static void loot_object(object *op)
void party_leave(object *op)
sstring add_string(const char *str)
int account_remove_player(const char *account_name, const char *player_name)
void apply_anim_suffix(object *who, const char *suffix)
#define FOR_OB_AND_BELOW_FINISH()
void object_get_multi_size(const object *ob, int *sx, int *sy, int *hx, int *hy)
int apply_container(object *op, object *sack, int aflags)
static int similar_direction(int a, int b)
void enter_player_maplevel(object *op)
void query_short_name(const object *op, char *buf, size_t size)
void SockList_AddChar(SockList *sl, unsigned char c)
void set_attr_value(living *stats, int attr, int8_t value)
void delete_character(const char *name)
int out_of_map(mapstruct *m, int x, int y)
uint32_t last_character_flags
int64_t last_skill_exp[MAX_SKILLS]
int has_carried_lights(const object *op)
void object_update_speed(object *op)
#define FREE_AND_COPY(sv, nv)
void do_some_living(object *op)
static const char * gravestone_text(object *op, char *buf2, int len)
int hideability(object *ob)
void leave(player *pl, int draw_exit)
void object_free(object *ob, int flags)
#define GET_MAP_MOVE_BLOCK(M, X, Y)
player * find_player(const char *plname)
Archetypes * archetypes()
static object * find_arrow(object *op, const char *type)
static void kill_player_not_permadeath(object *op)
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
#define FLAG_UNAGGRESSIVE
int die_roll(int num, int size, const object *op, int goodbad)
void display_motd(const object *op)
int object_matches_string(object *pl, object *op, const char *name)
const char *const drain_msg[NUM_STATS]
#define FIND_PLAYER_PARTIAL_NAME
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
#define AC_PLAYER_STAT_NO_CHANGE
#define FLAG_CAN_USE_SKILL
#define FOR_OB_AND_BELOW_PREPARE(op_)
int get_rangevector_from_mapcoord(const mapstruct *m, int x, int y, const object *op2, rv_vector *retval)
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
void delete_map(mapstruct *m)
int get_dam_bonus(int stat)
void SockList_Init(SockList *sl)
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
void receive_play_again(object *op, char key)
object * object_find_by_type_without_flags(const object *who, int type, int *flags, int num_flags)
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
void fire(object *op, int dir)
int push_ob(object *who, int dir, object *pusher)
object * find_skill_by_name(object *who, const char *name)
object * last_skill_ob[MAX_SKILLS]
void apply_death_exp_penalty(object *op)
int get_dex_bonus(int stat)
void move_player_attack(object *op, int dir)
static std::shared_ptr< inja::Environment > env
size_t strlcpy(char *dst, const char *src, size_t size)
object * object_new(void)
int is_wraith_pl(object *op)
object * create_archetype(const char *name)
void cast_dust(object *op, object *throw_ob, int dir)
void free_string(sstring str)
int transfer_ob(object *op, int x, int y, int randomly, object *originator)
void set_first_map(object *op)
void key_confirm_quit(object *op, char key)
#define offsetof(type, member)
void remove_unpaid_objects(object *op, object *env, int free_items)
void SockList_Term(SockList *sl)
#define FREE_AND_CLEAR_STR(xyz)
#define EVENT_PLAYER_DEATH
void dead_player(object *op)
#define MSG_TYPE_ITEM_ADD
#define MSG_TYPE_COMMAND_FAILURE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
void key_change_class(object *op, char key)
#define FLAG_KNOWN_MAGICAL
int stand_near_hostile(object *who)
#define FIND_PLAYER_NO_HIDDEN_DM
#define OUT_OF_REAL_MAP(M, X, Y)
object * get_nearest_criminal(object *mon)
object * object_find_by_type_and_slaying(const object *who, int type, const char *slaying)
void fatal(enum fatal_error err)
method_ret ob_process(object *op)
#define MSG_TYPE_SKILL_FAILURE
void each(std::function< void(T *)> op)
object * object_find_by_arch_name(const object *who, const char *name)
const char * party_get_password(const partylist *party)
int get_thaco_bonus(int stat)
language_t i18n_get_language_by_code(const char *code)
int object_can_pick(const object *who, const object *item)
std::vector< archetype * > players
void add_friendly_object(object *op)
void key_roll_stat(object *op, char key)
#define ST_CONFIRM_PASSWORD
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
object * object_find_by_type(const object *who, int type)
#define SOUND_TYPE_GROUND
#define MSG_TYPE_ITEM_REMOVE
int is_identifiable_type(const object *op)
void change_attr_value(living *stats, int attr, int8_t value)
void enter_exit(object *op, object *exit_ob)
object * check_spell_known(object *op, const char *name)
int fire_bow(object *op, object *arrow, int dir, int wc_mod, int16_t sx, int16_t sy)
static int save_life(object *op)
void animate_object(object *op, int dir)
archetype * find_archetype(const char *name)
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
#define MSG_TYPE_ATTRIBUTE_GOD
uint8_t stat_loss_on_death
void dragon_ability_gain(object *who, int atnr, int level)
void change_luck(object *op, int value)
static void restore_player(object *op)
void object_set_msg(object *op, const char *msg)
void esrv_update_item(int flags, object *pl, object *op)
int did_make_save(const object *op, int level, int bonus)
void send_rules(const object *op)
#define MSG_TYPE_ADMIN_RULES
void send_news(const object *op)
#define FLAG_BEEN_APPLIED
#define CLEAR_FLAG(xyz, p)
int random_roll(int min, int max, const object *op, int goodbad)
void SockList_ResetRead(SockList *sl)
void get_password(object *op)
int16_t last_resist[NROFATTACKS]
object * arch_to_object(archetype *at)
Player Stats effect how well a character can survie and interact inside the crossfire world This section discusses the various stats
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
void play_again(object *op)
player * get_player(player *p)
#define MSG_TYPE_ADMIN_LOGIN
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_END
uint8_t balanced_stat_loss
int save_player(object *op, int flag)
#define ST_GET_PARTY_PASSWORD
int object_matches_pickup_mode(const object *item, int mode)
void strip_endline(char *buf)
void object_remove(object *op)
int cure_disease(object *sufferer, object *caster, sstring skill)
Magical Runes Runes are magical inscriptions on the dungeon which cast a spell or detonate when something steps on them Flying objects don t detonate runes Beware ! Runes are invisible most of the time They are only visible occasionally ! There are several runes which are there are some special runes which may only be called with the invoke and people may apply it to read it Maybe useful for mazes ! This rune will not nor is it ordinarily invisible Partial Visibility of they ll be visible only part of the time They have a(your level/2) chance of being visible in any given round
void free_objectlink(objectlink *ol)
signed long object_sum_weight(object *op)
#define OB_TYPE_MOVE_BLOCK(ob1, type)
int move_player(object *op, int dir)
Crossfire Protocol most of the time after the actual code was already omit certain important and possibly make life miserable any new developer or curious player should be able to find most of the relevant information here If inconsistencies are found or this documentation proves to be consider the latest server side protocol code in the public source code repository as the authoritative reference Introduction If you were ever curious enough to telnet or netcat to a Crossfire chances are you were sorely disappointed While the protocol may seem to use plain text at it actually uses a mix of ASCII and binary data This handbook attempts to document various aspects of the Crossfire protocol As consult the README file to find out how to get in touch with helpful people via mailing and more History the communications plan was set to be a text based system It was up to the server and client to parse these messages and determine what to do These messages were assumed to be line per message At a reasonably early stage of Eric Anderson wrote a then the data itself you could send many data and after the other end could decode these commands This works fairly but I think the creation of numerous sub packets has some performance hit the eutl was not especially well so writing a client for a different platform became more Eric left to work on other products shortly after writing his which didn t really leave anyone with a full understanding of the socket code I have decided to remove the eutl dependency At least one advantage is that having this network related code directly in the client and server makes error handling a bit easier cleaner Packet Format the outside packet method the byte size for the size information is not included here Eutl originally used bytes for the size to bytes seems it makes a least some sense The actual data is something of the nature of the commands listed below It is a text followed by possible other data The remaining data can be binary it is up to the client and server to decode what it sent The commands as described below is just the data portion of the packet If writing a new remember that you must take into account the size of the packet There is no termination of other than knowing how long it should be For now
void remove_statbonus(object *op)
#define MSG_TYPE_ATTACK_NOATTACK
void make_path_to_file(const char *filename)
player * find_player_partial_name(const char *plname)
void roll_stats(object *op)
player * add_player(socket_struct *ns, int flags)
void query_base_name(const object *op, int plural, char *buf, size_t size)
int8_t get_attr_value(const living *stats, int attr)
void drain_rod_charge(object *rod)
short freearr_x[SIZEOFFREE]
static int player_attack_door(object *op, object *door)
Player Stats effect how well a character can survie and interact inside the crossfire world This section discusses the various what they and how they effect the player s actions Also in this section are the stat modifiers that specific classes professions bring Player and sps the current and maximum the Current and Maximum The Current Sp can go somewhat negative When Sp is negative not all spells can be and a more negative Sp makes spell casting less likey to succeed can affect Damage and how the characters as well as how often the character can attack this affects the prices when buying and selling items if this drops the player will start losing hit points wd Cleric or Dwarf sm Elf wd Fireborn ft Human ra Mage C Monk se Ninja hi Priest C Quetzalcoatl mw Swashbuckler si Thief st Viking ba Warrior or Wizard C Wraith C Class Prof Str Dex Con Wis Cha Int Pow Net Skills Enclosed are codes used for the skills above The ones in and fighting should all be pretty self explanatory For the other a brief description is for a more detailed look at the skills doc file Skill remove use magic items phys no fire cold Fireborns are supposed to be fire spirits They re closely in tune with magic and are powerful and learn magic easily Being fire they are immune to fire and and vulnerable to cold They are vulnerable to ghosthit and drain because being mostly non anything which strikes directly at the spirit hits them harder race attacktype restrictions immunities prot vuln Quetzalcoatl physical no armour fire cold Quetzalcoatl s are now born knowing the spell of burning but because of their negative wisdom bonus
bool shop_contains(object *ob)
static void swap_stat(object *op, int swap_second)
void clear_player(player *pl)
void pets_control_golem(object *op, int dir)
void link_player_skills(object *op)
object * find_key(object *pl, object *container, object *door)
void give_initial_items(object *pl, treasurelist *items)
static void update_transport_block(object *transport, int dir)
void player_map_change_common(object *op, mapstruct *const oldmap, mapstruct *const newmap)
void account_char_save(Account_Chars *chars)
void pick_up(object *op, object *alt)
void check_stat_bounds(living *stats, int8_t min_stat, int8_t max_stat)
void send_query(socket_struct *ns, uint8_t flags, const char *text)
void Send_With_Handling(socket_struct *ns, SockList *sl)
int is_true_undead(object *op)
#define MSG_TYPE_ITEM_INFO
int apply_race_and_class(object *op, archetype *race, archetype *opclass, living *stats)
#define FOR_INV_PREPARE(op_, it_)
static const int32_t MAX_FOOD
void drain_wand_charge(object *wand)
int playername_ok(const char *cp)
void account_char_remove(Account_Chars *chars, const char *pl_name)
party_rejoin_mode rejoin_party
void events_execute_global_event(int eventcode,...)
int object_can_merge(object *ob1, object *ob2)
const char * i18n(const object *who, const char *code)
void skill_attack(object *tmp, object *pl, int dir, const char *string, object *skill)
#define CS_QUERY_HIDEINPUT