Пример #1
0
static void
apply_move (Event_move e){
  Unit *u = id2unit(e.u);
  if(find_skill(u, S_IGNR))
    u->mv -= e.cost;
  else
    u->mv = 0;
  u->stamina -= e.cost;
  u->m = neib(u->m, e.dir);
  fill_map(selected_unit);
  if(u->player == current_player->id)
    update_fog_after_move(u);
}
Пример #2
0
/* a - shooting unit, b - target */
static int
range_damage (Unit *a, Unit *b){
  Skill_range s   = find_skill(a, S_RANGE)->range;
  int hits        = 0;
  int wounds      = 0; /*possible wounds(may be blocked by armour)*/
  int final       = 0; /*final wounds(not blocked by armour)*/
  int attacks     = a->count;
  /*chances to hit, to wound and to ignore armour. percents.*/
  int to_hit      = 2 + s.skill;
  int to_wound    = 5 + (s.strength - utypes[b->t].toughness);
  int to_as       = 10- utypes[b->t].armor;
#if 1
  int r = rnd(0, 2);
  to_hit   += rnd(-r, r);
  to_wound += rnd(-r, r);
  to_as    += rnd(-r, r);
#endif
  fixnum(0, 9, &to_hit);
  fixnum(0, 9, &to_wound);
  hits   = attacks * to_hit   / 10;
  wounds = hits    * to_wound / 10;
  final  = wounds  * to_as    / 10;
Пример #3
0
Файл: shop.c Проект: atrinik/dwc
/**
 * Return the price of an item for a character.
 * @param tmp Object we're querying the price of.
 * @param who Who is inquiring. Can be NULL, only meaningful if player.
 * @param flag Combination of @ref F_xxx "F_xxx" flags.
 * @return The price for the item. */
sint64 query_cost(object *tmp, object *who, int flag)
{
	sint64 val;
	double diff;
	int number;
	int charisma = 11;

	if ((number = tmp->nrof) == 0)
	{
		number = 1;
	}

	/* Money is always identified */
	if (tmp->type == MONEY)
	{
		return (number * tmp->value);
	}

	/* Handle identified items */
	if (QUERY_FLAG(tmp, FLAG_IDENTIFIED) || !need_identify(tmp))
	{
		if (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED))
		{
			return 0;
		}
		else
		{
			val = tmp->value * number;
		}
	}
	/* This area deals with objects that are not identified, but can be */
	else
	{
		if (tmp->arch != NULL)
		{
			if (flag == F_BUY)
			{
				LOG(llevBug, "BUG: query_cost(): Asking for buy-value of unidentified object %s.\n", query_name(tmp, NULL));
				val = tmp->arch->clone.value * number;
			}
			/* Trying to sell something, or get true value */
			else
			{
				/* Selling unidentified gems is *always* stupid */
				if (tmp->type == GEM || tmp->type == JEWEL || tmp->type == NUGGET || tmp->type == PEARL)
				{
					val = number * 3;
				}
				/* Don't want to give anything away */
				else if (tmp->type == POTION)
				{
					val = number * 50;
				}
				else
				{
					val = number * tmp->arch->clone.value;
				}
			}
		}
		else
		{
			/* No archetype with this object - we generate some dummy values to avoid server break */
			LOG(llevBug, "BUG: query_cost(): Have object with no archetype: %s\n", query_name(tmp, NULL));

			if (flag == F_BUY)
			{
				LOG(llevBug, "BUG: query_cost(): Asking for buy-value of unidentified object without arch.\n");
				val = number * 100;
			}
			else
			{
				val = number * 80;
			}
		}
	}

	/* Wands will count special. The base value is for a wand with one charge */
	if (tmp->type == WAND)
	{
		val += (val * tmp->level) * tmp->stats.food;
	}
	else if (tmp->type == ROD || tmp->type == HORN || tmp->type == POTION || tmp->type == SCROLL)
	{
		val += val * tmp->level;
	}

	/* We are done if we only want get the real value */
	if (flag == F_TRUE)
	{
		return val;
	}

	/* First, we adjust charisma for players and count skills in */
	if (who != NULL && who->type == PLAYER)
	{
		/* Used for SK_BARGAINING modification */
		charisma = who->stats.Cha;

		/* This skill will give us a charisma boost */
		if (find_skill(who, SK_BARGAINING))
		{
			charisma += 4;

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

	/* Now adjust for sell or buy multiplier */
	if (flag == F_BUY)
	{
		diff = (double) (1.0 - (double) cha_bonus[charisma]);
	}
	else
	{
		diff = (double) (0.20 + (double) cha_bonus[charisma]);
	}

	val = (val * (long) (1000 * (diff))) / 1000;

	/* We want to give at least 1 copper for items which have any
	 * value. */
	if (val < 1 && tmp->value > 0)
	{
		val = 1;
	}

	return val;
}
Пример #4
0
/**
 * Main part of the alchemy code. From this we call functions that take a
 * look at the contents of the 'cauldron' and, using these ingredients,
 * we construct an integer formula value which is referenced (randomly)
 * against a formula list (the formula list chosen is based on the #
 * contents of the cauldron).
 *
 * If we get a match between the recipe indicated in cauldron contents
 * and a randomly chosen one, an item is created and experience awarded.
 * Otherwise various failure effects are possible (getting worse and
 * worse with # cauldron ingredients). Note that the 'item' to be made
 * can be *anything* listed on the artifacts list in lib/artifacts which
 * has a recipe listed in lib/formulae.
 *
 * To those wondering why I am using the funky formula index method:
 *   1) I want to match recipe to ingredients regardless of ordering.
 *   2) I want a fast search for the 'right' recipe.
 *
 * Note: it is just possible that a totally different combination of
 * ingredients will result in a match with a given recipe. This is not a
 * bug! There is no good reason (in my mind) why alchemical processes
 * have to be unique -- such a 'feature' is one reason why players might
 * want to experiment around. :)
 * @param caster Who is doing alchemy.
 * @param cauldron The cauldron in which alchemy should take place. */
static void attempt_do_alchemy(object *caster, object *cauldron)
{
	recipelist *fl;
	recipe *rp = NULL;
	float success_chance;
	int numb, ability = 1;
	int formula = 0;

	/* Only players for now */
	if (caster->type != PLAYER)
	{
		return;
	}

	/* If no ingredients, no formula! Let's forget it */
	if (!(formula = content_recipe_value(cauldron)))
	{
		return;
	}

	numb = numb_ob_inside(cauldron);

	if ((fl = get_formulalist(numb)))
	{
		/* The caster only gets an increase in ability if they know
		 * alchemy skill */
		if (find_skill(caster, SK_ALCHEMY) != NULL)
		{
			change_skill(caster, SK_ALCHEMY);
			ability += (int) ((float) SK_level(caster) * (float) ((float) (4 + cauldron->magic) / 4.0f));
		}

#ifdef ALCHEMY_DEBUG
		LOG(llevDebug, "DEBUG: Got alchemy ability lvl = %d\n", ability);
#endif

		if (QUERY_FLAG(caster, FLAG_WIZ))
		{
			rp = fl->items;

			while (rp && (formula % rp->index) != 0)
			{
#ifdef EXTREME_ALCHEMY_DEBUG
				LOG(llevDebug, "DEBUG: found list %d formula: %s of %s (%d)\n", numb, rp->arch_name, rp->title, rp->index);
#endif
				rp = rp->next;
			}

			if (rp)
			{
#ifdef ALCHEMY_DEBUG
				if (rp->title != shstr_cons.NONE)
				{
					LOG(llevDebug, "DEBUG: WIZ got formula: %s of %s\n", rp->arch_name, rp->title);
				}
				else
				{
					LOG(llevDebug, "DEBUG: WIZ got formula: %s (nbatches:%d)\n", rp->arch_name, formula / rp->index);
				}
#endif
				attempt_recipe(caster, cauldron, ability, rp, formula / rp->index);
			}
			else
			{
				LOG(llevDebug, "DEBUG: WIZ couldnt find formula for ingredients.\n");
			}

			return;
		}

		/* Find the recipe */
		for (rp = fl->items; rp != NULL && (formula % rp->index) != 0; rp = rp->next)
		{
		}

		/* If we found a recipe */
		if (rp)
		{
			float ave_chance = fl->total_chance / (float) fl->number;
			object *item;

			/* Create the object **FIRST**, then decide whether to keep it. */
			if ((item = attempt_recipe(caster, cauldron, ability, rp, formula / rp->index)) != NULL)
			{
				/* Compute base chance of recipe success */
				success_chance = ((float) (15 * ability) / (float) (15 * ability + numb * item->level * (numb + item->level + formula / rp->index)));

				if (ave_chance == 0)
				{
					ave_chance = 1;
				}

				/* Adjust the success chance by the chance from the recipe list	*/
				if (ave_chance > rp->chance)
				{
					success_chance *= ((float) rp->chance + ave_chance) / (2.0f * ave_chance);
				}
				else
				{
					success_chance = 1.0f - ((1.0f - success_chance) * ((float) rp->chance + ave_chance) / (2.0f * (float) rp->chance));
				}

#ifdef ALCHEMY_DEBUG
				LOG(llevDebug, "DEBUG: percent success chance =  %f\n", success_chance);
#endif

				/* Roll the dice */
				if ((float) (rndm(0, 99)) <= 100.0 * success_chance)
				{
					/* We learn from our experience IF we know something of the alchemical arts */
					if (caster->chosen_skill && caster->chosen_skill->stats.sp == SK_ALCHEMY)
					{
						/* More exp is given for higher ingred number recipes */
						sint64 amount = numb * numb * calc_skill_exp(caster, item, -1);
						add_exp(caster, amount, SK_ALCHEMY);
						/* So when skill id this item, less xp is awarded */
						item->stats.exp = 0;
#ifdef EXTREME_ALCHEMY_DEBUG
						LOG(llevDebug, "DEBUG: %s gains %d experience points.\n", caster->name, amount);
#endif
					}

					return;
				}
			}
		}
	}

	/* If we get here, we failed! */
	alchemy_failure_effect(caster, cauldron, rp, calc_alch_danger(caster, cauldron));
}
Пример #5
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);
	}
}