From d639310ae112c8031f132c251da7845498bb5961 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno@eressea.de>
Date: Sat, 9 Sep 2023 07:03:30 +0200
Subject: [PATCH] fix a crash caused by new weapons code

---
 src/battle.c              | 24 ++++++++++++++----------
 src/battle.h              |  7 +++++--
 src/battle.test.c         | 16 ++++++++--------
 src/items/weapons.c       |  4 ++--
 src/spells/combatspells.c |  7 ++++---
 5 files changed, 33 insertions(+), 25 deletions(-)

diff --git a/src/battle.c b/src/battle.c
index 195fc3ff3..33098abe5 100644
--- a/src/battle.c
+++ b/src/battle.c
@@ -665,9 +665,9 @@ weapon_effskill(troop t, troop enemy, const weapon * w,
     fighter *tf = t.fighter;
     unit *tu = t.fighter->unit;
     /* Alle Modifier berechnen, die fig durch die Waffen bekommt. */
-    if (w) {
+    if (w && w->item.type) {
         int skill = 0;
-        const weapon_type *wtype = WEAPON_TYPE(w);
+        const weapon_type *wtype = resource2weapon(w->item.type->rtype);
 
         if (attacking) {
             skill = w->attackskill;
@@ -1941,9 +1941,12 @@ static int setreload(troop at)
 {
     fighter *af = at.fighter;
     const weapon_type *wtype = WEAPON_TYPE(af->person[at.index].missile);
-    if (wtype->reload == 0)
-        return 0;
-    return af->person[at.index].reload = wtype->reload;
+    if (wtype) {
+        if (wtype->reload != 0) {
+            return af->person[at.index].reload = wtype->reload;
+        }
+    }
+    return 0;
 }
 
 int getreload(troop at)
@@ -3113,7 +3116,7 @@ static void equip_weapons(fighter* fig)
         wp = arraddnptr(fig->weapons, 1);
         wp->attackskill = weapon_skill(wtype, u, true);
         wp->defenseskill = weapon_skill(wtype, u, false);
-        wp->item = itm;
+        wp->item.ref = itm;
     }
     w = arrlen(fig->weapons);
     qsort(fig->weapons, w, sizeof(weapon), cmp_weapon);
@@ -3122,11 +3125,12 @@ static void equip_weapons(fighter* fig)
 
     /* hand out weapons: */
     for (i = 0; i != w; ++i) {
-        const weapon *wp = fig->weapons + i;
-        const weapon_type *wtype = WEAPON_TYPE(wp);
+        weapon *wp = fig->weapons + i;
+        const item *itm = wp->item.ref;
+        const weapon_type *wtype = resource2weapon(item2resource(itm->type));
         bool is_missile;
         assert(wtype);
-
+        wp->item.type = itm->type;
         is_missile = (wtype->flags & WTF_MISSILE);
         if (!is_missile && wpless > wp->attackskill + wp->defenseskill) {
             /* we fight better with bare hands than this melee weapon */
@@ -3146,7 +3150,7 @@ static void equip_weapons(fighter* fig)
         }
         if (wp->attackskill >= 0 || wp->defenseskill >= 0)
         {
-            int count = wp->item->number;
+            int count = itm->number;
             while (count > 0 && (p_missile < fig->alive || p_melee < fig->alive)) {
                 if (is_missile) {
                     if (p_missile < fig->alive) {
diff --git a/src/battle.h b/src/battle.h
index 3929b6336..b53b62abb 100644
--- a/src/battle.h
+++ b/src/battle.h
@@ -96,12 +96,15 @@ typedef struct battle {
 } battle;
 
 typedef struct weapon {
-    const struct item* item;
+    union {
+        struct item *ref;
+        const struct item_type *type;
+    } item;
     int attackskill;
     int defenseskill;
 } weapon;
 
-#define WEAPON_TYPE(wp) ((wp) ? (wp)->item->type->rtype->wtype : NULL)
+#define WEAPON_TYPE(wp) ((wp && (wp)->item.type) ? (wp)->item.type->rtype->wtype : NULL)
 
 typedef struct troop {
     struct fighter* fighter;
diff --git a/src/battle.test.c b/src/battle.test.c
index 24574fa86..9de185d19 100644
--- a/src/battle.test.c
+++ b/src/battle.test.c
@@ -124,12 +124,12 @@ static void test_select_weapon(CuTest *tc) {
     b = make_battle(au->region);
     af = make_fighter(b, au, make_side(b, au->faction, 0, 0, 0), false);
     CuAssertIntEquals(tc, 3, (int)arrlen(af->weapons));
-    CuAssertPtrEquals(tc, i_axe, (item *)af->person[0].melee->item);
+    CuAssertPtrEquals(tc, it_axe, (item_type *)af->person[0].melee->item.type);
     CuAssertPtrEquals(tc, NULL, (weapon *)af->person[0].missile);
-    CuAssertPtrEquals(tc, i_sword, (item *)af->person[1].melee->item);
-    CuAssertPtrEquals(tc, i_missile, (item *)af->person[1].missile->item);
+    CuAssertPtrEquals(tc, it_sword, (item_type *)af->person[1].melee->item.type);
+    CuAssertPtrEquals(tc, it_missile, (item_type *)af->person[1].missile->item.type);
     CuAssertPtrEquals(tc, NULL, (weapon *)af->person[2].melee);
-    CuAssertPtrEquals(tc, i_missile, (item *)af->person[2].missile->item);
+    CuAssertPtrEquals(tc, it_missile, (item_type *)af->person[2].missile->item.type);
     free_battle(b);
 
     test_teardown();
@@ -154,7 +154,7 @@ static void test_select_weapon_restricted(CuTest *tc) {
     b = make_battle(au->region);
     af = make_fighter(b, au, make_side(b, au->faction, 0, 0, 0), false);
     CuAssertIntEquals(tc, 1, (int)arrlen(af->weapons));
-    CuAssertPtrEquals(tc, au->items, (void *)af->weapons[0].item);
+    CuAssertPtrEquals(tc, (item_type *)au->items->type, (item_type *)af->weapons[0].item.type);
     CuAssertPtrEquals(tc, af->weapons, (void *)af->person[0].melee);
     free_battle(b);
 
@@ -163,7 +163,7 @@ static void test_select_weapon_restricted(CuTest *tc) {
     b = make_battle(au->region);
     af = make_fighter(b, au, make_side(b, au->faction, 0, 0, 0), false);
     CuAssertIntEquals(tc, 1, (int)arrlen(af->weapons));
-    CuAssertPtrEquals(tc, au->items, (void *)af->weapons[0].item);
+    CuAssertPtrEquals(tc, (item_type *)au->items->type, (item_type *)af->weapons[0].item.type);
     CuAssertPtrNotNull(tc, af->person);
     CuAssertPtrEquals(tc, NULL, (void *)af->person[0].melee);
     free_battle(b);
@@ -175,7 +175,7 @@ static void test_select_weapon_restricted(CuTest *tc) {
     af = make_fighter(b, au, make_side(b, au->faction, 0, 0, 0), false);
     CuAssertPtrNotNull(tc, af->weapons);
     CuAssertIntEquals(tc, 1, (int)arrlen(af->weapons));
-    CuAssertPtrEquals(tc, au->items, (void *)af->weapons[0].item);
+    CuAssertPtrEquals(tc, (item_type *)au->items->type, (item_type *)af->weapons[0].item.type);
     CuAssertPtrEquals(tc, af->weapons, (void *)af->person[0].melee);
     free_battle(b);
 
@@ -185,7 +185,7 @@ static void test_select_weapon_restricted(CuTest *tc) {
     b = make_battle(au->region);
     af = make_fighter(b, au, make_side(b, au->faction, 0, 0, 0), false);
     CuAssertIntEquals(tc, 1, (int)arrlen(af->weapons));
-    CuAssertPtrEquals(tc, au->items, (void *)af->weapons[0].item);
+    CuAssertPtrEquals(tc, (item_type *)au->items->type, (void *)af->weapons[0].item.type);
     CuAssertPtrEquals(tc, NULL, (void *)af->person[0].melee);
     free_battle(b);
 
diff --git a/src/items/weapons.c b/src/items/weapons.c
index 168bd61f5..23805e5c5 100644
--- a/src/items/weapons.c
+++ b/src/items/weapons.c
@@ -43,7 +43,7 @@ int *casualties)
         message *msg;
         for (i = 0; i <= at->index; ++i) {
             const weapon *wp = fi->person[i].melee;
-            if (wp != NULL && wp->item->type == wtype->itype)
+            if (WEAPON_TYPE(wp) == wtype)
                 ++k;
         }
         msg = msg_message("useflamingsword", "amount unit", k, fi->unit);
@@ -103,7 +103,7 @@ int *casualties)
         message *msg;
 
         for (i = 0; i <= at->index; ++i) {
-            if (af->person[i].reload == 0 && af->person[i].missile->item->type == wtype->itype)
+            if (af->person[i].reload == 0 && WEAPON_TYPE(af->person[i].missile) == wtype)
                 ++k;
         }
         msg = msg_message("usecatapult", "amount unit", k, au);
diff --git a/src/spells/combatspells.c b/src/spells/combatspells.c
index 2a0c51cf0..7bfc49df9 100644
--- a/src/spells/combatspells.c
+++ b/src/spells/combatspells.c
@@ -287,10 +287,11 @@ int sp_combatrosthauch(struct castorder * co)
         for (w = 0; w != len; ++w) {
             weapon *wp = df->weapons;
             if (df->unit->items && force > 0) {
-                item ** itp = i_find(&df->unit->items, wp->item->type);
+                const item_type *itype = wp->item.type;
+                item ** itp = i_find(&df->unit->items, itype);
                 if (*itp) {
                     item *it = *itp;
-                    requirement *mat = wp->item->type->construction->materials;
+                    requirement *mat = itype->construction->materials;
                     int n = force;
                     if (it->number < n) n = it->number;
 
@@ -299,7 +300,7 @@ int sp_combatrosthauch(struct castorder * co)
                             int p;
                             force -= n;
                             k += n;
-                            i_change(itp, wp->item->type, -n);
+                            i_change(itp, itype, -n);
                             for (p = 0; n && p != df->unit->number; ++p) {
                                 if (df->person[p].melee == wp) {
                                     df->person[p].melee = NULL;