Пример #1
0
/**
 * Create a path to the per-server settings directory.
 * @param path
 * Path inside the per-server settings directory.
 * @return
 * New path. Must be freed.
 */
char *file_path_server(const char *path)
{
    StringBuffer *sb;

    HARD_ASSERT(path != NULL);

    sb = file_path_server_internal();
    stringbuffer_append_printf(sb, ".common/%s", path);

    return stringbuffer_finish(sb);
}
Пример #2
0
/**
 * Get absolute path to the specified relative path. This path will typically
 * point to the to client data directory (which is usually located in the user's
 * home/appdata directory), but depending on the specified mode, extra actions
 * may be performed. These ensure that if you're trying to access a file that
 * does not yet exist in the client data directory, it will be read from the
 * client installation directory instead (unless it's being appended to, in
 * which case it will be copied to the client data directory first).
 *
 * Generally, you should almost always use this when you need to construct a
 * path, or use one of the many @ref file_wrapper_functions.
 * @param fname
 * The file path.
 * @param mode
 * File mode.
 * @return
 * The absolute path. Must be freed.
 */
char *file_path(const char *path, const char *mode)
{
    bool is_write, is_append;
    StringBuffer *sb;
    char version[MAX_BUF], client_path[HUGE_BUF], *new_path;

    HARD_ASSERT(path != NULL);
    HARD_ASSERT(mode != NULL);

    SOFT_ASSERT_RC(path[0] != '/', estrdup(path),
            "Path is already absolute: %s", path);

    sb = stringbuffer_new();
    stringbuffer_append_printf(sb, "%s/.atrinik/%s/%s", get_config_dir(),
            package_get_version_partial(VS(version)), path);
    new_path = stringbuffer_sub(sb, 0, 0);

    is_write = is_append = false;

    if (strchr(mode, 'w') != NULL) {
        is_write = true;
    } else if (strchr(mode, '+') != NULL || strchr(mode, 'a') != NULL) {
        is_append = true;
    }

    if (is_write || is_append) {
        if (access(new_path, W_OK) != 0) {
            char *dirname;

            /* Ensure directories exist if we're going to use this path for
             * writing/appending. */
            dirname = path_dirname(new_path);
            mkdir_recurse(dirname);
            efree(dirname);

            if (is_append) {
                get_data_dir_file(VS(client_path), path);
                copy_file(client_path, new_path);
            }
        }
    } else {
        if (access(new_path, R_OK) != 0) {
            get_data_dir_file(VS(client_path), path);
            stringbuffer_seek(sb, 0);
            stringbuffer_append_string(sb, client_path);
        }
    }

    efree(new_path);

    return stringbuffer_finish(sb);
}
Пример #3
0
/**
 * Create a path to the per-player settings directory.
 * @param path
 * Path inside the per-player settings directory.
 * @return
 * New path. Must be freed.
 */
char *file_path_player(const char *path)
{
    StringBuffer *sb;

    HARD_ASSERT(path != NULL);

    sb = file_path_server_internal();

    SOFT_ASSERT_LABEL(*cpl.account != '\0', done, "Account name is empty.");
    SOFT_ASSERT_LABEL(*cpl.name != '\0', done, "Player name is empty.");

    stringbuffer_append_printf(sb, "%s/%s/%s", cpl.account, cpl.name, path);

done:
    return stringbuffer_finish(sb);
}
Пример #4
0
/**
 * Constructs a path leading to the chosen server settings directory. Used
 * internally by file_path_player() and file_path_server().
 * @return
 *
 */
static StringBuffer *file_path_server_internal(void)
{
    StringBuffer *sb;

    sb = stringbuffer_new();
    stringbuffer_append_string(sb, "settings/");

    SOFT_ASSERT_RC(selected_server != NULL, sb, "Selected server is NULL.");
    SOFT_ASSERT_RC(!string_isempty(selected_server->hostname), sb,
            "Selected server has empty hostname.");

    stringbuffer_append_printf(sb, "servers/%s-%d/", selected_server->hostname,
            selected_server->port);

    return sb;
}
Пример #5
0
/**
 * Generate a message detailing the properties of 1-6 artifacts drawn
 * sequentially from the artifact list.
 * @param level Level of the book
 * @param buf Buffer to contain the description.
 * @param booksize Length of the book.
 * @return 'buf'. */
static char *artifact_msg(int level, char *buf, size_t booksize)
{
	artifactlist *al;
	artifact *art;
	int chance, i, type, index;
	int book_entries = level > 5 ? RANDOM () % 3 + RANDOM () % 3 + 2 : RANDOM () % level + 1;
	char *final, *ch;
	object *tmp = NULL;
	StringBuffer *desc;

	/* Values greater than 5 create msg buffers that are too big! */
	if (book_entries > 5)
	{
		book_entries = 5;
	}

	/* Let's determine what kind of artifact type randomly.
	 * Right now legal artifacts only come from those listed
	 * in art_name_array. Also, we check to be sure an artifactlist
	 * for that type exists! */
	i = 0;

	do
	{
		index = rndm(1, arraysize(art_name_array)) - 1;
		type = art_name_array[index].type;
		al = find_artifactlist(type);
		i++;
	}
	while (al == NULL && i < 10);

	/* Unable to find a message */
	if (i == 10)
	{
		snprintf(buf, booksize, "None");
		return buf;
	}

	/* There is no reason to start on the artifact list at the begining. Lets
	 * take our starting position randomly... */
	art = al->items;

	for (i = rndm(1, level) + rndm(0, 1); i > 0; i--)
	{
		/* Out of stuff, loop back around */
		if (art == NULL)
		{
			art = al->items;
		}

		art = art->next;
	}

	/* Ok, let's print out the contents */
	snprintf(buf, booksize, "<t t=\"Magical %s\">Herein %s detailed %s...\n", art_name_array[index].name, book_entries > 1 ? "are" : "is", book_entries > 1 ? "some artifacts" : "an artifact");

	/* Artifact msg attributes loop. Let's keep adding entries to the 'book'
	 * as long as we have space up to the allowed max # (book_entires) */
	while (book_entries > 0)
	{
		if (art == NULL)
		{
			art = al->items;
		}

		desc = stringbuffer_new();
		tmp = get_archetype(art->def_at_name);
		give_artifact_abilities(tmp, art);
		SET_FLAG(tmp, FLAG_IDENTIFIED);

		stringbuffer_append_printf(desc, "\n<t t=\"%s %s\">It is ", tmp->name, tmp->title ? tmp->title : "");

		/* Chance of finding. */
		chance = 100 * ((float) art->chance / al->total_chance);

		if (chance >= 20)
		{
			stringbuffer_append_string(desc, "an uncommon");
		}
		else if (chance >= 10)
		{
			stringbuffer_append_string(desc, "an unusual");
		}
		else if (chance >= 5)
		{
			stringbuffer_append_string(desc, "a rare");
		}
		else
		{
			stringbuffer_append_string(desc, "a very rare");
		}

		/* Value of artifact. */
		stringbuffer_append_printf(desc, " item with a value of %s.", cost_string_from_value(tmp->value));

		if ((ch = describe_item(tmp)) && strlen(ch) > 1)
		{
			stringbuffer_append_printf(desc, "\nProperties of this artifact include:\n %s", ch);
		}

		final = stringbuffer_finish(desc);

		/* Add the buf if it will fit. */
		if (book_overflow(buf, final, booksize))
		{
			free(final);
			break;
		}

		snprintf(buf + strlen(buf), booksize - strlen(buf), "%s", final);
		free(final);

		art = art->next;
		book_entries--;
	}
Пример #6
0
/**
 * Player examines some object.
 * @param op Player.
 * @param tmp Object to examine. */
void examine(object *op, object *tmp)
{
	char buf[VERY_BIG_BUF], tmp_buf[64];
	int i;

	if (tmp == NULL || tmp->type == CLOSE_CON)
	{
		return;
	}

	strcpy(buf, "That is ");
	strncat(buf, long_desc(tmp, op), VERY_BIG_BUF - strlen(buf) - 1);
	buf[VERY_BIG_BUF - 1] = '\0';

	/* Only add this for usable items, not for objects like walls or
	 * floors for example. */
	if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED) && need_identify(tmp))
	{
		strncat(buf, " (unidentified)", VERY_BIG_BUF - strlen(buf) - 1);
	}

	buf[VERY_BIG_BUF - 1] = '\0';
	new_draw_info(NDI_UNIQUE, op, buf);
	buf[0] = '\0';

	if (QUERY_FLAG(tmp, FLAG_MONSTER) || tmp->type == PLAYER)
	{
		new_draw_info_format(NDI_UNIQUE, op, "%s.", describe_item(tmp->head ? tmp->head : tmp));
		examine_living(op, tmp);
	}
	/* We don't double use the item_xxx arch commands, so they are always valid */
	else if (QUERY_FLAG(tmp, FLAG_IDENTIFIED))
	{
		if (QUERY_FLAG(tmp, FLAG_IS_GOOD))
		{
			new_draw_info_format(NDI_UNIQUE, op, "It is good aligned.");
		}
		else if (QUERY_FLAG(tmp, FLAG_IS_EVIL))
		{
			new_draw_info_format(NDI_UNIQUE, op, "It is evil aligned.");
		}
		else if (QUERY_FLAG(tmp, FLAG_IS_NEUTRAL))
		{
			new_draw_info_format(NDI_UNIQUE, op, "It is neutral aligned.");
		}

		if (tmp->item_level)
		{
			if (tmp->item_skill)
			{
				new_draw_info_format(NDI_UNIQUE, op, "It needs a level of %d in %s to use.", tmp->item_level, find_skill_exp_skillname(tmp->item_skill));
			}
			else
			{
				new_draw_info_format(NDI_UNIQUE, op, "It needs a level of %d to use.", tmp->item_level);
			}
		}

		if (tmp->item_quality)
		{
			if (QUERY_FLAG(tmp, FLAG_INDESTRUCTIBLE))
			{
				new_draw_info_format(NDI_UNIQUE, op, "Qua: %d Con: Indestructible.", tmp->item_quality);
			}
			else
			{
				new_draw_info_format(NDI_UNIQUE, op, "Qua: %d Con: %d.", tmp->item_quality, tmp->item_condition);
			}
		}

		buf[0] = '\0';
	}

	switch (tmp->type)
	{
		case SPELLBOOK:
			if (QUERY_FLAG(tmp, FLAG_IDENTIFIED) && tmp->stats.sp >= 0 && tmp->stats.sp <= NROFREALSPELLS)
			{
				if (tmp->sub_type == ST1_SPELLBOOK_CLERIC)
				{
					snprintf(buf, sizeof(buf), "%s is a %d level prayer.", spells[tmp->stats.sp].name, spells[tmp->stats.sp].level);
				}
				else
				{
					snprintf(buf, sizeof(buf), "%s is a %d level spell.", spells[tmp->stats.sp].name, spells[tmp->stats.sp].level);
				}
			}

			break;

		case BOOK:
			if (tmp->msg != NULL)
			{
				strcpy(buf, "Something is written in it.");
			}

			break;

		case CONTAINER:
			if (QUERY_FLAG(tmp, FLAG_IDENTIFIED))
			{
				if (tmp->race != NULL)
				{
					if (tmp->weight_limit)
					{
						snprintf(buf, sizeof(buf), "It can hold only %s and its weight limit is %.1f kg.", tmp->race, (float) tmp->weight_limit / 1000.0f);
					}
					else
					{
						snprintf(buf, sizeof(buf), "It can hold only %s.", tmp->race);
					}

					/* Has magic modifier? */
					if (tmp->weapon_speed != 1.0f)
					{
						new_draw_info(NDI_UNIQUE, op, buf);

						/* Bad */
						if (tmp->weapon_speed > 1.0f)
						{
							snprintf(buf, sizeof(buf), "It increases the weight of items inside by %.1f%%.", tmp->weapon_speed * 100.0f);
						}
						/* Good */
						else
						{
							snprintf(buf, sizeof(buf), "It decreases the weight of items inside by %.1f%%.", 100.0f - (tmp->weapon_speed * 100.0f));
						}
					}
				}
				else
				{
					if (tmp->weight_limit)
					{
						snprintf(buf, sizeof(buf), "Its weight limit is %.1f kg.", (float)tmp->weight_limit / 1000.0f);
					}

					/* Has magic modifier? */
					if (tmp->weapon_speed != 1.0f)
					{
						new_draw_info(NDI_UNIQUE, op, buf);

						/* Bad */
						if (tmp->weapon_speed > 1.0f)
						{
							snprintf(buf, sizeof(buf), "It increases the weight of items inside by %.1f%%.", tmp->weapon_speed * 100.0f);
						}
						/* Good */
						else
						{
							snprintf(buf, sizeof(buf), "It decreases the weight of items inside by %.1f%%.", 100.0f - (tmp->weapon_speed * 100.0f));
						}
					}
				}

				new_draw_info(NDI_UNIQUE, op, buf);

				if (tmp->weapon_speed == 1.0f)
				{
					snprintf(buf, sizeof(buf), "It contains %3.3f kg.", (float) tmp->carrying / 1000.0f);
				}
				else if (tmp->weapon_speed > 1.0f)
				{
					snprintf(buf, sizeof(buf), "It contains %3.3f kg, increased to %3.3f kg.", (float) tmp->damage_round_tag / 1000.0f, (float) tmp->carrying / 1000.0f);
				}
				else
				{
					snprintf(buf, sizeof(buf), "It contains %3.3f kg, decreased to %3.3f kg.", (float) tmp->damage_round_tag / 1000.0f, (float) tmp->carrying / 1000.0f);
				}
			}

			break;

		case WAND:
			if (QUERY_FLAG(tmp, FLAG_IDENTIFIED))
			{
				snprintf(buf, sizeof(buf), "It has %d charges left.", tmp->stats.food);
			}

			break;

		case POWER_CRYSTAL:
			/* Avoid division by zero... */
			if (tmp->stats.maxsp == 0)
			{
				snprintf(buf, sizeof(buf), "It has capacity of %d.", tmp->stats.maxsp);
			}
			else
			{
				int i;

				/* Higher capacity crystals */
				if (tmp->stats.maxsp > 1000)
				{
					i = (tmp->stats.maxsp % 1000) / 100;

					if (i)
					{
						snprintf(tmp_buf, sizeof(tmp_buf), "It has capacity of %d.%dk and is ", tmp->stats.maxsp / 1000, i);
					}
					else
					{
						snprintf(tmp_buf, sizeof(tmp_buf), "It has capacity of %dk and is ", tmp->stats.maxsp / 1000);
					}
				}
				else
				{
					snprintf(tmp_buf, sizeof(tmp_buf), "It has capacity of %d and is ", tmp->stats.maxsp);
				}

				strcat(buf, tmp_buf);
				i = (tmp->stats.sp * 10) / tmp->stats.maxsp;

				if (tmp->stats.sp == 0)
				{
					strcat(buf, "empty.");
				}
				else if (i == 0)
				{
					strcat(buf, "almost empty.");
				}
				else if (i < 3)
				{
					strcat(buf, "partially filled.");
				}
				else if (i < 6)
				{
					strcat(buf, "half full.");
				}
				else if (i < 9)
				{
					strcat(buf, "well charged.");
				}
				else if (tmp->stats.sp == tmp->stats.maxsp)
				{
					strcat(buf, "fully charged.");
				}
				else
				{
					strcat(buf, "almost full.");
				}
			}

			break;
	}

	if (buf[0] != '\0')
	{
		new_draw_info(NDI_UNIQUE, op, buf);
	}

	if (tmp->material && (need_identify(tmp) && QUERY_FLAG(tmp, FLAG_IDENTIFIED)))
	{
		strcpy(buf, "It is made of: ");

		for (i = 0; i < NROFMATERIALS; i++)
		{
			if (tmp->material & (1 << i))
			{
				strcat(buf, material[i].name);
				strcat(buf, " ");
			}
		}

		new_draw_info(NDI_UNIQUE, op, buf);
	}

	if (tmp->weight)
	{
		float weight = (float) (tmp->nrof ? tmp->weight * (int) tmp->nrof : tmp->weight) / 1000.0f;

		if (tmp->type == MONSTER)
		{
			new_draw_info_format(NDI_UNIQUE, op, "%s weighs %3.3f kg.", gender_subjective_upper[object_get_gender(tmp)], weight);
		}
		else if (tmp->type == PLAYER)
		{
			new_draw_info_format(NDI_UNIQUE, op, "%s weighs %3.3f kg and is carrying %3.3f kg.", gender_subjective_upper[object_get_gender(tmp)], weight, (float) tmp->carrying / 1000.0f);
		}
		else
		{
			new_draw_info_format(NDI_UNIQUE, op, tmp->nrof > 1 ? "They weigh %3.3f kg." : "It weighs %3.3f kg.", weight);
		}
	}

	if (QUERY_FLAG(tmp, FLAG_STARTEQUIP))
	{
		/* Unpaid clone shop item */
		if (QUERY_FLAG(tmp, FLAG_UNPAID))
		{
			new_draw_info_format(NDI_UNIQUE, op, "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", query_cost_string(tmp, op, F_BUY));
		}
		/* God-given item */
		else
		{
			new_draw_info_format(NDI_UNIQUE, op, "%s god-given item%s.", tmp->nrof > 1 ? "They are" : "It is a", tmp->nrof > 1 ? "s" : "");

			if (QUERY_FLAG(tmp, FLAG_IDENTIFIED))
			{
				if (tmp->value)
				{
					new_draw_info_format(NDI_UNIQUE, op, "But %s worth %s.", tmp->nrof > 1 ? "they are" : "it is", query_cost_string(tmp, op, F_TRUE));
				}
				else
				{
					new_draw_info_format(NDI_UNIQUE, op, "%s worthless.", tmp->nrof > 1 ? "They are" : "It is");
				}
			}
		}
	}
	else if (tmp->value && !IS_LIVE(tmp))
	{
		if (QUERY_FLAG(tmp, FLAG_IDENTIFIED))
		{
			if (QUERY_FLAG(tmp, FLAG_UNPAID))
			{
				new_draw_info_format(NDI_UNIQUE, op, "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", query_cost_string(tmp, op, F_BUY));
			}
			else
			{
				new_draw_info_format(NDI_UNIQUE, op, "%s worth %s.", tmp->nrof > 1 ? "They are" : "It is", query_cost_string(tmp, op, F_TRUE));
				goto dirty_little_jump1;
			}
		}
		else
		{
			object *floor;
dirty_little_jump1:

			floor = GET_MAP_OB_LAYER(op->map, op->x, op->y, 0);

			if (floor && floor->type == SHOP_FLOOR && tmp->type != MONEY)
			{
				/* Used for SK_BARGAINING modification */
				int charisma = op->stats.Cha;

				/* This skill gives us a charisma boost */
				if (find_skill(op, SK_BARGAINING))
				{
					charisma += 4;

					if (charisma > MAX_STAT)
					{
						charisma = MAX_STAT;
					}
				}

				new_draw_info_format(NDI_UNIQUE, op, "This shop will pay you %s (%0.1f%%).", query_cost_string(tmp, op, F_SELL), 20.0f + 100.0f * cha_bonus[charisma]);
			}
		}
	}
	else if (!IS_LIVE(tmp))
	{
		if (QUERY_FLAG(tmp, FLAG_IDENTIFIED))
		{
			if (QUERY_FLAG(tmp, FLAG_UNPAID))
			{
				new_draw_info_format(NDI_UNIQUE, op, "%s would cost nothing.", tmp->nrof > 1 ? "They" : "It");
			}
			else
			{
				new_draw_info_format(NDI_UNIQUE, op, "%s worthless.", tmp->nrof > 1 ? "They are" : "It is");
			}
		}
	}

	/* Does the object have a message?  Don't show message for all object
	 * types - especially if the first entry is a match */
	if (tmp->msg && tmp->type != EXIT && tmp->type != BOOK && tmp->type != CORPSE && !QUERY_FLAG(tmp, FLAG_WALK_ON) && strncasecmp(tmp->msg, "@match", 7))
	{
		/* This is just a hack so when identifying the items, we print
		 * out the extra message */
		if (need_identify(tmp) && QUERY_FLAG(tmp, FLAG_IDENTIFIED))
		{
			new_draw_info(NDI_UNIQUE, op, "The object has a story:");
			new_draw_info(NDI_UNIQUE, op, tmp->msg);
		}
	}

	/* Blank line */
	new_draw_info(NDI_UNIQUE, op, " ");

	if (QUERY_FLAG(op, FLAG_WIZ))
	{
		StringBuffer *sb = stringbuffer_new();
		char *diff;

		stringbuffer_append_printf(sb, "count %d\n", tmp->count);
		dump_object(tmp, sb);
		diff = stringbuffer_finish(sb);
		new_draw_info(NDI_UNIQUE, op, diff);
		free(diff);
	}
}