Skip to content

Commit

Permalink
Merge pull request #282 from doug1234/master
Browse files Browse the repository at this point in the history
Improved favored enemy and fix to max number of bardic music
  • Loading branch information
DudeMcDude authored Apr 6, 2018
2 parents c1a0b6b + 64b67d3 commit f4bbe32
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 3 deletions.
5 changes: 4 additions & 1 deletion TemplePlus/condition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5160,10 +5160,13 @@ int ClassAbilityCallbacks::BardMusicRadial(DispatcherCallbackArgs args){
if (!bardLvl || perfSkill < 3)
return 0;

//Ask python for the maximum number of uses of bardic music
int nMaxBardicMusic = d20Sys.D20QueryPython(args.objHndCaller, "Max Bardic Music");

RadialMenuEntryParent bmusic(5039);
bmusic.flags |= 0x6;
bmusic.minArg = args.GetCondArg(0);
bmusic.maxArg = bardLvl;
bmusic.maxArg = nMaxBardicMusic;
auto bmusicId = bmusic.AddChildToStandard(args.objHndCaller, RadialMenuStandardNode::Class);

RadialMenuEntryAction insCourage(5040, D20A_BARDIC_MUSIC, BM_INSPIRE_COURAGE, "TAG_CLASS_FEATURES_BARD_INSPIRE_COURAGE");
Expand Down
131 changes: 131 additions & 0 deletions TemplePlus/python/python_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1434,6 +1434,136 @@ static PyObject* PyObjHandle_ConditionAddWithArgs(PyObject* obj, PyObject* args)
return PyInt_FromLong(result);
}

static PyObject* PyObjHandle_FavoredEnemy(PyObject* obj, PyObject* args) {
auto self = GetSelf(obj);
if (!self->handle)
return PyInt_FromLong(0);

objHndl critter;
if (!PyArg_ParseTuple(args, "O&:objhndl.is_favored_enemy", &ConvertObjHndl, &critter)) {
return 0;
}

if (!critter)
return PyInt_FromLong(0);

auto category = critterSys.GetCategory(critter);
int result = 0;

switch (category) {
case mc_type_aberration:
result = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_ABERRATION);
break;
case mc_type_animal:
result = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_ANIMAL);
break;
case mc_type_beast:
result = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_BEAST);
break;
case mc_type_construct:
result = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_CONSTRUCT);
break;
case mc_type_elemental:
result = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_ELEMENTAL);
break;
case mc_type_giant:
result = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_GIANT);
break;
case mc_type_humanoid:
{
//Check the subtype (be careful since it could fall into more than one category, if so return the highest feat count)
int flags = critterSys.GetSubcategoryFlags(critter);
if (flags & mc_subtype_goblinoid) {
int count = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_HUMANOID_GOBLINOID);
if (count > result) result = count;
}
if (flags & mc_subtype_reptilian) {
int count = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_HUMANOID_REPTILIAN);
if (count > result) result = count;
}
if (flags & mc_subtype_dwarf) {
int count = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_HUMANOID_DWARF);
if (count > result) result = count;
}
if (flags & mc_subtype_elf) {
int count = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_HUMANOID_ELF);
if (count > result) result = count;
}
if (flags & mc_subtype_gnoll) {
int count = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_HUMANOID_GNOLL);
if (count > result) result = count;
}
if (flags & mc_subtype_gnome) {
int count = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_HUMANOID_GNOME);
if (count > result) result = count;
}
if (flags & mc_subtype_halfling) {
int count = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_HUMANOID_HALFLING);
if (count > result) result = count;
}
if (flags & mc_subtype_orc) {
int count = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_HUMANOID_ORC);
if (count > result) result = count;
}
if (flags & mc_subtype_human) {
int count = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_HUMANOID_HUMAN);
if (count > result) result = count;
}
}
break;
case mc_type_ooze:
result = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_OOZE);
break;
case mc_type_plant:
result = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_PLANT);
break;
case mc_type_shapechanger:
result = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_SHAPECHANGER);
break;
case mc_type_vermin:
result = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_VERMIN);
break;
case mc_type_dragon:
result = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_DRAGON);
break;
case mc_type_magical_beast:
result = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_BEAST);
break;
case mc_type_monstrous_humanoid:
result = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_MONSTROUS_HUMANOID);
break;
case mc_type_outsider:
{
//Check the subtype (since it could fall into more than one category be careful to return the highest count)
int flags = critterSys.GetSubcategoryFlags(critter);
if (flags & mc_subtype_evil) {
int count = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_OUTSIDER_EVIL);
if (count > result) result = count;
}
if (flags & mc_subtype_good) {
int count = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_OUTSIDER_GOOD);
if (count > result) result = count;
}
if (flags & mc_subtype_lawful) {
int count = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_OUTSIDER_LAWFUL);
if (count > result) result = count;
}
if (flags & mc_subtype_chaotic) {
int count = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_OUTSIDER_CHAOTIC);
if (count > result) result = count;
}
}
break;
case mc_type_fey:
result = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_FEY);
break;
case mc_type_undead:
result = feats.HasFeatCountByClass(self->handle, FEAT_FAVORED_ENEMY_UNDEAD);
break;
}

return PyInt_FromLong(result);
}

static PyObject* PyObjHandle_IsFlankedBy(PyObject* obj, PyObject* args) {
auto self = GetSelf(obj);
Expand Down Expand Up @@ -3269,6 +3399,7 @@ static PyMethodDef PyObjHandleMethods[] = {
{ "is_active_combatant", PyObjHandle_IsActiveCombatant, METH_VARARGS, NULL },
{ "is_category_type", PyObjHandle_IsCategoryType, METH_VARARGS, NULL },
{ "is_category_subtype", PyObjHandle_IsCategorySubtype, METH_VARARGS, NULL },
{ "is_favored_enemy", PyObjHandle_FavoredEnemy, METH_VARARGS, NULL },
{ "is_flanked_by", PyObjHandle_IsFlankedBy, METH_VARARGS, NULL },
{ "is_friendly", PyObjHandle_IsFriendly, METH_VARARGS, NULL },
{ "is_unconscious", PyObjHandle_IsUnconscious, METH_VARARGS, NULL },
Expand Down
Binary file modified tpdata/tpgamefiles.dat
Binary file not shown.
5 changes: 5 additions & 0 deletions tpdatasrc/tpgamefiles/rules/feats/improved favored enemy.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name: Improved Favored Enemy
flags: 12582912
prereqs:
description: You deal an extra 3 points of damage to your favored enemies. This benefit stacks with any existing favored enemy bonus gained from another class.
prereq descr: Base attack bonus +5 and favored enemy ability,
15 changes: 15 additions & 0 deletions tpdatasrc/tpgamefiles/scr/feats/feat - Improved Favored Enemy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from toee import *


def CheckPrereq(attachee, classLevelled, abilityScoreRaised):

#Return zero if base attack bonus is too low
if attachee.get_base_attack_bonus() < 5:
return 0

#Check for any favored enemy feat
for i in range (feat_favored_enemy_aberration , feat_favored_enemy_humanoid_human):
if attachee.has_feat(i):
return 1

return 0
10 changes: 8 additions & 2 deletions tpdatasrc/tpgamefiles/scr/tpModifiers/extra_music.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,20 @@ def EMNewDay(attachee, args, evt_obj):

BardicMusicCount = attachee.has_feat("Extra Music")


#Extra Music grants 4 additional uses of Bardic Music each time the feat is taken
#Max music per day remains 3, can't find a way to alter it. Works properly nonetheless.
args.set_arg(0, args.get_arg(0) + BardicMusicCount * 4)

return 0

def QueryMaxBardicMusic(attachee, args, evt_obj):

#Total uses = bard level + extra music count * 4
MaxMusicCount = attachee.has_feat("Extra Music") * 4
MaxMusicCount += attachee.stat_level_get(stat_level_bard)
evt_obj.return_val = MaxMusicCount
return 0

eSF = PythonModifier()
eSF.ExtendExisting("Bardic Music")
eSF.AddHook(ET_OnNewDay, EK_NEWDAY_REST, EMNewDay, ())
eSF.AddHook(ET_OnD20PythonQuery, "Max Bardic Music", QueryMaxBardicMusic, ())
23 changes: 23 additions & 0 deletions tpdatasrc/tpgamefiles/scr/tpModifiers/improved_favored_enemy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#Improved Favored Enemy: Complete Warrior, p. 101

from templeplus.pymod import PythonModifier
from toee import *
import tpdp

print "Registering Improved Favored Enemy"

#Feat adds 3 extra damage
bon_val = 3

def impFavoredEnemyDamageBonus(attachee, args, evt_obj):

target = evt_obj.attack_packet.target
favored_enemy = attachee.is_favored_enemy(target)

if favored_enemy:
evt_obj.damage_packet.bonus_list.add_from_feat(bon_val, 0, 114, "Improved Favored Enemy")
return 0

impFavoredEnemy = PythonModifier("Improved Favored Enemy", 2) # args are just-in-case placeholders
impFavoredEnemy.MapToFeat("Improved Favored Enemy")
impFavoredEnemy.AddHook(ET_OnDealingDamage, EK_NONE, impFavoredEnemyDamageBonus, ())

0 comments on commit f4bbe32

Please sign in to comment.