Add a user-defined name to vehicle definitions.

This also adds partial support for a custom vehicle graphic.
This commit is contained in:
2025-02-22 22:07:55 -05:00
committed by Celtic Minstrel
parent f4bdf95617
commit 8ab663b620
7 changed files with 66 additions and 1 deletions

View File

@@ -13,7 +13,10 @@
<text name='loc-lbl' anchor='area-lbl' relative='pos-in pos' top='11' left='0' width='97' height='14'>Location</text> <text name='loc-lbl' anchor='area-lbl' relative='pos-in pos' top='11' left='0' width='97' height='14'>Location</text>
<text name='loc' rel-anchor='prev' relative='pos pos-in' top='0' left='5' width='40' height='16'/> <text name='loc' rel-anchor='prev' relative='pos pos-in' top='0' left='5' width='40' height='16'/>
<led name='owned' anchor='loc-lbl' relative='pos-in pos' top='11' left='10'>Not Party Property</led> <text name='name-lbl' anchor='loc-lbl' relative='pos-in pos' top='11' left='0' width='97' height='14'>Name</text>
<field name='name' rel-anchor='prev' relative='pos pos-in' top='0' left='5' width='100' height='14'/>
<led name='owned' anchor='name-lbl' relative='pos-in pos' top='11' left='10'>Not Party Property</led>
<button name='cancel' rel-anchor='prev' relative='neg pos' type='regular' def-key='esc' top='15' left='10'>Cancel</button> <button name='cancel' rel-anchor='prev' relative='neg pos' type='regular' def-key='esc' top='15' left='10'>Cancel</button>
<button name='del' rel-anchor='prev' relative='pos pos-in' type='regular' top='0' left='0'>Delete</button> <button name='del' rel-anchor='prev' relative='pos pos-in' type='regular' top='0' left='0'>Delete</button>

View File

@@ -264,6 +264,11 @@ shop ID 0. Shops require the following subtags:
of this element in a `CDATA` declaration. of this element in a `CDATA` declaration.
* `<journal>` - (max unbounded) A journal string. The scenario editor wraps the contents * `<journal>` - (max unbounded) A journal string. The scenario editor wraps the contents
of this element in a `CDATA` declaration. of this element in a `CDATA` declaration.
* `<vehicle>` - (max unbounded) Contains additional data for a placed boat or horse. Only present if the additional data is used.
* `type=` - Must be either `boat` or `horse`.
* `id=` - The horse or boat ID, as written into the map data - a one-based index into the global list of horses or boats.
* `<name>` - A designer-visible name for the boat or horse. Used by the scenario editor to present a list of boats or horses.
* `<pic>` - The graphic to use for the boat or horse.
The `<editor>` element can have the following child tags: The `<editor>` element can have the following child tags:

View File

@@ -289,6 +289,23 @@
</xs:simpleContent> </xs:simpleContent>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:element name="vehicle" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="type">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="boat"/>
<xs:enumeration value="horse"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="id" type="xs:integer"/>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="pic" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence> </xs:sequence>
</xs:complexType> </xs:complexType>
<xs:complexType name="editorData"> <xs:complexType name="editorData">

View File

@@ -904,6 +904,23 @@ void readScenarioFromXml(ticpp::Document&& data, cScenario& scenario) {
if(strnum >= scenario.journal_strs.size()) if(strnum >= scenario.journal_strs.size())
scenario.journal_strs.resize(strnum + 1); scenario.journal_strs.resize(strnum + 1);
game->GetText(&scenario.journal_strs[strnum], false); game->GetText(&scenario.journal_strs[strnum], false);
} else if(type == "vehicle") {
std::string vtype = game->GetAttribute("type");
if(vtype != "boat" && vtype != "horse")
throw xBadVal(type, "type", vtype, game->Row(), game->Column(), fname);
auto& list = (vtype == "boat" ? scenario.boats : scenario.horses);
game->GetAttribute("id", &strnum);
list.resize(strnum);
int i = strnum - 1;
Iterator<Element> vehicle;
for(vehicle = vehicle.begin(game.Get()); vehicle != vehicle.end(); vehicle++) {
vehicle->GetValue(&type);
if(type == "name") {
vehicle->GetText(&list[i].name);
} else if(type == "pic") {
vehicle->GetText(&list[i].pic);
} else throw xBadNode(type, vehicle->Row(), vehicle->Column(), fname);
}
} else throw xBadNode(type, game->Row(), game->Column(), fname); } else throw xBadNode(type, game->Row(), game->Column(), fname);
} }
if(!reqs.empty()) if(!reqs.empty())

View File

@@ -10,6 +10,7 @@
#define BOE_DATA_VEHICLE_H #define BOE_DATA_VEHICLE_H
#include <iosfwd> #include <iosfwd>
#include <string>
#include "location.hpp" #include "location.hpp"
namespace legacy { namespace legacy {
@@ -28,6 +29,8 @@ public:
short which_town; short which_town;
bool exists; bool exists;
bool property; bool property;
pic_num_t pic = 0;
std::string name; // For designer use; not stored in save files
cVehicle(); cVehicle();
void import_legacy(legacy::horse_record_type& old); void import_legacy(legacy::horse_record_type& old);

View File

@@ -2633,6 +2633,7 @@ bool edit_vehicle(cVehicle& what, int num, bool is_boat) {
dlg["loc"].setText(boost::lexical_cast<std::string>(what.loc)); dlg["loc"].setText(boost::lexical_cast<std::string>(what.loc));
dlg["num"].setTextToNum(num); dlg["num"].setTextToNum(num);
dlg["title"].setText(is_boat ? "Edit Boat" : "Edit Horse"); dlg["title"].setText(is_boat ? "Edit Boat" : "Edit Horse");
dlg["name"].setText(what.name);
cLed& prop = dynamic_cast<cLed&>(dlg["owned"]); cLed& prop = dynamic_cast<cLed&>(dlg["owned"]);
prop.setState(what.property ? led_red : led_off); prop.setState(what.property ? led_red : led_off);
@@ -2645,6 +2646,7 @@ bool edit_vehicle(cVehicle& what, int num, bool is_boat) {
if(dlg.accepted()) { if(dlg.accepted()) {
what.property = prop.getState() != led_off; what.property = prop.getState() != led_off;
what.exists = true; what.exists = true;
what.name = dlg["name"].getText();
} }
return what.exists; return what.exists;
} }

View File

@@ -336,6 +336,24 @@ void writeScenarioToXml(ticpp::Printer&& data, cScenario& scenario) {
data.PushAttribute("id", scenario.journal_strs.size() - 1); data.PushAttribute("id", scenario.journal_strs.size() - 1);
data.CloseElement("journal"); data.CloseElement("journal");
} }
for(size_t i = 0; i < scenario.boats.size(); i++) {
if(scenario.boats[i].name.empty() && scenario.boats[i].pic == 0) continue;
data.OpenElement("vehicle");
data.PushAttribute("type", "boat");
data.PushAttribute("id", i + 1);
if(!scenario.boats[i].name.empty()) data.PushElement("name", scenario.boats[i].name);
if(scenario.boats[i].pic > 0) data.PushElement("pic", scenario.boats[i].pic);
data.CloseElement("vehicle");
}
for(size_t i = 0; i < scenario.horses.size(); i++) {
if(scenario.horses[i].name.empty() && scenario.horses[i].pic == 0) continue;
data.OpenElement("vehicle");
data.PushAttribute("type", "horse");
data.PushAttribute("id", i + 1);
if(!scenario.horses[i].name.empty()) data.PushElement("name", scenario.horses[i].name);
if(scenario.horses[i].pic > 0) data.PushElement("pic", scenario.horses[i].pic);
data.CloseElement("vehicle");
}
data.CloseElement("game"); data.CloseElement("game");
data.OpenElement("editor"); data.OpenElement("editor");
data.PushElement("default-ground", scenario.default_ground); data.PushElement("default-ground", scenario.default_ground);