Skip to content

Commit

Permalink
[objects] add: Creature::update_appearance
Browse files Browse the repository at this point in the history
[rules] add: load size from appearance.2da
[profiles] add: appearance constants
  • Loading branch information
jd28 committed Nov 30, 2024
1 parent a698c28 commit 397b686
Show file tree
Hide file tree
Showing 9 changed files with 448 additions and 20 deletions.
7 changes: 5 additions & 2 deletions lib/nw/objects/Appearance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,10 @@ bool deserialize(CreatureAppearance& self, const GffStruct& archive)
self.wings = old;
}

archive.get_to("Appearance_Type", self.id);
uint16_t temp;
if (archive.get_to("Appearance_Type", temp)) {
self.id = Appearance::make(temp);
}
archive.get_to("Portrait", self.portrait, false);
archive.get_to("PortraitId", self.portrait_id, self.portrait.length() == 0);
archive.get_to("Appearance_Head", self.body_parts.head, false); // Only in dynamic models
Expand Down Expand Up @@ -187,7 +190,7 @@ bool serialize(const CreatureAppearance& self, GffBuilderStruct& archive)
{
archive.add_field("Tail_New", self.tail)
.add_field("Wings_New", self.wings)
.add_field("Appearance_Type", self.id)
.add_field("Appearance_Type", uint16_t(*self.id))
.add_field("PortraitId", self.portrait_id)
.add_field("Appearance_Head", uint8_t(self.body_parts.head))
.add_field("BodyPart_Belt", uint8_t(self.body_parts.belt))
Expand Down
3 changes: 2 additions & 1 deletion lib/nw/objects/Appearance.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "../rules/attributes.hpp"
#include "../serialization/Serialization.hpp"

namespace nw {
Expand Down Expand Up @@ -45,7 +46,7 @@ struct CreatureAppearance {
uint32_t tail = 0;
uint32_t wings = 0;

uint16_t id = 0;
Appearance id = Appearance::invalid();
Resref portrait;
uint16_t portrait_id = 0;

Expand Down
25 changes: 15 additions & 10 deletions lib/nw/objects/Creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,16 +119,8 @@ void Creature::clear()
bool Creature::instantiate()
{
if (instantiated_) return true;
auto tda = kernel::twodas().get("appearance");
if (tda) {
if (tda->get_to(appearance.id, "SIZECATEGORY", size)) {
auto cresize = kernel::twodas().get("creaturesize");
if (cresize) {
cresize->get_to(size, "ACATTACKMOD", combat_info.size_ab_modifier);
cresize->get_to(size, "ACATTACKMOD", combat_info.size_ac_modifier);
}
}
}
update_appearance(appearance.id);

nw::kernel::objects().run_instantiate_callback(this);
instantiated_ = (inventory.instantiate() && equipment.instantiate());
size_t i = 0;
Expand Down Expand Up @@ -206,6 +198,19 @@ AlignmentFlags Creature::alignment_flags() const noexcept
return result;
}

void Creature::update_appearance(Appearance id)
{
auto app = kernel::rules().appearances.get(id);
if (!app) { return; }

size = app->size;
auto cresize = kernel::twodas().get("creaturesize");
if (cresize) {
cresize->get_to(size, "ACATTACKMOD", combat_info.size_ab_modifier);
cresize->get_to(size, "ACATTACKMOD", combat_info.size_ac_modifier);
}
}

bool Creature::deserialize(Creature* obj, const nlohmann::json& archive, SerializationProfile profile)
{
if (!obj) {
Expand Down
3 changes: 3 additions & 0 deletions lib/nw/objects/Creature.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ struct Creature : public ObjectBase {
/// Gets alignment flags
AlignmentFlags alignment_flags() const noexcept;

/// Update creatures appearance
void update_appearance(Appearance id);

Common common;
CreatureAppearance appearance;
CombatInfo combat_info;
Expand Down
406 changes: 406 additions & 0 deletions lib/nw/profiles/nwn1/constants.hpp

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions lib/nw/rules/attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ AppearanceInfo::AppearanceInfo(const TwoDARowView& tda)
tda.get_to("LABEL", label);
tda.get_to("STRING_REF", string_ref);
tda.get_to("RACE", model);
tda.get_to("SIZECATEGORY", size);
}

// -- PhenotypeInfo -----------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions lib/nw/rules/attributes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ struct AppearanceInfo {
String label;
uint32_t string_ref = std::numeric_limits<uint32_t>::max();
String model;
int size = 0;

bool valid() const noexcept { return string_ref != 0xFFFFFFFF || !label.empty(); }
};
Expand Down
4 changes: 2 additions & 2 deletions tests/kernel_objects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ TEST(ObjectSystem, LoadCreature)
EXPECT_EQ(ent->common.resref, "nw_chicken");
EXPECT_EQ(ent->stats.get_ability_score(nwn1::ability_dexterity), 7);
EXPECT_EQ(ent->scripts.on_attacked, "nw_c2_default5");
EXPECT_EQ(ent->appearance.id, 31);
EXPECT_EQ(*ent->appearance.id, 31);
EXPECT_EQ(ent->gender, 1);

auto ent2 = nwk::objects().get<nw::Creature>(ent->handle());
Expand All @@ -44,7 +44,7 @@ TEST(ObjectSystem, LoadCreature)
EXPECT_EQ(ent3->common.resref, "pl_agent_001");
EXPECT_EQ(ent3->stats.get_ability_score(nwn1::ability_dexterity), 13);
EXPECT_EQ(ent3->scripts.on_attacked, "mon_ai_5attacked");
EXPECT_EQ(ent3->appearance.id, 6);
EXPECT_EQ(*ent3->appearance.id, 6);
EXPECT_EQ(ent3->appearance.body_parts.shin_left, 1);
EXPECT_EQ(ent3->soundset, 171);
EXPECT_TRUE(nwn1::get_equipped_item(ent3, nw::EquipIndex::chest));
Expand Down
18 changes: 13 additions & 5 deletions tests/objects_creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ TEST(Creature, GffDeserialize)
EXPECT_EQ(obj1->common.resref, "nw_chicken");
EXPECT_EQ(obj1->stats.get_ability_score(nwn1::ability_dexterity), 7);
EXPECT_EQ(obj1->scripts.on_attacked, "nw_c2_default5");
EXPECT_EQ(obj1->appearance.id, 31);
EXPECT_EQ(*obj1->appearance.id, 31);
EXPECT_EQ(obj1->gender, 1);
EXPECT_EQ(obj1->alignment_flags(), nw::align_true_neutral);

Expand All @@ -50,7 +50,7 @@ TEST(Creature, GffDeserialize)
EXPECT_EQ(obj2->common.resref, "pl_agent_001");
EXPECT_EQ(obj2->stats.get_ability_score(nwn1::ability_dexterity), 13);
EXPECT_EQ(obj2->scripts.on_attacked, "mon_ai_5attacked");
EXPECT_EQ(obj2->appearance.id, 6);
EXPECT_EQ(*obj2->appearance.id, 6);
EXPECT_EQ(obj2->appearance.body_parts.shin_left, 1);
EXPECT_EQ(obj2->soundset, 171);
EXPECT_TRUE(nwn1::get_equipped_item(obj2, nw::EquipIndex::chest));
Expand Down Expand Up @@ -343,6 +343,11 @@ TEST(Creature, AttackBonus)
EXPECT_EQ(nwn1::get_ability_score(obj, nwn1::ability_strength), 16);
EXPECT_EQ(nwn1::get_ability_modifier(obj, nwn1::ability_strength), 3);
EXPECT_EQ(obj->combat_info.size_ab_modifier, 1);
obj->update_appearance(nwn1::appearance_type_human);
EXPECT_EQ(obj->combat_info.size_ab_modifier, 0);
obj->update_appearance(nwn1::appearance_type_halfling);
EXPECT_EQ(obj->combat_info.size_ab_modifier, 1);

EXPECT_EQ(29, nwn1::base_attack_bonus(obj));
EXPECT_EQ(45, nwn1::resolve_attack_bonus(obj, nwn1::attack_type_onhand));

Expand Down Expand Up @@ -425,11 +430,14 @@ TEST(Creature, AttackBonus)

EXPECT_TRUE(obj4->stats.has_feat(nwn1::feat_weapon_finesse));
EXPECT_EQ(obj4->combat_info.combat_mode, nw::CombatMode::invalid());
EXPECT_TRUE(nwn1::get_equipped_item(obj4, nw::EquipIndex::righthand));
EXPECT_EQ(nwn1::get_equipped_item(obj4, nw::EquipIndex::righthand)->baseitem, nwn1::base_item_dagger);
auto item4 = nwn1::get_equipped_item(obj4, nw::EquipIndex::righthand);
EXPECT_TRUE(item4);
EXPECT_EQ(item4->baseitem, nwn1::base_item_dagger);
EXPECT_EQ(nwn1::get_ability_modifier(obj4, nwn1::ability_strength), 1);
EXPECT_EQ(nwn1::get_ability_modifier(obj4, nwn1::ability_dexterity), 11);
EXPECT_EQ(25, nwn1::base_attack_bonus(obj4));
EXPECT_EQ(obj4->combat_info.size_ab_modifier, 1);
EXPECT_TRUE(nwn1::weapon_is_finessable(obj4, item4));
EXPECT_EQ(40, nwn1::resolve_attack_bonus(obj4, nwn1::attack_type_onhand));

// Dual Wield
Expand Down Expand Up @@ -835,7 +843,7 @@ TEST(Creature, JsonSerialization)
EXPECT_TRUE(ent2);
EXPECT_EQ(ent2->stats.get_ability_score(nwn1::ability_dexterity), 13);
EXPECT_EQ(ent2->scripts.on_attacked, "mon_ai_5attacked");
EXPECT_EQ(ent2->appearance.id, 6);
EXPECT_EQ(*ent2->appearance.id, 6);
EXPECT_EQ(ent2->appearance.body_parts.shin_left, 1);
EXPECT_EQ(ent2->soundset, 171);
EXPECT_TRUE(nwn1::get_equipped_item(ent2, nw::EquipIndex::chest));
Expand Down

0 comments on commit 397b686

Please sign in to comment.