![]() |
#1 |
Rookie
Join Date: Jun 2020
Posts: 8
![]() |
Monster_Base Flags
Hey there!
I have been messing around with some of the code on the "4.2-Release" branch of Angband Vanilla. Unfortunately, I'm finding that this codebase is *SO* large that I'm having trouble figuring out how to grab simple parameters for alteration. So... what I'm trying to do is to figure out how to alter the function "effect_handler_TAP_UNLIFE" in the file "effects.c". Origin_Behavior: Current behavior in "4.2-Release" is described as: "When 'Tap Unlife' is cast by the necromancer; it selects the closest undead monster in Line of Sight, and it damages the undead monster as it restores some spell points to the necromancer based on the damage to the undead monster." Current behavior: Code:
bool effect_handler_TAP_UNLIFE(effect_handler_context_t *context) { int amount = effect_calculate_value(context, false); struct loc target; struct monster *mon = NULL; char m_name[80]; int drain = 0; bool fear = false; bool dead = false; context->ident = true; /* Closest living monster */ if (!target_set_closest(TARGET_KILL, monster_is_undead)) { return false; } target_get(&target); mon = target_get_monster(); /* Hurt the monster */ monster_desc(m_name, sizeof(m_name), mon, MDESC_TARG); msg("You draw power from the %s.", m_name); drain = MIN(mon->hp, amount) / 4; dead = mon_take_hit(mon, amount, &fear, " is destroyed!"); /* Gain mana */ effect_simple(EF_RESTORE_MANA, context->origin, format("%d", drain), 0, 0, 0, 0, 0, NULL); /* Handle fear for surviving monsters */ if (!dead && monster_is_visible(mon)) { message_pain(mon, amount); if (fear) { add_monster_message(mon, MON_MSG_FLEE_IN_TERROR, true); } } return true; } Changed_Behavior: Intended change to the behavior to the "Tap Unlife" spell in a private branch called "Necromancer_Changes" is: "When 'Tap Unlife' is cast by the necromancer; it selects all undead monsters in Line of Sight and it damages the undead monsters as it restores some spell points to the necromancer based on the damage inflicted to one instance of an undead monster." My code changes: Code:
bool effect_handler_TAP_UNLIFE(effect_handler_context_t *context) { int amount = effect_calculate_value(context, false); struct loc target; struct monster *mon = NULL; char m_name[80]; int drain = 0; bool fear = false; bool dead = false; msg("XXXCalled Tap Unlife: amount: %i.",amount); context->ident = true; /* Closest living monster */ if (!target_set_closest(TARGET_KILL, monster_is_undead)) { return false; } target_get(&target); mon = target_get_monster(); struct loc origin = origin_get_loc(context->origin); int i = 0; for (i = 1; i < cave_monster_max(cave); i++) { struct monster *mon = cave_monster(cave, i); /* Paranoia -- Skip dead monsters */ if (!mon->race) continue; /* Require line of sight */ if (!los(cave, origin, mon->grid)) continue; /* Jump directly to the monster */ /* Hurt the monster */ if(monster_is_undead) { monster_desc(m_name, sizeof(m_name), mon, MDESC_TARG); msg("You draw power from the %s.", m_name); drain = MIN(mon->hp, amount) / 4; dead = mon_take_hit(mon, amount, &fear, " is destroyed!"); } context->ident = true; } /* Hurt the monster */ /* monster_desc(m_name, sizeof(m_name), mon, MDESC_TARG); msg("You draw power from the %s.", m_name); drain = MIN(mon->hp, amount) / 4; dead = mon_take_hit(mon, amount, &fear, " is destroyed!"); */ /* Gain mana */ effect_simple(EF_RESTORE_MANA, context->origin, format("%d", drain), 0, 0, 0, 0, 0, NULL); /* Handle fear for surviving monsters */ /* if (!dead && monster_is_visible(mon)) { message_pain(mon, amount); if (fear) { add_monster_message(mon, MON_MSG_FLEE_IN_TERROR, true); } } */ return true; } You'll notice if you test this code that every monster in Line of Sight is currently targeted for damage (Undead or not) [Apparently, 'monster_is_undead' currently always evaluates to 'true'] as long as at least one Undead is in Line of Sight. This behavior is undesirable... I would like to target undead exclusively with the casting of "Tap Unlife". I've been trying to figure out how to grab a property for a given monster that will tell me if the monster has a flag, 'UNDEAD'... but I'm coming up dry. For those of you with more experience editing the vanilla Angband codebase... if you know how to resolve this problem... would you mind suggesting a solution? Note... I have NO INTENTION of replacing the current vanilla behavior with my changes as part of "canon"; I'm just... trying stuff right now. Last edited by Celiend; June 25, 2020 at 06:28. |
![]() |
![]() |
![]() |
#2 |
Veteran
Join Date: May 2012
Location: Adelaide, Australia
Posts: 2,433
![]() |
I'd take a look at how the priest spell "dispel undead" works.
Code:
effect:PROJECT_LOS_AWARE:DISP_UNDEAD |
![]() |
![]() |
![]() |
#3 | |
Rookie
Join Date: Jun 2020
Posts: 8
![]() |
Quote:
Code:
spell:Dispel Undead:10:14:55:6 effect:PROJECT_LOS_AWARE:DISP_UNDEAD dice:d$S expr:S:PLAYER_LEVEL:* 3 desc:Inflicts unresistable damage on each undead monster within line of sight. Code:
bool effect_handler_PROJECT_LOS_AWARE(effect_handler_context_t *context) { int i; int dam = effect_calculate_value(context, context->other ? true : false); int typ = context->subtype; int flg = PROJECT_JUMP | PROJECT_KILL | PROJECT_HIDE; if (context->aware) flg |= PROJECT_AWARE; /* Affect all (nearby) monsters */ for (i = 1; i < cave_monster_max(cave); i++) { struct monster *mon = cave_monster(cave, i); struct loc grid; /* Paranoia -- Skip dead monsters */ if (!mon->race) continue; /* Location */ grid = mon->grid; /* Require line of sight */ if (!square_isview(cave, grid)) continue; /* Jump directly to the target monster */ (void)project(source_player(), 0, grid, dam, typ, flg, 0, 0, context->obj); context->ident = true; } /* Result */ return true; } Last edited by Celiend; June 25, 2020 at 09:08. |
|
![]() |
![]() |
![]() |
#4 |
Vanilla maintainer
Join Date: Apr 2007
Location: Canberra, Australia
Age: 55
Posts: 8,657
Donated: $60
![]() |
I think your problem is here:
You need Code:
if(monster_is_undead(mon))
__________________
One for the Dark Lord on his dark throne In the Land of Mordor where the Shadows lie. |
![]() |
![]() |
![]() |
#5 |
Rookie
Join Date: Jun 2020
Posts: 8
![]() |
Problem solved!!! Thank you wobbly!
The code is sinfully ugly; but mechanically, it's doing exactly what I want it to! (To be clear... the sinfully ugly part is "MY FAULT" not due to your suggestion) Using wobbly's suggested approach: Code:
/** * Draw energy from a nearby undead */ bool effect_handler_TAP_UNLIFE(effect_handler_context_t *context) { int amount = effect_calculate_value(context, false); struct loc target; struct monster *mon = NULL; char m_name[80]; // Hardcoded to affect Undead? int typ = 40; int flg = PROJECT_JUMP | PROJECT_KILL | PROJECT_HIDE; if (context->aware) flg |= PROJECT_AWARE; int drain = 0; bool fear = false; bool dead = false; msg("XXXCalled Tap Unlife: amount: %i.",amount); context->ident = true; /* Closest living monster */ if (!target_set_closest(TARGET_KILL, monster_is_undead)) { return false; } target_get(&target); mon = target_get_monster(); struct loc origin = origin_get_loc(context->origin); int i = 0; for (i = 1; i < cave_monster_max(cave); i++) { struct monster *mon = cave_monster(cave, i); struct loc grid; /* Location */ grid = mon->grid; /* Paranoia -- Skip dead monsters */ if (!mon->race) continue; /* Require line of sight */ if (!los(cave, origin, mon->grid)) continue; /* Jump directly to the monster */ /* Hurt the monster */ /* if(monster_is_undead) { monster_desc(m_name, sizeof(m_name), mon, MDESC_TARG); msg("You draw power from the %s.", m_name); drain = MIN(mon->hp, amount) / 4; dead = mon_take_hit(mon, amount, &fear, " is destroyed!"); } */ (void)project(source_player(), 0, grid, amount, typ, flg, 0, 0, context->obj); context->ident = true; } Thank you to the both of you for responding. ![]() ![]() ![]() |
![]() |
![]() |
![]() |
#6 |
Rookie
Join Date: Jun 2020
Posts: 8
![]() |
Nick's suggested solution works as intended, as well!
This is neat!!! Thank you again for responding, wobbly and Nick! This code is too ugly for me to attempt to submit it as part of a 'pull request'; and mechanically, the playerbase would probably object to the affect this behavior would have on the balance of the Necromancer... so it may be odious from those grounds. I've exerted some direct control over the Vanilla Angband code-base! I am practically squeeking with joy, atm! Code:
bool effect_handler_TAP_UNLIFE(effect_handler_context_t *context) { int amount = effect_calculate_value(context, false); struct loc target; struct monster *mon = NULL; char m_name[80]; // Hardcoded to affect Undead? int typ = 40; int flg = PROJECT_JUMP | PROJECT_KILL | PROJECT_HIDE; if (context->aware) flg |= PROJECT_AWARE; int drain = 0; bool fear = false; bool dead = false; msg("XXXCalled Tap Unlife: amount: %i.",amount); context->ident = true; /* Closest living monster */ if (!target_set_closest(TARGET_KILL, monster_is_undead)) { return false; } target_get(&target); mon = target_get_monster(); struct loc origin = origin_get_loc(context->origin); int i = 0; for (i = 1; i < cave_monster_max(cave); i++) { struct monster *mon = cave_monster(cave, i); struct loc grid; /* Location */ grid = mon->grid; /* Paranoia -- Skip dead monsters */ if (!mon->race) continue; /* Require line of sight */ if (!los(cave, origin, mon->grid)) continue; /* Jump directly to the monster */ /* Hurt the monster */ if(monster_is_undead(mon)) { monster_desc(m_name, sizeof(m_name), mon, MDESC_TARG); msg("You draw power from the %s.", m_name); drain = MIN(mon->hp, amount) / 4; dead = mon_take_hit(mon, amount, &fear, " is destroyed!"); } //(void)project(source_player(), 0, grid, amount, typ, flg, 0, 0, context->obj); context->ident = true; } /* Hurt the monster */ /* monster_desc(m_name, sizeof(m_name), mon, MDESC_TARG); msg("You draw power from the %s.", m_name); drain = MIN(mon->hp, amount) / 4; dead = mon_take_hit(mon, amount, &fear, " is destroyed!"); */ /* Gain mana */ effect_simple(EF_RESTORE_MANA, context->origin, format("%d", drain), 0, 0, 0, 0, 0, NULL); /* Handle fear for surviving monsters */ /* if (!dead && monster_is_visible(mon)) { message_pain(mon, amount); if (fear) { add_monster_message(mon, MON_MSG_FLEE_IN_TERROR, true); } } */ return true; } |
![]() |
![]() |
![]() |
#7 |
Rookie
Join Date: Jun 2020
Posts: 8
![]() |
Here is the pretty version:
Code:
/** * Draw energy from all nearby undead */ bool effect_handler_TAP_UNLIFE(effect_handler_context_t *context) { int amount = effect_calculate_value(context, false); struct loc target; struct monster *mon = NULL; char m_name[80]; int drain = 0; bool fear = false; bool dead = false; context->ident = true; /* Closest living monster */ if (!target_set_closest(TARGET_KILL, monster_is_undead)) { return false; } target_get(&target); mon = target_get_monster(); struct loc origin = origin_get_loc(context->origin); int i = 0; for (i = 1; i < cave_monster_max(cave); i++) { struct monster *mon = cave_monster(cave, i); struct loc grid; /* Location */ grid = mon->grid; /* Paranoia -- Skip dead monsters */ if (!mon->race) continue; /* Require line of sight */ if (!los(cave, origin, mon->grid)) continue; /* Jump directly to the monster */ /* Hurt the monster */ if(monster_is_undead(mon)) { monster_desc(m_name, sizeof(m_name), mon, MDESC_TARG); msg("You draw power from the %s.", m_name); drain = MIN(mon->hp, amount) / 4; dead = mon_take_hit(mon, amount, &fear, " is destroyed!"); } context->ident = true; } /* Gain mana */ effect_simple(EF_RESTORE_MANA, context->origin, format("%d", drain), 0, 0, 0, 0, 0, NULL); return true; } |
![]() |
![]() |
![]() |
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Display Modes | |
|
|
![]() |
||||
Thread | Thread Starter | Forum | Replies | Last Post |
modifying monster.txt & monster_base.txt | Tibarius | Development | 3 | May 16, 2020 18:13 |
List of all Class/Race Flags? | tynan | Vanilla | 2 | March 29, 2014 06:29 |
Monster Flags | fizzix | v4 | 4 | February 10, 2012 00:37 |
Racial Flags | Jungle_Boy | Vanilla | 1 | October 10, 2011 02:17 |
Too darn many flags. :-( | PaulBlay | Development | 9 | April 4, 2009 23:59 |