Add several new Affect nodes.

- Alter monster statistics on the fly, including basic attacks
- Alter experience level and morale (the latter currently only works on monsters while the former might have strange results on PCs)
- Alter the contents of the player's soul crystal
- Forced Give node now has an option to force-equip the item
This commit is contained in:
2015-06-01 01:39:57 -04:00
parent 071e60023f
commit e0ff77060a
6 changed files with 138 additions and 13 deletions

View File

@@ -224,9 +224,13 @@ no room in their inventory.
<dt>Mess1, Mess2:</dt><dd>Standard usage.</dd>
<dt>Extra 1a:</dt><dd>The number of the item to give. Press the Choose button to pick an
item.</dd>
<dt>Extra 2b:</dt><dd>The special to jump to if the item is not successfully given (if all
the parties item slots are full). If No Special is given, the Jump To special is used as
<dt>Extra 1b:</dt><dd>The special to jump to if the item is not successfully given (if all
the party's item slots are full). If No Special is given, the Jump To special is used as
usual.</dd>
<dt>Extra 2a:</dt><dd>If 1, the item is given pre-equipped, without checking to see if
this is legal. This should only be used if you know exactly what else they have equipped,
for example if you are creating a joined NPC or if you previously stripped them of their
items.</dd>
<dt>Uses:</dt><dd>If you want the party to get an item after winning a combat outdoors,
use a Forced Give. This makes sure that if it is at all possible, they get it.</dd>
<dt>Uses 2:</dt><dd>Use this is the party is given an item during a talking special
@@ -826,6 +830,52 @@ one.</dd></dd>
<dl>
<dt>Mess3:</dt><dd>The number of the string containing the new name.</dd></dd>
<dt>Type 91: Affect Level</dt><dd>Alters the experience level of a monster or PC.
<dl>
<dt>Extra 1a:</dt><dd>The number of levels to add/remove.</dd>
<dt>Extra 1b:</dt><dd>If 0, gains levels. Otherwise, removes.</dd>
<dt>Note:</dt>Use sparingly, especially when draining. If affecting a PC, this does not
change skill points or amount of experience.</dd>
<dt>Type 92: Affect Morale</dt><dd>Changes a monster's morale. If the target is not a
monster, this has no effect. Decreasing morale is the same as a Fear spell.
<dl>
<dt>Extra 1a:</dt><dd>The amount to increase/decrease morale.</dd>
<dt>Extra 1b: If 0, increases. Otherwise, decreases.</dd></dd>
<dt>Type 95: Affect Soul Crystal</dt><dd>Records the currently targeted monster in the
party's soul crystal, or erases it if there is already a monster of the same kind recorded.
If the current target is not a monster, this has no effect. If you know the type of the
monster you want to record, then you need to first place one on the map, record it in the
soul crystal, and finally remove it from the map.
<dl>
<dt>Extra 1a:</dt><dd>If 0, records. Otherwise, erases.</dd>
<dt>Extra 1b:</dt><dd>If 0, the monster is given a chance to resist. If 1, the capture is
forced.</dd>
<dt>Note:</dt><dd>Recording a monster works exactly as a successful casting of Capture
Soul on it, meaning that a random existing monster will be erased if necessary to make
room. Multispace monsters, monsters of the Important race, and monsters with the Splits
special ability will not be recorded.</dd></dd>
<dt>Type 96: Affect Monster Attack</dt><dd>Changes the strength of one of a monster's
attacks. If the target is not a monster, this has no effect.
<dl>
<dt>Extra 1a:</dt><dd>The attack to change. (Range 0 ... 2)</dd>
<dt>Extra 1b:</dt><dd>The amount to change the number of dice. (0 to leave it
unchanged.)</dd>
<dt>Extra 1c:</dt><dd>The amount to change the number of sides. (0 to leave it
unchanged.)</dd>
<dt>Extra 2a:</dt><dd>If 0, increase strength. Otherwise, decrease.</dd></dd>
<dt>Type 97: Affect Monster Statistic</dt><dd>Changes one of a monster's inherent
statistics. If the target is not a monster, this has no effect.
<dl>
<dt>Extra 1a:</dt><dd>The amount to increase/decrease. (Range 0 ... 7)</dd>
<dt>Extra 1b:</dt><dd>If 0, increase. Otherwise, decrease.</dd>
<dt>Extra 2a:</dt><dd>The statistic to increase/decrease: 0 - max health, 1 - max magic,
2 - armor, 3 - skill, 4 - speed, 5 - mage spells, 6 - priest spells, 7 - magic resistance,
8 - fire resistance, 9 - cold resistance, 10 - poison resistance</dd></dd>
<dt>Type 98: Affect Statistic</dt><dd>Changes the character's statistics (e.g. Strength,
Mage Spells, etc.)
<dl>
@@ -1480,7 +1530,7 @@ the party in.</dd>
sector (Range 0 ... 47, 0 ... 47)</dd>
<dt>Uses:</dt><dd>If, when the party leaves at the north end of a dungeon, you want them
to be in a different location in the outdoors from where they were when the entered, place
a special node of this type just before the north exit (where theyre forced to step on
a special node of this type just before the north exit (where they're forced to step on
it).</dd>
<dt>Note:</dt><dd>When this node is called, there is a delay while the new outdoors
section is loaded into memory. Try not to call it too often.</dd></dd>

View File

@@ -1066,12 +1066,14 @@ bool monst_check_special_terrain(location where_check,short mode,short which_mon
return can_enter;
}
void record_monst(cCreature *which_m) {
void record_monst(cCreature* which_m, bool forced) {
short r1;
r1 = get_ran(1,1,100);
r1 = (r1 * 7) / 10;
if(forced) r1 = 0;
if((which_m->x_width > 1) || (which_m->y_width > 1)) {
ASB("Capture Soul: Monster is too big.");
}

View File

@@ -31,7 +31,7 @@ bool town_move_monster(short num,location dest);
bool monster_placid(short m_num);
void monst_inflict_fields(short which_monst);
bool monst_check_special_terrain(location where_check,short mode,short which_monst);
void record_monst(cCreature *which_m);
void record_monst(cCreature* which_m, bool forced=false);
short place_monster(mon_num_t which,location where,bool forced=false);
bool summon_monster(mon_num_t which,location where,short duration,short given_attitude,bool by_party);
void activate_monsters(short code,short attitude);

View File

@@ -2200,7 +2200,7 @@ void general_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
break;
case eSpecType::FORCED_GIVE:
check_mess = true;
if(!univ.party.forced_give(spec.ex1a,eItemAbil::NONE) && spec.ex1b >= 0)
if(!univ.party.forced_give(spec.ex1a + 10000 * spec.ex2a,eItemAbil::NONE) && spec.ex1b >= 0)
*next_spec = spec.ex1b;
break;
case eSpecType::BUY_ITEMS_OF_TYPE:
@@ -3001,6 +3001,63 @@ void affect_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
else univ.party[i].skills[skill] = minmax(0, skill_max[skill], univ.party[i].skills[skill] + adj);
}
break;
case eSpecType::AFFECT_LEVEL:
if(pc_num >= 100) {
int lvl = pc->get_level();
if(spec.ex1b == 0)
lvl += spec.ex1a;
else lvl -= spec.ex1a;
dynamic_cast<cCreature*>(pc)->level = lvl;
} else for(i = 0; i < 6; i++)
if(pc_num == 6 || pc_num == i) {
int cur = univ.party[i].get_level();
int lvl = cur;
if(spec.ex1b == 0)
lvl += spec.ex1a;
else lvl -= spec.ex1a;
univ.party[i].level = lvl;
}
break;
case eSpecType::AFFECT_MORALE:
pc->scare(spec.ex1a * (spec.ex1b != 0 ? 1 : -1));
break;
case eSpecType::AFFECT_MONST_ATT:
if(pc_num < 100) break;
if(spec.ex1a < 0 || spec.ex1a > 2) {
giveError("Invalid monster attack (0-2)");
break;
}
if(spec.ex2a == 0) {
dynamic_cast<cCreature*>(pc)->a[spec.ex1a].dice += spec.ex1b;
dynamic_cast<cCreature*>(pc)->a[spec.ex1a].dice += spec.ex1c;
} else {
dynamic_cast<cCreature*>(pc)->a[spec.ex1a].dice -= spec.ex1b;
dynamic_cast<cCreature*>(pc)->a[spec.ex1a].dice -= spec.ex1c;
}
break;
case eSpecType::AFFECT_MONST_STAT:
if(pc_num < 100) break;
if(spec.ex2a < 0 || spec.ex2a > 7) {
giveError("Invalid monster stat (0-7)");
break;
}
i = spec.ex1a;
if(spec.ex1b > 0)
i = -i;
switch(spec.ex2a) {
case 0: dynamic_cast<cCreature*>(pc)->m_health += i; break;
case 1: dynamic_cast<cCreature*>(pc)->max_mp += i; break;
case 2: dynamic_cast<cCreature*>(pc)->armor += i; break;
case 3: dynamic_cast<cCreature*>(pc)->skill += i; break;
case 4: dynamic_cast<cCreature*>(pc)->speed += i; break;
case 5: dynamic_cast<cCreature*>(pc)->mu += i; break;
case 6: dynamic_cast<cCreature*>(pc)->cl += i; break;
case 7: dynamic_cast<cCreature*>(pc)->magic_res += i; break;
case 8: dynamic_cast<cCreature*>(pc)->fire_res += i; break;
case 9: dynamic_cast<cCreature*>(pc)->cold_res += i; break;
case 10:dynamic_cast<cCreature*>(pc)->poison_res += i; break;
}
break;
case eSpecType::AFFECT_MAGE_SPELL:
if(pc_num >= 100) break;
if(spec.ex1a != minmax(0,61,spec.ex1a)) {
@@ -3042,6 +3099,15 @@ void affect_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
}
univ.party.alchemy[spec.ex1a] = true;
break;
case eSpecType::AFFECT_SOUL_CRYSTAL:
if(pc_num < 100) break;
if(spec.ex1a == 0)
record_monst(dynamic_cast<cCreature*>(pc), spec.ex1b);
else for(i = 0; i < 4; i++) {
if(univ.party.imprisoned_monst[i] == dynamic_cast<cCreature*>(pc)->number)
univ.party.imprisoned_monst[i] = 0;
}
break;
case eSpecType::AFFECT_PARTY_STATUS:
if(spec.ex2a < 0 || spec.ex2a > 3) break;
if(spec.ex1b == 0 && spec.ex2a == 1 && univ.party.in_boat >= 0)

View File

@@ -430,6 +430,11 @@ bool cParty::give_item(cItem item,bool do_print) {
// TODO: Utilize the second parameter in special node processing
// if abil > 0, force abil, else ignore
bool cParty::forced_give(item_num_t item_num,eItemAbil abil,short dat) {
bool force_equip = false;
if(item_num >= 10000) {
item_num -= 10000;
force_equip = true;
}
if(item_num < 0 || item_num >= univ.scenario.scen_items.size())
return true;
cItem item = univ.scenario.scen_items[item_num];
@@ -442,6 +447,8 @@ bool cParty::forced_give(item_num_t item_num,eItemAbil abil,short dat) {
for(int j = 0; j < 24; j++)
if(adven[i]->main_status == eMainStatus::ALIVE && adven[i]->items[j].variety == eItemType::NO_ITEM) {
adven[i]->items[j] = item;
if(force_equip)
adven[i]->equip[j] = true;
if(print_result) {
std::ostringstream announce;

View File

@@ -605,13 +605,13 @@ enum class eSpecType {
AFFECT_TRAITS = 88,
AFFECT_AP = 89,
AFFECT_NAME = 90,
UNUSED30 = 91,
UNUSED31 = 92,
UNUSED32 = 93,
UNUSED33 = 94,
UNUSED34 = 95,
UNUSED35 = 96,
UNUSED36 = 97,
AFFECT_LEVEL = 91,
AFFECT_MORALE = 92,
AFFECT_SOUL_CRYSTAL = 93,
AFFECT_EQUIPPED = 94,
AFFECT_MONST_TARG = 95,
AFFECT_MONST_ATT = 96,
AFFECT_MONST_STAT = 97,
AFFECT_STAT = 98,
AFFECT_MAGE_SPELL = 99,
AFFECT_PRIEST_SPELL = 100,