Your default scenario comes with 383 premade item types, number 0 to 382, and you can
-have 400 item types overall. Like terrain types, you can customize the item types to suit
+add as many new types as you wish. Like terrain types, you can customize the item types to suit
your scenario. Click on Edit Item Types to bring up a list of items, and click on an item
type to bring up the item editing window. This window has these options:
@@ -39,7 +39,7 @@ reduces damage in combat. The higher the number, the greater the reduction.
items (like potions) or missiles.
Type Flag (Advanced): When a character gets several items of the same type
(like darts or arrows), they will all be combined into one item. This happens when the
-items have the same type flag. You can have items have the same type flag, and thus be
+items have the same type flag. You can have items that have the same type flag, and thus be
combined. Only give an item a type flag greater than 100 ... smaller type flags are
reserved for the preset items.
Value: The value of the item in gold.
@@ -49,7 +49,7 @@ to see if the party has a special item. Set an item's special class here (0 for
class).
For example, an item Boat Ticket can have special class 1, and a special node
which checks if the party has a ticket can check for special class 1. Note that items with
-a non-zero special class are taken away from the party when they leave the
+a non-zero special class have the special class set to 0 when the party leaves the
scenario.
Weapon key skill: If the item is a weapon of any kind (but not ammunition such as
arrows), there will be a place to enter in the key skill for the weapon. You can click the
@@ -79,7 +79,7 @@ their index in a list, anything that changes the index of an item is something t
so when an item (other than the last in the list) is deleted, the editor just sets its
type to No Item.
1-Hand weapon
-
2-Hand weapn
+
2-Hand weapon
Weapons are wielded in the hand. The item level indicates the amount of damage the
weapon does (specifically, the size of the die). They cannot have reagent abilities.
Gold
@@ -165,7 +165,7 @@ alchemical recipes.
button on the PC inventory screen. Otherwise, the ability has no effect. Examples are a
wand that shoots fireballs or a healing potion.
Usable abilities are always linked to the item's charges. Whenever an item with a usable
-ability is actually used, the items amount of charges goes down by 1. When the items
+ability is actually used, the item's amount of charges goes down by 1. When the item's
charge level goes down to 0, the item disappears. An item with a usable ability must have
at least 1 charge.
The cash value of an item with a usable ability is calculated differently from normal
@@ -207,7 +207,7 @@ ability of this type must have charges, and must be of variety Non-use Object.
There are a wide variety of special abilities. The abilities (and the meaning of the
-extra fields) are listed in the one of the Appendices.
+extra fields) are listed in the Appendix.
To select an ability, press one of the four buttons to the upper right. Each button
brings up a menu with one of the four classes of special item. The item's ability strength
can be entered in the text area just below. The
diff --git a/doc/editor/Monsters.html b/doc/editor/Monsters.html
index 931fbb7e3..ca9f34be9 100644
--- a/doc/editor/Monsters.html
+++ b/doc/editor/Monsters.html
@@ -33,9 +33,9 @@ this number.
when it hits. For example, if a blow does eight dice of damage, each of which has 11
sides, the program generates 8 random numbers from 1 to 11, adds them up, and does that
much damage. A monster can have up to 3 different attacks.
+
Attack Types: Press Choose to select an attack type (e.g. bite, claw, etc.)
Monster Type: Press Choose to pick a monster type (e.g. human, insect, demon,
etc.).
-
Attack 1 Types: Press Choose to select an attack type (e.g. bite, claw, etc.)
Treasure: Determines how much treasure the monster leaves when killed (0 - none,
to 4 - lots). Don't have common creatures leave treasure of type 3 or 4.
Default Talking Picture: Press Choose to select the default picture the player
@@ -57,8 +57,8 @@ the Abilities button.
the parameters of an existing special ability. If there are more than four special
abilities, use the arrow buttons to navigate through them. Abilities are listed in the
Monster Abilities section, later in this chapter. They are also covered in more detail in
-the appendices.
-
Summon Type - Determines whether the monster can be summoned by the mages
+the Appendix.
+
Summon Type - Determines whether the monster can be summoned by the mage's
summoning spells. Type 1 monsters are easy to summon, while Type 3 monsters require much
more powerful spells. If No Summon is selected, spells never summon the monster.
Item To Drop When Killed, Chance of Dropping - The number of an item to place
@@ -70,6 +70,7 @@ than 100.
Invisible - Monster can't be seen. You can select a graphic for this creature,
but it's only seen when editing the town, not playing the scenario.
Mindless - Creature is immune to fear.
+
Amorphous - Creature is immune to assassination.
Invulnerable - Creature practically immune to damage.
Guard - Creature is a guard. When the party commits a crime and makes the town
hostile, it becomes stronger and will immediately seek out the party to kill them (even if
@@ -153,7 +154,7 @@ categories. See the appendix for details on how to do this.
Some Monsters Should be Left Alone
-
Certain monster types are summoned by mage spells, and should be left alone. These
+
Certain monster types are summoned by mage or priest spells, and should be left alone. These
monster types are Guardian, Demon, Snake, Asp, Mung Rat, Shade, and Deva. You can easily
tell that you're editing one of these monsters by looking at the non-editable "Summoned
By" field at the bottom of the Edit Monster Type dialog.
diff --git a/doc/editor/Specials.html b/doc/editor/Specials.html
index 59b24147e..1e42eee6e 100644
--- a/doc/editor/Specials.html
+++ b/doc/editor/Specials.html
@@ -208,7 +208,9 @@ different classes of special encounters. These classes, when they can be used (t
have no effect outdoors, for example), and what they do are described in the Appendix on
special nodes.
Stuff Done flags - Many special nodes either change or examine a Stuff Done
-flag. Put the two parts of the required stuff done flag in these two text areas.
+flag. Put the two parts of the required stuff done flag in these two text areas.
+Sometimes, when a node uses these fields for a different purpose, a small button
+will appear above the field. Click this button to choose the value from a list.
Message 1-3, Pict, Pict type - Some special nodes display a piece of text on the
screen. Other special nodes display a dialog box, with text in the middle and a picture in
the upper left corner. The numbers for these messages and the number of the picture to
diff --git a/doc/editor/Terrain.html b/doc/editor/Terrain.html
index 2dd413549..33dda8336 100644
--- a/doc/editor/Terrain.html
+++ b/doc/editor/Terrain.html
@@ -29,9 +29,9 @@ means is described below:
Picture: Simply, what the terrain looks like. To select a picture, click the
-Pick Picture button (if you dont want the terrain graphic to be animated) or the Animated
+Pick Picture button (if you don't want the terrain graphic to be animated) or the Animated
button (if you do). If you want to use a customized terrain graphic, see the chapter
-Customized Graphics.
Name: The name of the terrain, which is given when the party looks at it. This
can be at most 30 characters long.
Blockage: Whether the party can see through and walk through it. Click on the
@@ -39,7 +39,7 @@ button by the desired blockage. The blockage values are:
Clear - Party can see through and walk through terrain unobstructed. (Example: floor,
grass)
-
Walk through, opaque - Party can walk through this terrain, but cant see through it.
+
Walk through, opaque - Party can walk through this terrain, but can't see through it.
(Example: secret passage)
Clear, special - Party can see through and walk through terrain unobstructed, but
monsters will not walk through it. (Example: Special encounter, lava)
@@ -72,7 +72,8 @@ to give all your basic walls the key w).
casts light, and how far out that light extends. For example, a torch has a light radius
of 4, so all spots in town within 4 spaces of a torch space are always lit.
Transform to what - This field is used in conjunction with certain types of
-special nodes (see Special Encounters). If this is a terrain type that you often want to
+special nodes (see Special Encounters).
+If this is a terrain type that you often want to
change to something else (such as a closed portcullis, which you may often want to change
to an open portcullis), enter the number of the terrain type to change it to here. Then,
to change the terrain type, use a Transform Terrain special node.
@@ -96,7 +97,7 @@ conform to, while the Trim Terrain field should be set to the Ground Type of the
terrain. For example, hill trims transition between hills (with ground type 4) and grass
(with ground type 1), so their Trim Terrain is set to 1.
Frills - Terrains with this trim type will have small frills drawn around their
-borders to match the the adjacent terrains.
+borders to match the adjacent terrains.
Road - Terrains with this trim type will be connected with road segments. In
addition, if there are two terrains with this trim type separated by a single terrain with
an appropriate cardinal direction trim type, the road segment will be extended across the
diff --git a/doc/editor/appendix/Items.html b/doc/editor/appendix/Items.html
index 59b3806a2..0f7138740 100644
--- a/doc/editor/appendix/Items.html
+++ b/doc/editor/appendix/Items.html
@@ -21,17 +21,17 @@ for alchemical recipes.
Usable abilities: Usable item abilities are only activated by pressing the
-items use button on the PC inventory screen. Otherwise, the ability has no effect.
+item's use button on the PC inventory screen. Otherwise, the ability has no effect.
Examples are a wand that shoots fireballs or a healing potion.
-
Usable abilities are always linked to the items charges. Whenever an item with a usable
-ability is actually used, the items amount of charges goes down by 1. When the items
+
Usable abilities are always linked to the item's charges. Whenever an item with a usable
+ability is actually used, the item's amount of charges goes down by 1. When the item's
charge level goes down to 0, the item disappears. An item with a usable ability must have
at least 1 charge.
The cash value of an item with a usable ability is calculated differently from normal
-items. The items actual cost is its value multiplied by the number of its charges.
+items. The item's actual cost is its value multiplied by the number of its charges.
(Example: Suppose a Potion of Healing has a value of 100 and 2 charges. This potion would
cost 200 gold and sell for half that.)
-
Inherent Abilities:Inherent abilities are abilities that are always present and
+
Inherent Abilities: Inherent abilities are abilities that are always present and
are activated automatically, as opposed to being activated by pressing the Use button on
the PC Inventory screen. Examples are a shield with fire protection (which is activated
automatically when the character takes fire damage) or comfrey root (whose ability it that
@@ -39,7 +39,7 @@ it can be used as an alchemical ingredient, and which is used automatically when
tries to make a potion with it).
Some inherent abilities have charges (such as alchemical ingredients). When used, the
amount of charges goes down by one. When there are no charges left, the item disappears.
-The name of inherent ability types that require charges have a (c) after them.The value of
+The name of inherent ability types that require charges have a (c) after them. The value of
these items is calculated the same way as for Usable abilities.
@@ -69,8 +69,8 @@ ability of this type must have charges, and must be of variety Non-use Object.
As mentioned before, each item type has two acompanying extra data fields as well as
the Magic Item Adjust setting. For each ability, these two fields have different ranges
-and different affects (the first field is usually Ability Strength), and their values will
-modify the affects of the item abilities in different ways. What each ability does and how
+and different effects (the first field is usually Ability Strength), and their values will
+modify the effects of the item abilities in different ways. What each ability does and how
the extra data fields and Magic Item Adjust affect it are described below.
@@ -138,6 +138,14 @@ Strength. (So, an ability strength of 1 has no effect.)
Drains morale of target.
Ability 14 - Weapon Call Special
The weapon calls a special node every time it hits.
+
Ability 15 - HP Damage
+
The weapon's damage is multiplied by the wielder's health ratio, meaning it does less damage as they lose health and only 1 damage when they are on the verge of death.
+
Ability 16 - Inverse HP Damage
+
The weapon's damage is multiplied by the inverse of the wielder's health ratio, meaning it does more damage as they lose health and only 1 damage when they are at full health.
+
Ability 17 - SP Damage
+
The weapon's damage is multiplied by the wielder's energy ratio, meaning it does less damage as they lose energy and only 1 damage when they are completely depleted.
+
Ability 18 - Inverse SP Damage
+
The weapon's damage is multiplied by the inverse of the wielder's energy ratio, meaning it does more damage as they lose energy and only 1 damage when they are at full energy.
General Abilities (Inherent)
@@ -185,7 +193,7 @@ cannot boost max HP or max SP. The Ability Strength is how many extra levels the
gets. This cannot raise the effective level above 20. It can however raise the effective
level of Mage or Priest Spells above 7, though there's not much use in doing so - the only
thing it affects is your chance of breaking a forcecage. If applied to one of the three
-basic stats (Strength, Dexterity, and Intelligence), this ability increases your bonus to
+basic stats (Strength, Dexterity, and Intelligence), this ability increases your bonus
to that stat by one, but the bonuses are otherwise still based on your actual level in the
stat. The Ability Strength is still relevant, however, because a few circumstances use the
modified skill level instead of the stat bonus. These circumstances are: Amount you can carry
@@ -217,14 +225,14 @@ effect.
Calls a special node when the wearer is hit in melee combat or by a non-magical
missile.
Ability 48 - Life Saving (c)
-
When the wielder takes a death blow, he/she survives and is healed, and the item loses
+
When the wielder takes a death blow, they survive and are healed, and the item loses
a charge. This item must be given charges.
-
Ability 49 - Prot. from petrify
+
Ability 49 - Protect from petrify
Reduces chance of being petrified.
Ability 50 - Regenerate
Heals wielder occasionally.
Ability 51 - Poison Augment
-
Wielder's weapon poison more effective. The wielder must poison their weapon first for
+
Wielder's weapon poison is more effective. The wielder must poison their weapon first for
this ability to have any effect.
Ability 52 - Radiant
When worn, this item sometimes increases the light level around you. This can even
@@ -248,6 +256,8 @@ Strength.
it is.
Ability 59 - Drains Missiles
Drains missiles twice as fast. This is typically given to bows and crossbows.
+
Ability 60 - Drop Call Special
+
Calls a special node when dropped on the ground.
Usable Abilities
@@ -278,7 +288,7 @@ of acid (which means the acid lasts about 5 turns).
Ability 70 - Poison Weapon
This item is a weapon poison that can be applied to the user's weapon. The Magic Use
Type is ignored, and the Ability Strength is the strength of the poison. When used, the
-user has a chance (based on the Poison skill) of poisoning him/herself.
+user has a chance (based on the Poison skill) of poisoning themself.
Ability 71 - Affect Status
Affects the level of a status effect on the user. Note that some pairs of status
effects are considered opposites, so that curing one is the same as afflicting its
@@ -364,7 +374,7 @@ are the extra data fields..
Ability 85 - Book
The item is a book which gives some textual information when used. A book does not
consume any charges when used. To set the contents of the book, edit the item description.
-At the end of the description, add three vertical bars (
|
) followed by the
+At the end of the description, add three vertical bars (|) followed by the
content of the book. If you want, you can add another three vertical bars followed by a
second string. Note that there is limited space for the strings in the dialog.
@@ -372,11 +382,11 @@ second string. Note that there is limited space for the strings in the dialog.
Reagents (Inherent)
To perform alchemy or cast certain spells, the alchemist/caster must have items with
-certain abilities in his/her inventory. For example, to make a Weak Poison potion, the
+certain abilities in their inventory. For example, to make a Weak Poison potion, the
maker must have an item with the Holly ability, or to cast a Magic Map spell, the caster
must have an item with the Sapphire ability.
These items must have charges, representing the number of times they can be used. The
-Magic Item Adjust and Ability Strength fields are not used (except for Lockpicks).
+Magic Item Adjust and Ability Strength fields are not used.
The name of each ability represents the ingredient/spell component that the item with
that ability can substitute for. For example, a gem with the ability Smoky Crystal can be
used to cast Mindduel.
You can edit the text messages for the scenario, a town, or an outdoor section. This
-gives you the chance to directly edit the adventure text, without going through the
-editing windows. You can access the text messages by selecting the Edit Text options from
-the Town, Outdoors, or Scenario menus. Click on a text message to edit it. Remember each
-message can be at most 256 characters long.
-
Each list is, as always, numbered starting with 0.
-
-
The Outdoor Text Messages
-
-
-
0 - Name of Scenario
-
1,2 - Descriptive text and credits (each max. 60 characters long)
-
3 - Contact information
-
4-9 - Intro message (when scenario is started)
-
10-59 - Currently unused.
-
60-159 - Name and description of 50 special items (60 is name of special item 0, 61 is
-description of special item 0, 62 is name of special item 1, and so on)
-
160-259 - The 100 text messages for the scenario special nodes. The messages that begin
-with an * are unused special messages.
-
-
-
The Town Text Messages
-
-
-
0 - Name of Town
-
1-16 - Descriptions of area rectangles
-
17-19 - Private comments on the town (not used in scenario)
-
20-119 - The 100 text messages for the town section special nodes.
-
120-134 - The text for the area's signs (string 120 is for sign 0).
-
-
-
The Outdoor Text Messages
-
-
-
0 - Name of Area
-
1-8 - Descriptions of area rectangles
-
9 - A private comment on the section (not used in scenario)
-
10-99 - The 90 text messages for the outdoor section special nodes.
-
100-107 - The text for the area's signs (string 100 is for sign 0).
-
-
-
-
-
diff --git a/doc/editor/appendix/Monsters.html b/doc/editor/appendix/Monsters.html
index ea6a9a1f4..fca7b18f3 100644
--- a/doc/editor/appendix/Monsters.html
+++ b/doc/editor/appendix/Monsters.html
@@ -36,7 +36,7 @@ rather than Cancel. Clicking Cancel will cause the ability to be added with defa
Monster - This is here to remind you what the monster is you're editing an
-ability for.
Display name - Shows the ability's name as it will be shown in-game, for
example when casting Scry Monster.
Ability Type - The type of ability. This was set when you added the ability and
diff --git a/doc/editor/appendix/Specials.html b/doc/editor/appendix/Specials.html
index ea33fbccc..67e01cf27 100644
--- a/doc/editor/appendix/Specials.html
+++ b/doc/editor/appendix/Specials.html
@@ -30,16 +30,17 @@ fields do.
General Use Specials
This is the class of special encounters which can be called at practically any time.
-Most of them can always be called. A few can't - these are noted in the encounter
+Most of them can always be called. A few can't be called in certain circumstances -
+these are noted in the encounter
description.
General notes
Stuff done 1, Stuff done 2:
Some of these nodes change a Stuff Done flag. A
Stuff Done flag is described by two values: Stuff done 1 and Stuff done 2. The legal range
-of the first flag is from 0 to 299, and the range for the second flag is 0 to 9. If a
+of the first flag is from 0 to 349, and the range for the second flag is 0 to 49. If a
value is given outside the legal range, the special node does nothing and the Jump To node
-is called next (though often the editor will give you an error when you try to do
+is called next (though usually the editor will give you an error when you try to do
this).
Jump To:
After a special node is called and has its effect, this field
specifies the next node to be called. If this value is negative, the special encounter
@@ -64,7 +65,7 @@ Jump To node.
Extra 1a:
This is the value to change it to.
Example:
If Stuff done 1 is set to 90, Stuff done 2 is set to 4, and Extra 1a
is set to 8, when this node is called Stuff Done (90,4) becomes 8. If, instead, Stuff done
-2 is set to 40, this value is out of range (0 ... 9) and you will get an error.
+2 is set to 60, this value is out of range (0 ... 49) and you will get an error.
Type 2: Increment Flag
This node increases (or decreases) a Stuff Done flag by
a specified amount.
@@ -89,7 +90,7 @@ town.
Mess1:
This message is the name of the store the party has found.
Extra 1a:
The number of the shop.
Extra 1b:
The item cost adjuster, a number from 0 (very cheap) to 6 (very
-expensive). See chapter 11 (Dialogue) for the complete list of cost adjustments.
A text message is displayed on one (or two)
line(s) of the text area (in the lower right hand corner). Don't make the displayed
@@ -201,7 +202,7 @@ usually won't even be called if the space is impassable.
Extra 1a:
This is the number of ticks to set the timer forward. A day is 3000
ticks. The maximum this can be set to is 30000.
-
Type 13: Start Global Timer
One of the parties special encounter timers is
+
Type 13: Start Global Timer
One of the party's special encounter timers is
activated. Each move taken, the timer goes down by 1. When it runs out, a scenario special
node is called (even if the party enters or leaves town). Also see Start Town Timer, under
Town Special Nodes.
@@ -213,9 +214,13 @@ at No Special, nothing happens.
Type 14: Play a sound
Plays one of the game's sounds.
-
Extra1a:
Which sound to play. For a list of sounds, read Appendix A.
+
Extra 1a:
Which sound to play. For a list of sounds, read
+Appendix A. You can also click Choose to select
+the sound from a list, which allows you to hear the sounds while you choose.
+
Extra 1b:
Whether to wait while the sound plays. If 0, the game will
+pause until the sound has finished playing. If 1, the game will not wait.
-
Type 15: Change Horse Possession
Makes a horse the parties property (or not).
+
Type 15: Change Horse Possession
Makes a horse the party's property (or not).
Mess1, Mess2:
Standard usage.
Extra1a:
The horse to change ownership of. (Range 0 ... 29)
@@ -243,7 +248,7 @@ treasure map. When the map is read, call this special. Set Extra 1a to 14 and Ex
1.
Type 18: Major Event Has Occurred
A major event is recorded as having
-occurred. See Passage of Time in the chapter on Special Encounters for a more detailed
+occurred. See Passage of Time in the chapter on Special Encounters for a more detailed
explanation.
Mess1, Mess2:
Standard usage.
@@ -263,14 +268,14 @@ the party's item slots are full). If No Special is given, the Jump To special is
usual.
Uses:
If you want the party to get an item after winning a combat outdoors,
use a Forced Give. This makes sure that if it is at all possible, they get it.
-
Uses 2:
Use this is the party is given an item during a talking special
+
Uses 2:
Use this if the party is given an item during a talking special
encounter. If the party inventory is full, jump to a special telling them that they can't
carry the item and to come back later, and then end the special. This enables you to keep
from setting a Stuff Done flag saying they got the item, when, in fact, they
didn't.
Type 20: Buy Items of Type
All items that belong to the given special class
-(described in the chapter on items) are taken from the party. For each item taken, the
+(described in the chapter on items) are taken from the party. For each item taken, the
party gets some gold. This can be accompanied by one or two messages, if you wish.
Mess1, Mess2:
Standard usage. Note that the messages are only displayed if
@@ -279,7 +284,7 @@ some items are actually taken away.
Extra 1b:
The special to jump to if no items are taken. If No Special is
specified, the Jump To special is used as usual.
Extra 2a:
The amount of gold to pay for each item (Range 0 ... 250)
-
Uses:
This is a how you give a bounty for items. If you want someone to give
+
Uses:
This is how you give a bounty for items. If you want someone to give
the party 10 gold for each unicorn horn, give unicorn horns a special class of, say, 30,
and call this special node with Extra 1a set to 30 and Extra 2a set to 10.
@@ -294,7 +299,7 @@ scenario specials once, and then just call it from the many places it's used.Type 22: Set Many Flags
This node sets 50 Stuff Done flags to a desired
value.
-
Stuff Done 1:
A number from 0 to 299. When this node is called, (Stuff Done 1,
+
Stuff Done 1:
A number from 0 to 349. When this node is called, (Stuff Done 1,
0), (Stuff Done 1, 1), ... (Stuff Done 1, 49) are all set to Extra 1a.
Extra 1a:
This is the value to change it to.
Example:
Suppose Stuff Done flag (200,4) is 35. This node is called with Stuff
@@ -313,8 +318,9 @@ is 8, then the value of Stuff Done flag (12,5) becomes the same as Stuff Done fl
Mess1:
The number of a message containing a title string to show in the
dialog.
-
Extra 1a:
The number of the graphics sheet to show. See the chapter on custom
-graphics for details on what a graphics sheet is and how to get the game to see it. This
+
Extra 1a:
The number of the graphics sheet to show. See the chapter on
+custom graphics
+for details on what a graphics sheet is and how to get the game to see it. This
special node displays the entire sheet in a dialog, so the sheet can be whatever size you
want.
@@ -354,7 +360,7 @@ to be multiple scenarios.)
Stuff Done 1, Stuff Done 2:
The flag to store or change.
Mess1:
If set to a positive number, this is the number of a string used to
look up the campaign flag. If left at -1, the name of your scenario is used.
-
Extra 1a, Extra 1b
The campaign flag to fetch or change. Each of thes must be
+
Extra 1a, Extra 1b
The campaign flag to fetch or change. Each of these must be
in the range 0..24.
Extra 2a:
Set this to 0 to set the Campaign Flag equal to the value of the
Stuff Done Flag. Set it to 1 to instead set the Stuff Done flag equal to the value of the
@@ -402,7 +408,7 @@ these two fields.
by. Otherwise, the value to divide by is the value of the Stuff Done Flag specified by
these two fields.
Extra 1c, Extra 2c
This is the Stuff Done Flag to store the remainder of the
-division in. You can leave these are -1 if you don't care about the remainder. Similarly,
+division in. You can leave these at -1 if you don't care about the remainder. Similarly,
you can leave Stuff Done 1 and 2 at -1 if you only care about the remainder.
Type 33: Exponentiation
Raises a number to a power and stores the result in a
@@ -516,7 +522,8 @@ the scenario's quests or jobs.
Marks the quest as not started. This might be useful if the quest is on a job board
and you want it to be repeatable. Note however that marking a quest available does not
-grant automatic rewards.
+grant automatic rewards. If you want the rewards you would need to first mark
+the quest as complete.
Marks the quest as started. If it wasn't already started, the game automatically fills
in the quest's start day, and if Extra 2a is non-negative, the quest is considered to have
come from the job board with that number.
@@ -551,8 +558,8 @@ items.
Done 1 and Stuff Done 2 fields. If you do, when the node is called, if that flag has a
value of 250, the node does nothing and the special ends immediately. If the flag is not
250, the node has the desired effect, and then that Stuff Done flag is set to 250 (so this
-node has no effect is called again).
-
These nodes have one more special property. If you have a have a special encounter
+node has no effect if called again).
+
These nodes have one more special property. If you have a special encounter
marked by a white dot, the first node called from that special encounter is a One-Shot
Special, and the specified Stuff Done flag in that node is 250, then the white dot
disappears. Thus, specials that don't do anything anymore aren't marked by a special
@@ -562,7 +569,7 @@ dot.
Stuff done 1, Stuff done 2:
All of these nodes change a Stuff Done flag. A
Stuff Done flag is described by two values: Stuff done 1 and Stuff done 2. The legal range
-of the first flag is from 0 to 299, and the range for the second flag is 0 to 9. You can
+of the first flag is from 0 to 349, and the range for the second flag is 0 to 49. You can
give a value outside the legal range (such as -1 for Stuff Done 1). If you do this, the
special node does its job normally, and if this node is called again, it will do it again.
This is sometimes a good idea.
@@ -589,13 +596,13 @@ the Choose button to select an item.
tell them their inventory is full). If No Special is given, the Jump To special is called
normally.
-
Type 51: Give Special Item
Gives the party one of the scenarios special items.
+
Type 51: Give Special Item
Gives the party one of the scenario's special items.
This can be accompanied by one or two messages, if you wish.
Stuff done 1, Stuff done 2:
As usual.
Mess1, Mess2:
Standard usage.
Extra 1a:
The number of the special item to give. (Range 0 ... 49)
-
Extra 1b:
If 0 (the default), the special item is given. Otherwise, its taken
+
Extra 1b:
If 0 (the default), the special item is given. Otherwise, it's taken
away.
Type 52: One-Time Do Nothing
If the Stuff Done flag is set to 250, this node
@@ -622,7 +629,7 @@ a dialog box with up to six text messages and a dialog picture (which you choose
upper left. The lower right hand corner can have 1 to 3 buttons. The player must press a
button, at which point another special node will be called. You choose a special node to
call for each button.
-The first button is always labeled OK if its the only button or Leave if there are other
+The first button is always labeled OK if it's the only button or Leave if there are other
buttons. If the first button is pressed, the Jump To special is called normally. Otherwise
the special node in Extra 1b or 2b is called.
@@ -637,22 +644,22 @@ is 1, this button appears. Otherwise, it doesn't.
the Choose button.
Pictype:
This specifies the type of picture to display. To select a picture
type, press the Choose button.
-
Extra 1a:
Determines what the second button is labeled. If left -1, there is
+
Extra 1a:
Determines what the second button is labeled. If left at -1, there is
no second button. Press the Choose button to select a label.
-
Extra 1b:
What special node to call is button 2 is pressed.
-
Extra 2a:
Determines what the third button is labeled. If left -1, there is no
+
Extra 1b:
What special node to call if button 2 is pressed.
+
Extra 2a:
Determines what the third button is labeled. If left at -1, there is no
third button. Press the Choose button to select a label.
-
Extra 2b:
What special node to call is button 3 is pressed.
+
Extra 2b:
What special node to call if button 3 is pressed.
Example:
If Mess 1 is 30, and Mess 2 is 4, the dialog box that comes up
contains messages 30 through 33.
Note:
A dialog box can only contain consecutive text messages. You can't bring
up a dialog box which contains message 24, followed by messages 1, 20, and 64.
-
Example:
Suppose to want a dialog box to come up displaying messages 37
+
Example:
Suppose you want a dialog box to come up displaying messages 37
through 40.
Uses:
This is one special node where you may often want to leave Stuff Done 1
-at -1 (so this node displays the dialog box every time its called). For example, if you
+at -1 (so this node displays the dialog box every time it's called). For example, if you
want the text of a book to come up when the party looks at a certain bookshelf, you
-probably want the same text to keep coming up when the look at the bookshelf later
+probably want the same text to keep coming up when they look at the bookshelf later
on.
Type 58: Give Item Dialog
Displays a dialog box with up to six text
@@ -666,7 +673,7 @@ ends immediately and the Stuff Done flag is not set.
Mess 1:
The number of the first message to be displayed in the dialog box. The
six messages starting with this message will be displayed in the dialog box (though the
strings can, of course, be blank). Press the create/edit button to edit the text.
-
Mess 3:
The number of special item to give (0 .. 49). If this is left at -1,
+
Mess 3:
The number of special item to give. If this is left at -1,
no special item is given.
Pict:
This is the number of the picture to display. To select a picture, press
the Choose button.
@@ -690,7 +697,7 @@ open space near the party. This can be accompanied by one or two messages, if yo
(Range 0 ... 3)
Type 62: One-Time Place Town Encounter
Activates all monsters in town in the
-specified Special Encounter Group (see the section on monsters in town for more
+specified Special Encounter Group (see the section on monsters in town for more
information). If no monsters in that group are left, the encounter has no effect. This can
be accompanied by one or two messages, if you wish.
@@ -709,17 +716,29 @@ in town or combat (no traps outdoors).
Mess1, Mess2:
Standard usage. You can provide customized text saying the party
sees what may be a trap. If both of these fields are left at -1, the game displays a
generic You Found A Trap message.
-
Extra 1a:
The type of trap: 0 - randomly selected, 1 - damage 1 character, 2 -
-poison 1 character, 3 - poison party, 4 - damage party, 5 - paralyze character, 6 - no
-trap after all, 7 - drain experience, 8 - make town hostile, 9 - fire damage 1 character,
-10 - dumbfound 1 character, 11 - disease 1 character, 12 - disease party, 13 - custom
+
Extra 1a:
The type of trap:
+
+
randomly selected
+
damage 1 character
+
poison 1 character
+
poison party
+
damage party
+
paralyze character
+
no trap after all
+
drain experience
+
make town hostile
+
fire damage 1 character
+
dumbfound 1 character
+
disease 1 character
+
disease party
+
custom
Extra 1b:
The severity of the trap. The higher the number, the deadlier the
trap. A severity of three all but guarantees lethality. (Range 0 ... 3)
Extra 2a:
The disarming penalty. The higher the number, the harder to disarm.
(Range 0 ... 100)
Extra 2b:
If trap type is 13 (custom), this scenario special node is called
when the PC fails to disarm the trap. It is never called if the PC successfully disarms
-the trap.
+the trap. The JumpTo node will still be called after calling this node.
Note:
If this special node is placed on a container (like a chest), the party
must disarm the trap to be able to take any of the items in the chest.
@@ -741,8 +760,8 @@ spell, or as a result of using a space that happened to have a monster (or PC) o
target is considered to be selected.
Finally, the last few nodes in this section (like Party Status, Affect Gold, etc) only
affect the whole party; they ignore the currently selected target.
-
Note that when one of these specials does something bad (e.g. diseases or poisons) a
-character, all resistances (e.g. protection from poison rings) apply.
+
Note that when one of these specials does something bad to a character
+(e.g. disease or poison), all resistances (e.g. protection from poison rings) apply.
General notes:
Stuff done 1, Stuff done 2:
None of these special node types use these
@@ -750,8 +769,8 @@ fields.
Mess 1, Mess 2:
All of these special node types (except Select a PC) can
display one or two messages. If you don't want a message displayed, just leave these at
-1.
-
Extra 1b:
This field usually affects whether the node helps of hurts the
-party. In general, if its 0 (the default) it helps. Otherwise, it hurts.
+
Extra 1b:
This field usually affects whether the node helps or hurts the
+party. In general, if it's 0 (the default) it helps. Otherwise, it hurts.
Extra 2b:
When these nodes are called during combat, if this is 0, the node
only affects the active PC. Otherwise, it affects the whole party. (Exception to this -
the Do Damage node type)
@@ -794,9 +813,6 @@ Select a PC node, followed by an Affect Statistic node.
It has no effect when called during a talking special. When called during combat, and a
Select a PC node has not been called, it only affects the active character.
-
Pict:
If this is 0, this node damages the whole party. If this is 1, and the
-node is called during combat, only the current pc is damaged. Otherwise, the whole party
-is damaged.
Extra 1a:
This is the number of dice of damage that is rolled. (Maximum:
256)
Extra 1b:
This is the number of sides of the dice that are rolled. For
@@ -805,7 +821,7 @@ example, if Extra 1a is 5 and Extra 2b is 8, the game generates 5 random numbers
Extra 2a:
This is the amount of extra damage to add. If this is 100, for
example, 100 extra points of damage are inflicted.
Extra 2b:
This is the type of damage inflicted (0 - weapon, 1 - fire, 2 -
-poison, 3 - general magic, 4 - unblockable, 5 - cold, 6 - demon,7 - undead)
If non-zero, this specifies which sound to play along with the
damage. Leave it at 0 to use the default sound.
@@ -814,13 +830,14 @@ maximum of 250 or a minimum of 0. This special cannot kill anybody, only reduce
health to 0.
Extra 1a:
The amount to raise/lower health.
-
Extra 1b:
If 0, health is raised. Otherwise, its lowered.
+
Extra 1b:
If 0, health is raised. Otherwise, it's lowered.
Type 83: Affect Spell Points
Increases/decreases spell points. Spell points
can be changed to a maximum of 100 or a minimum of 0.
Extra 1a:
The amount to raise/lower spell points.
-
Extra 1b:
If 0, spell points are raised. Otherwise, theyre lowered.
+
Extra 1b:
If 0, spell points are raised. Otherwise, they're lowered.
+
Extra 1c:
Only used when lowering spell points. If 0, the spell points are lowered by the exact amount specified. If 1, targets with Mage Spells or Priest Spells are allowed to partially resist the effect.
Type 84: Affect Experience
Adds/drains experience. If the target is a monster,
this has no effect.
@@ -864,7 +881,7 @@ Note, if harming the party, all resistances apply. You don't need to worry about
the chosen status effect is inherently helpful or harmful - the game knows this, so just
set Extra 1b to 0 if you want to help the party or 1 if you want to harm them.
-
Extra 1a:
The amount to change. (Usually ranges is 0 ... 8; Martyr's Shield is
+
Extra 1a:
The amount to change. (Usual range is 0 ... 8; Martyr's Shield is
0 ... 10, and paralysis is 0 ... 5000)
Extra 1b:
If 0, helps. Otherwise, harms.
Extra 1c:
Which status effect. Press the Choose button to select one.
@@ -903,7 +920,7 @@ change skill points or amount of experience.
monster, this has no effect. Decreasing morale is the same as a Fear spell.
Extra 1a:
The amount to increase/decrease morale.
-
Extra 1b: If 0, increases. Otherwise, decreases.
+
Extra 1b:
If 0, increases. Otherwise, decreases.
Type 93: Affect Soul Crystal
Records the currently targeted monster in the
party's soul crystal, or erases it if there is already a monster of the same kind recorded.
@@ -936,7 +953,7 @@ default. Leave at -1 to use the default. If the item doesn't normally have charg
is ignored. (But keep in mind that certain enchantments give charges.)
Extra 2a:
You can force whether the item is identified using this field. If
left at -1, the default setting in the item properties is used. Set to 0 to force it to be
-unidentified, or 1 to force it to be unidentified. If you set it to 2, it will be fully
+unidentified, or 1 to force it to be identified. If you set it to 2, it will be fully
identified, even revealing the concealed ability (if any).
Extra 2b:
You can force whether the item is cursed using this field. Leave at
-1 to use the default setting, or set to 0 to force uncursed, 1 to force cursed.
@@ -980,7 +997,7 @@ statistics. If the target is not a monster, this has no effect.
Mage Spells, etc.)
Pict:
This is a number from 1 to 100, which represents the percentage chance
-the statistic is affected. If 100 (the default) its always changes. If 0, it never
+the statistic is affected. If 100 (the default) it's always changed. If 0, it never
is.
Extra 1a:
The amount to increase/decrease (0 .. 10).
Extra 1b:
If 0, increase. If 1, decrease.
@@ -1022,7 +1039,7 @@ Appendices.
Extra 1a:
The recipe to give (Range 0 ... 19).
Extra 1b:
If 0, give recipe. If 1, take away.
-
Type 104:
Affect Party Status
Adds or removes a status effect that
+
Type 104: Affect Party Status
Adds or removes a status effect that
affects the whole party, such as Stealth or Flight.
Extra 1a:
The duration (Range 0 ... 250).
@@ -1095,7 +1112,7 @@ Stuff Done flag. If the Stuff Done flag is greater than the value of Extra 1a, t
in Extra 1b is called. Otherwise, if the Stuff Done flag is less than the value in Extra
2a, the special in Extra 2b is called. If neither case applies, the Jump To special is
called.
-
The default values for Extra 1a is -1. If it is left at -1, it isn't checked, and the
+
The default value for Extra 1a is -1. If it is left at -1, it isn't checked, and the
special in Extra 1b won't be called. The same is true for Extra 2a.
Stuff done 1, Stuff done 2:
Specifies the Stuff Done flag to
@@ -1268,7 +1285,7 @@ Extra 1b is called.
Jump To:
Otherwise, this special is called.
Type 148: If Fields/Objects?
Result depends on the presence of fields,
-barriers, or similar transient objects exist in the current town.
+barriers, or similar transient objects existing in the current town.
Extra 1a, Extra 1b, Extra 2a, Extra 2b:
The rectangle to check. This works
just like a Rectangle special; see that section for details.
@@ -1309,7 +1326,7 @@ will be called.
particular species.
Extra 1a:
The species to check for.
-
Extra 1b:
This special is called if there is the number of living PCs of the
+
Extra 1b:
This special is called if the number of living PCs of the
specified species compares favourably with the required number in Extra 2a.
Extra 2a:
The number of PCs required of the specified species.
Extra 2b:
Specifies how to compare the actual number with the required number.
@@ -1324,14 +1341,13 @@ this is undesirable, check the party size first.
trait. This works just like the above node, but checks for a trait instead of a species.
Extra 1a:
The trait to check for.
-
Extra 1b:
This special is called if there is the number of living PCs with the
+
Extra 1b:
This special is called if the number of living PCs with the
specified trait compares favourably with the required number in Extra 2a.
Extra 2a, Extra 2b
As in the above node.
Jump To:
Otherwise, this special is called.
Uses:
This is often used to check the Cave Lore or Woodsman traits.
-
Type 153: Has Enough of Statistic?
Result depends on whether the sum of the
-parties Mage Lore skill is high enough.
+
Type 153: Has Enough of Statistic?
Result depends on whether a particular skill in the party is high enough.
Extra 1a:
If the skill is at least this amount, the special in Extra 1b is
called.
@@ -1344,26 +1360,27 @@ maximum level.
Jump To:
Otherwise, this special is called.
Note:
Don't make the required amount be much higher than 20. In fact, it's
generally best to never make it higher than 20, since there's a possibility that the party
-will have only one PC.
+will have only one PC. For the same reason, if checking mage or priest spells skill, you generally
+shouldn't make the required amount higher than 7.
Uses:
Checking if the party has enough mage lore to decipher an ancient scroll
and learn a new spell.
Type 154: Text response?
This is one of the most complicated and powerful
special nodes. It brings up a dialog box asking the party to type in some text (such as
-the answer to a ridder, or a password). If the response matches one of two given text
+the answer to a riddle, or a password). If the response matches one of two given text
messages, a specified special node is called.
Pict:
This is a number from 1 to 10. It is the number of characters the
-players answer has to match the correct answer to be accepted. If it is 4, the first four
-characters of the players answer must match the first four characters of the correct
+player's answer has to match the correct answer to be accepted. If it is 4, the first four
+characters of the player's answer must match the first four characters of the correct
answer.
-
Extra 1a:
The number of a scenario special message (not
a town or
-outdoor special message).
Extra 1b:
If the players answer matches the message in Extra 1a, this special
-is called.
-
Extra 2a:
The number of a scenario special message (not
a town or
+
Extra 1a:
The number of a scenario special message (not a town or
outdoor special message).
-
Extra 2b:
If the players answer matches the message in Extra 1a, this special
+
Extra 1b:
If the player's answer matches the message in Extra 1a, this special
+is called.
+
Extra 2a:
The number of a scenario special message (not a town or
+outdoor special message).
+
Extra 2b:
If the player's answer matches the message in Extra 1a, this special
is called.
Jump To:
Otherwise, this special is called.
Note:
To create the scenario message containing the correct answer, select
@@ -1373,13 +1390,13 @@ answer to the question there. The number of that message (160-259) is the number
the Extra 1a/Extra 2a field.
Example:
A pixie asks a riddle whose answer is cheese. Scenario message 185 is
cheese. Message 1 says the pixie's riddle. Extra 1a is 185, Extra 1b is the special node
-with the result of correct answering of the riddle, and Jump To leads to the node with the
+with the result of correctly answering the riddle, and Jump To leads to the node with the
result of an incorrect answer.
-
If pict is set to 4, only the first 4 characters of the players answer are looked at.
+
If pict is set to 4, only the first 4 characters of the player's answer are looked at.
Thus, cheese, cheer, and cheep would count as right answers. Chew, however, would
not.
Note:
Letter case is ignored. ChEeSe would be counted as a correct answer,
-even is the correct answer was CHEese.
+even if the correct answer was CHEese.
Type 155: Stuff done equal?
If the specified Stuff Done flag is equal to the
value given in Extra 1a, the special in Extra 1b is called. Otherwise, the Jump To special
@@ -1406,8 +1423,30 @@ as Wrack or Strengthen Target can also be tested for; just enter the same spell
would enter for the item ability.
Type 157: If Numeric Response?
Result depends on a number entered by the player.
-
-
+
+
Mess 1:
The number of a scenario string giving a prompt to the user.
+
Mess 2, Mess 3:
Specifies the minimum and maximum value the game will accept.
+If the player tries to enter a value outside this range, the dialog will not close.
+The dialog will display the expect range clearly to the player.
+
Pict:
Specifies the comparison mode for the tests. If 0, the test passes
+when the number is in the specified range. If 1, the test passes when the number is
+not in the specified range. If 2, the test passes if the number compares
+favourably to the expected number.
+
Pic Type:
Specifies a special node to call if both tests pass.
+
Extra 1a:
If Pict is set to 0 or 1, this specifies the lower bound of the
+range. Otherwise, it specifies the number to compare to.
+
Extra 1b:
If Pict is set to 0 or 1, this specifies the upper bound of the
+range. Otherwise, it specifies the comparison operator to use. Click Choose to select
+one.
+
Extra 1c:
This special node is called if this test fails but the
+other test passes.
+
Extra 2a, Extra 2b, Extra 2c:
As extra 1a, 1b, and 1c, defining a second
+test.
+
JumpTo:
This special node is called if neither of the tests pass.
+
Note:
If Extra 1a is set to -1, the first test is ignored and the special
+nodes in Extra 1c and Pic Type are never called. Similarly, if Extra 2a is set to
+-1, the second test is ignored and the special nodes in Extra 2c and Pic Type are
+never called.
Type 158: In Boat?
Result depends whether the player is in a boat.
@@ -1493,7 +1532,7 @@ while talking.
Extra 1a, Extra 1b:
The x and y coordinates of the space to hit.
Extra 2a:
The amount of damage to inflict. (Range 0 ... 1000)
Extra 2b:
This is the type of damage inflicted (0 - weapon, 1 - fire, 2 -
-poison, 3 - general magic, 4 - unblockable, 5 - cold, 6 - demon,7 - undead)
Damage doing specials are ignored when called while Talking.
Type 176: Explosion on Space
Everything within a given radius of the specified
@@ -1503,7 +1542,7 @@ space takes damage. Only creatures who can be seen from the exploding space are
Extra 1a, Extra 1b:
The x and y coordinates of the space to hit.
Extra 2a:
The amount of damage to inflict. (Range 0 ... 1000)
Extra 2b:
This is the type of damage inflicted (0 - weapon, 1 - fire, 2 -
-poison, 3 - general magic, 4 - unblockable, 5 - cold, 6 - demon,7 - undead)
If left at 0, the burst is a simple explosion. If set to 1, a larger
burst is used for an even flashier effect.
Extra 2c:
Specifies the sound to play with the explosion. Leave at -1 to use
@@ -1567,7 +1606,7 @@ and the special encounter ends.
Extra 1a, Extra 1b:
The x and y coordinates of the space the party is
teleported to if the player pushes Enter.
Note:
Like all party moving special nodes, if this is called any time besides
-when walking in town mode, the special encounter ends immediately, and, if moving, the
+when walking in town mode, the special encounter normally ends immediately, and, if moving, the
party is not allowed to enter the space.
Type 186: Generic Button
A dialog box comes up saying the party has found a
@@ -1588,7 +1627,7 @@ stairs down, 2 - path slopes up, 3 - path slopes down, 4 - slimy stairway up, 5
stairway down, 6 - dark passage up, 7 - dark passage down, 8+ - no dialog (stairway
is forced).
Extra 2c:
If left at 0, the party can only enter while walking in town mode
-(as described in the note for Generic Portal). If set to 1 or 2, the encounter can be
+(as described in the note for Generic Portal). If set to 1 or 3, the encounter can be
activated in combat mode. If set to 2 or 3, the encounter can be activated by other
actions, such as searching the space, using the space, targeting a spell on the space,
etc.
If, when the party leaves at the north end of a dungeon, you want them
to be in a different location in the outdoors from where they were when the entered, place
a special node of this type just before the north exit (where they're forced to step on
-it).
-
Note:
When this node is called, there is a delay while the new outdoors
-section is loaded into memory. Try not to call it too often.
+it).
Type 192: Place Item
Places an item on a specified space.
@@ -1690,7 +1727,7 @@ the party is split up, the lone character is moved back to where the party was w
split up, the party is rejoined, and the special encounter ends.
Extra 1a:
If 0, nothing else happens. If non-zero, a teleportation noise plays
-when the party is split up.
+when the party is reunited.
Extra 2a:
If 0, the party is returned to where they split up at. Otherwise,
the party remains at their current location.
@@ -1781,7 +1818,9 @@ intended to be magical. Set it to 0 to prevent the user from targeting spaces in
antimagic field. If left at -1, the default is used, which is to allow it in town mode but
not in combat. (This is probably a relic of the extremely limited selection of spells that
can be targeted in town mode.)
-
JumpTo:
This node is called once for every selected target.
+
JumpTo:
This node is called once for every selected target. Note that this
+does not mean it is called once for every space affected – if you target 3 crosses,
+the node is called once for each cross.
Type 201: Place Pattern (Fields/Objects)
Places fields according to a preset
spell pattern relative to a specified space.
@@ -1797,7 +1836,9 @@ spell pattern relative to a specified space.
5 - circle radius 3,
6 - 5 spaces in a cross,
7-13 - rotateable 2x8 wall in various orientation
-
Extra 2a
The field type to place
+
Extra 2a
The field type to place. Two special values are supported – 32 removes
+any fields on the space, while 33 transforms any terrains of the Crumbling type into their
+transform to terrain.
Type 202: Place Pattern (Direct Damage)
Deals damage according to a preset
spell pattern relative to a specified space.
@@ -1806,7 +1847,7 @@ spell pattern relative to a specified space.
Extra 2a:
The type of damage to deal
The amount of damage to deal. This is the number of six-sided dice to roll to
calculate the damage.
-
If 0, it will animate each affected creature sequentially using simply booms,
+
If 0, it will animate each affected creature sequentially using simple booms,
similar to what happens when fields are placed and creatures take damage as a result. If
1, all damage will be animated simultaneously using fully-animated explosions, similar to
what happens when casting spells such as Fireball or Divine Thud.
@@ -1814,17 +1855,19 @@ what happens when casting spells such as Fireball or Divine Thud.
Type 203: Relocate Creature
This node forces a single creature to relocate to
a different space. Useful for cutscenes. It can handle either absolute or relative
movement.
-However, it does not currently check that it is legal for the creature to be on that
+However, it usually does not check that it is legal for the creature to be on that
space.
This can split the party into its individual members temporarily, similar to combat mode,
but they return to the party's original location once the node sequence ends.
+However, if in combat mode, the PCs remain on the final location.
Extra 1a, Extra 1b:
The x and y coordinates or differentials.
Extra 2a:
The creature to relocate - 0-5 for party members, 100+x for a
specific monster, -1 for the currently selected target.
Extra 2b:
If 0, Extra 1a and 1b are taken as absolute coordinates. If 1, they
are added to the x and y coordinates, respectively. 2 or 3 means the x coordinate is
-instead subtracted, while 3 or 4 means the y coordinate is instead subtracted.
+instead subtracted, while 3 or 4 means the y coordinate is instead subtracted. Set to 5 to use
+absolute positioning but select a nearby space the monster can be on.
Extra 2c:
If positive, this specifies a delay in milliseconds after the
creature
is repositioned.
@@ -1900,7 +1943,10 @@ space. Items inside containers are not moved. This only works in town.
items to.
Mess 3:
If 0, place items on the ground. If this is 1 and the target space has
a container on it (including a movable container such as a barrel), the items are instead
-placed in the container.
+placed in the container. If the space somehow contains both a static terrain container
+and a crate or barrel, the items are placed in the crate or barrel.
+
Pict Type:
If 0, items in containers are not moved. If 1, even items in
+containers will be collected onto the target space.
Type 213: Destroy Items
Destroys all of the items in the rectangle. Be careful
not to destroy something the party needs to finish the scenario. Only works in town.
diff --git a/doc/editor/appendix/nav.js b/doc/editor/appendix/nav.js
index 516069821..81dd90463 100644
--- a/doc/editor/appendix/nav.js
+++ b/doc/editor/appendix/nav.js
@@ -35,7 +35,9 @@ document.addEventListener('DOMContentLoaded', function() {
nav.appendChild(links[i]);
document.querySelector('.navbar').appendChild(nav);
// Now check if one was requested in the query string
- var dest = location.search.match(/^jumpto\=(\d)/, '');
- if(dest && dest[1] >= 0 && dest[1] < elems.length)
+ var query = new URLSearchParams(location.search);
+ var dest = query.get('jumpto');
+ console.log(dest);
+ if(dest && dest >= 0 && dest < elems.length)
elems[dest].scrollIntoView();
});
diff --git a/doc/editor/nav.js b/doc/editor/nav.js
index f38f90caa..edd36767d 100644
--- a/doc/editor/nav.js
+++ b/doc/editor/nav.js
@@ -4,39 +4,48 @@ The navbar, to be included in all files.
*/
-document.write('\
-\
-
\n`);
+}
+
+document.write('\n\n');
diff --git a/doc/upload.sh b/doc/upload.sh
new file mode 100755
index 000000000..3bf919f6e
--- /dev/null
+++ b/doc/upload.sh
@@ -0,0 +1,31 @@
+
+while getopts "u:h:p:" OPT; do
+ case $OPT in
+ u) UPLOAD_USER=$OPTARG;;
+ h) UPLOAD_HOST=$OPTARG;;
+ p) UPLOAD_PATH=$OPTARG;;
+ \?) exit 1;;
+ esac
+done
+
+if [ -z "$UPLOAD_USER" ]; then
+ echo "Missing user -u"
+ exit 1
+fi
+
+if [ -z "$UPLOAD_HOST" ]; then
+ echo "Missing host -h"
+ exit 1
+fi
+
+if [ -z "$UPLOAD_PATH" ]; then
+ echo "Missing path -p"
+ exit 1
+fi
+
+echo "Uploading documentation files to $UPLOAD_USER@$UPLOAD_HOST"
+
+rsync -rptv \
+ --exclude-from=doc/upload_exclude.txt \
+ --delete --delete-excluded \
+ doc/ $UPLOAD_USER@$UPLOAD_HOST:$UPLOAD_PATH
diff --git a/doc/upload_exclude.txt b/doc/upload_exclude.txt
new file mode 100644
index 000000000..4d1462987
--- /dev/null
+++ b/doc/upload_exclude.txt
@@ -0,0 +1,6 @@
+Notes from Jeff Vogel.txt
+SConscript
+documentation.lyx
+gpl-license.txt
+upload_exclude.txt
+upload.sh
diff --git a/pkg/mac/SConscript b/pkg/mac/SConscript
index 360f84cc2..9d9c70789 100644
--- a/pkg/mac/SConscript
+++ b/pkg/mac/SConscript
@@ -2,7 +2,7 @@
Import("env platform")
if str(platform) != "darwin":
- print "Error: Building for", str(platform), "but trying to create a Mac install package"
+ print("Error: Building for", str(platform), "but trying to create a Mac install package")
env.Command('OBoE.dmg', "#build/Blades of Exile",
action='hdiutil create -fs HFS+ -volname "Blades of Exile" -srcfolder $SOURCE $TARGET')
diff --git a/pkg/win/SConscript b/pkg/win/SConscript
index 79e6b0725..f76852e5d 100644
--- a/pkg/win/SConscript
+++ b/pkg/win/SConscript
@@ -4,7 +4,7 @@ import os.path as path
Import("env platform")
if str(platform) != "win32":
- print "Error: Building for", str(platform), "but trying to create a Windows installer package"
+ print(f"Error: Building for {platform}, but trying to create a Windows installer package")
env.Depends("data.nsi", ["gen-data.py", "#build/Blades of Exile/data"])
diff --git a/proj/vs2013/vcpkg.json b/proj/vs2013/vcpkg.json
new file mode 100644
index 000000000..a5ea903bd
--- /dev/null
+++ b/proj/vs2013/vcpkg.json
@@ -0,0 +1,18 @@
+{
+ "builtin-baseline": "bcf3d00d2116056fda0ce47615f6074ffecb7524",
+ "dependencies": [
+ "zlib",
+ "sfml",
+ "opengl",
+ "boost-any",
+ "boost-dynamic-bitset",
+ "boost-ptr-container",
+ "boost-core",
+ "boost-filesystem",
+ "boost-system",
+ "boost-date-time",
+ "boost-chrono",
+ "boost-math",
+ "boost-spirit"
+ ]
+}
\ No newline at end of file
diff --git a/proj/vs2017/Common/Common.vcxproj b/proj/vs2017/Common/Common.vcxproj
index 870e91842..ef1cd6531 100644
--- a/proj/vs2017/Common/Common.vcxproj
+++ b/proj/vs2017/Common/Common.vcxproj
@@ -456,7 +456,7 @@
-
+
@@ -539,53 +539,53 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/proj/vs2017/Tests/Tests.vcxproj b/proj/vs2017/Tests/Tests.vcxproj
index c63040bac..b0f6b382e 100644
--- a/proj/vs2017/Tests/Tests.vcxproj
+++ b/proj/vs2017/Tests/Tests.vcxproj
@@ -201,7 +201,8 @@
-
+
+
diff --git a/proj/vs2017/Tests/Tests.vcxproj.filters b/proj/vs2017/Tests/Tests.vcxproj.filters
index 3c32a5094..f0d64028a 100644
--- a/proj/vs2017/Tests/Tests.vcxproj.filters
+++ b/proj/vs2017/Tests/Tests.vcxproj.filters
@@ -77,7 +77,10 @@
Source Files
-
+
+ Source Files
+
+ Source Files
diff --git a/proj/vs2017/vcpkg.json b/proj/vs2017/vcpkg.json
new file mode 100644
index 000000000..a5ea903bd
--- /dev/null
+++ b/proj/vs2017/vcpkg.json
@@ -0,0 +1,18 @@
+{
+ "builtin-baseline": "bcf3d00d2116056fda0ce47615f6074ffecb7524",
+ "dependencies": [
+ "zlib",
+ "sfml",
+ "opengl",
+ "boost-any",
+ "boost-dynamic-bitset",
+ "boost-ptr-container",
+ "boost-core",
+ "boost-filesystem",
+ "boost-system",
+ "boost-date-time",
+ "boost-chrono",
+ "boost-math",
+ "boost-spirit"
+ ]
+}
\ No newline at end of file
diff --git a/proj/xc12/BoE.xcodeproj/project.pbxproj b/proj/xc12/BoE.xcodeproj/project.pbxproj
index 8e2511014..88e6251e6 100755
--- a/proj/xc12/BoE.xcodeproj/project.pbxproj
+++ b/proj/xc12/BoE.xcodeproj/project.pbxproj
@@ -59,6 +59,9 @@
911A14031B8FAFC600900FD9 /* town_read.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91C2A6EC1B8FA91400346948 /* town_read.cpp */; };
911A14041B8FB00300900FD9 /* talk_read.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91C2A6EE1B8FAA8E00346948 /* talk_read.cpp */; };
911A14051B8FB00600900FD9 /* out_read.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91C2A6ED1B8FA9FB00346948 /* out_read.cpp */; };
+ 911DD995297C56F500205EBC /* string_quote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 911DD994297C56F500205EBC /* string_quote.cpp */; };
+ 911DD9BF297C8B2000205EBC /* dialogs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 911DD9BE297C8B2000205EBC /* dialogs.cpp */; };
+ 911DD9D5297C909D00205EBC /* tagfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 919F2E71287E4E0500F47750 /* tagfile.cpp */; };
911F2D991B98F43B00E3102E /* libCommon.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 911F2D981B98F43B00E3102E /* libCommon.a */; };
911F2D9A1B98F43C00E3102E /* libCommon.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 911F2D981B98F43B00E3102E /* libCommon.a */; };
911F2D9B1B98F43C00E3102E /* libCommon.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 911F2D981B98F43B00E3102E /* libCommon.a */; };
@@ -204,8 +207,7 @@
919DDC0D19007517003E7FED /* freetype.framework in Copy Libraries and Frameworks */ = {isa = PBXBuildFile; fileRef = 919DDC091900750D003E7FED /* freetype.framework */; };
919DDC0E1900751C003E7FED /* freetype.framework in Copy Libraries and Frameworks */ = {isa = PBXBuildFile; fileRef = 919DDC091900750D003E7FED /* freetype.framework */; };
919DDC0F1900751F003E7FED /* freetype.framework in Copy Libraries and Frameworks */ = {isa = PBXBuildFile; fileRef = 919DDC091900750D003E7FED /* freetype.framework */; };
- 919F2E7E287E529600F47750 /* tagfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 919F2E71287E4E0500F47750 /* tagfile.cpp */; };
- 919F2E9A287E5BB700F47750 /* tagfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 919F2E99287E5BB700F47750 /* tagfile.cpp */; };
+ 919F2E9A287E5BB700F47750 /* tagfiles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 919F2E99287E5BB700F47750 /* tagfiles.cpp */; };
919F2ECA287F023100F47750 /* SFML.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 91F6F8E218F87F3700E3EA15 /* SFML.framework */; };
919F2ECB287F023100F47750 /* sfml-audio.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 91F6F8DD18F87F3700E3EA15 /* sfml-audio.framework */; };
919F2ECC287F023100F47750 /* sfml-graphics.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 91F6F8DE18F87F3700E3EA15 /* sfml-graphics.framework */; };
@@ -616,6 +618,8 @@
910BBAB50FB91A26001E34EA /* field.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = field.cpp; sourceTree = ""; };
910BBAB80FB91ADB001E34EA /* message.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = message.hpp; sourceTree = ""; };
910BBAB90FB91ADB001E34EA /* message.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = message.cpp; sourceTree = ""; };
+ 911DD994297C56F500205EBC /* string_quote.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = string_quote.cpp; sourceTree = ""; };
+ 911DD9BE297C8B2000205EBC /* dialogs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dialogs.cpp; sourceTree = ""; };
911F2D981B98F43B00E3102E /* libCommon.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libCommon.a; path = lib/libCommon.a; sourceTree = ""; };
911F2D9D1B98F44700E3102E /* libCommon-Party.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libCommon-Party.a"; path = "lib/libCommon-Party.a"; sourceTree = ""; };
911F2DA21B98FF2300E3102E /* cursors */ = {isa = PBXFileReference; lastKnownFileType = folder; path = cursors; sourceTree = ""; };
@@ -740,7 +744,7 @@
919DDC091900750D003E7FED /* freetype.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = freetype.framework; path = /Library/Frameworks/freetype.framework; sourceTree = ""; };
919F2E71287E4E0500F47750 /* tagfile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = tagfile.cpp; sourceTree = ""; };
919F2E72287E4E0500F47750 /* tagfile.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = tagfile.hpp; sourceTree = ""; };
- 919F2E99287E5BB700F47750 /* tagfile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = tagfile.cpp; sourceTree = ""; };
+ 919F2E99287E5BB700F47750 /* tagfiles.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = tagfiles.cpp; sourceTree = ""; };
919F2EAF287F00B800F47750 /* boe_test.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = boe_test.entitlements; sourceTree = ""; };
91A0B15A1900F73E00EF438F /* mask.frag */ = {isa = PBXFileReference; explicitFileType = sourcecode.glsl; fileEncoding = 4; path = mask.frag; sourceTree = ""; };
91A2480D2969CFD200B8D90F /* res_dialog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = res_dialog.cpp; sourceTree = ""; };
@@ -1511,6 +1515,7 @@
isa = PBXGroup;
children = (
91CC17391B421CA0003D9A69 /* catch.cpp */,
+ 911DD9BE297C8B2000205EBC /* dialogs.cpp */,
91C763D81B4C4BB30086D879 /* enums.cpp */,
91E128E51BC19DA400C8BE1D /* init.cpp */,
919B13A31BBD8849009905A4 /* item_legacy.cpp */,
@@ -1529,8 +1534,8 @@
91CC173A1B421CA0003D9A69 /* scen_read.cpp */,
91CC173B1B421CA0003D9A69 /* scen_write.cpp */,
919B13A51BBDE985009905A4 /* spec_legacy.cpp */,
- 919F2E99287E5BB700F47750 /* tagfile.cpp */,
- 91430437296C0088003A3967 /* vector2d.cpp */,
+ 911DD994297C56F500205EBC /* string_quote.cpp */,
+ 919F2E99287E5BB700F47750 /* tagfiles.cpp */,
9176FEC41D550EFD006EF694 /* talk_legacy.cpp */,
91C2A6EE1B8FAA8E00346948 /* talk_read.cpp */,
91E381471B97675900F69B81 /* talk_write.cpp */,
@@ -1540,6 +1545,7 @@
9176FEC51D550EFE006EF694 /* town_legacy.cpp */,
91C2A6EC1B8FA91400346948 /* town_read.cpp */,
91E381451B97671E00F69B81 /* town_write.cpp */,
+ 91430437296C0088003A3967 /* vector2d.cpp */,
);
name = src;
sourceTree = "";
@@ -2009,7 +2015,6 @@
919CC25E1B37736900273FDA /* universe.cpp in Sources */,
919CC2731B3773FD00273FDA /* fileio_party.cpp in Sources */,
919CC2801B37744800273FDA /* pc.editors.cpp in Sources */,
- 919F2E7E287E529600F47750 /* tagfile.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2025,6 +2030,7 @@
919CC2561B37733E00273FDA /* shop.cpp in Sources */,
919CC2571B37734000273FDA /* special.cpp in Sources */,
919CC2581B37734700273FDA /* spell.cpp in Sources */,
+ 911DD9D5297C909D00205EBC /* tagfile.cpp in Sources */,
919CC2591B37734C00273FDA /* talking.cpp in Sources */,
919CC25A1B37735100273FDA /* terrain.cpp in Sources */,
919CC25C1B37735C00273FDA /* town.cpp in Sources */,
@@ -2131,6 +2137,7 @@
91430438296C0088003A3967 /* vector2d.cpp in Sources */,
91C763DD1B4EE7950086D879 /* map_write.cpp in Sources */,
91EF27731B693D3900666469 /* ter_read.cpp in Sources */,
+ 911DD995297C56F500205EBC /* string_quote.cpp in Sources */,
91EF27751B693D4800666469 /* ter_write.cpp in Sources */,
91EF27771B693D5500666469 /* item_read.cpp in Sources */,
91EF27791B693D5F00666469 /* item_write.cpp in Sources */,
@@ -2139,9 +2146,10 @@
911A14031B8FAFC600900FD9 /* town_read.cpp in Sources */,
911A14041B8FB00300900FD9 /* talk_read.cpp in Sources */,
911A14051B8FB00600900FD9 /* out_read.cpp in Sources */,
- 919F2E9A287E5BB700F47750 /* tagfile.cpp in Sources */,
+ 919F2E9A287E5BB700F47750 /* tagfiles.cpp in Sources */,
91E381461B97673700F69B81 /* town_write.cpp in Sources */,
91E381481B97677900F69B81 /* talk_write.cpp in Sources */,
+ 911DD9BF297C8B2000205EBC /* dialogs.cpp in Sources */,
91E3814A1B97679800F69B81 /* out_write.cpp in Sources */,
919B13A21BBCDF14009905A4 /* monst_legacy.cpp in Sources */,
919B13A41BBD8854009905A4 /* item_legacy.cpp in Sources */,
@@ -2340,6 +2348,7 @@
"-Wno-quoted-include-in-framework-header",
"-Wno-shorten-64-to-32",
"-Wno-comma",
+ "-Werror=implicit-fallthrough",
);
};
name = Debug;
@@ -2447,6 +2456,7 @@
"-Wno-quoted-include-in-framework-header",
"-Wno-shorten-64-to-32",
"-Wno-comma",
+ "-Werror=implicit-fallthrough",
);
};
name = Release;
diff --git a/proj/xc4/BoE.xcodeproj/project.pbxproj b/proj/xc4/BoE.xcodeproj/project.pbxproj
index 3a063c9f9..1bf150a04 100755
--- a/proj/xc4/BoE.xcodeproj/project.pbxproj
+++ b/proj/xc4/BoE.xcodeproj/project.pbxproj
@@ -219,9 +219,12 @@
91B375332969F529008B0324 /* res_dialog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91B375322969F529008B0324 /* res_dialog.cpp */; };
91B375362969F548008B0324 /* tagfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91B375352969F548008B0324 /* tagfile.cpp */; };
91B375372969F548008B0324 /* tagfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91B375352969F548008B0324 /* tagfile.cpp */; };
- 91B3753A2969F57B008B0324 /* tagfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91B375392969F57B008B0324 /* tagfile.cpp */; };
+ 91B3753A2969F57B008B0324 /* tagfiles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91B375392969F57B008B0324 /* tagfiles.cpp */; };
91B3753D29736417008B0324 /* keymods.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91B3753B29736417008B0324 /* keymods.cpp */; };
91B3753E29736417008B0324 /* keymods.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 91B3753C29736417008B0324 /* keymods.hpp */; };
+ 91B37545297C8ABC008B0324 /* dialogs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91B3753F297C8ABB008B0324 /* dialogs.cpp */; };
+ 91B37549297C8ABC008B0324 /* string_quote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91B37543297C8ABC008B0324 /* string_quote.cpp */; };
+ 91B3754A297C8ABC008B0324 /* vector2d.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91B37544297C8ABC008B0324 /* vector2d.cpp */; };
91B3EF1F0F969C9C00BF5B67 /* BoECharEd.icns in Resources */ = {isa = PBXBuildFile; fileRef = 91B3EF110F969BD300BF5B67 /* BoECharEd.icns */; };
91B3EF470F969F1700BF5B67 /* BoEScenEd.icns in Resources */ = {isa = PBXBuildFile; fileRef = 91B3EEDB0F969BA700BF5B67 /* BoEScenEd.icns */; };
91B3EF480F969F2300BF5B67 /* pc.main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91B3EF050F969BD300BF5B67 /* pc.main.cpp */; };
@@ -719,9 +722,12 @@
91B375342969F533008B0324 /* res_dialog.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = res_dialog.hpp; sourceTree = ""; };
91B375352969F548008B0324 /* tagfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tagfile.cpp; sourceTree = ""; };
91B375382969F55B008B0324 /* tagfile.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = tagfile.hpp; sourceTree = ""; };
- 91B375392969F57B008B0324 /* tagfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tagfile.cpp; sourceTree = ""; };
+ 91B375392969F57B008B0324 /* tagfiles.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tagfiles.cpp; sourceTree = ""; };
91B3753B29736417008B0324 /* keymods.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = keymods.cpp; sourceTree = ""; };
91B3753C29736417008B0324 /* keymods.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = keymods.hpp; sourceTree = ""; };
+ 91B3753F297C8ABB008B0324 /* dialogs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dialogs.cpp; sourceTree = ""; };
+ 91B37543297C8ABC008B0324 /* string_quote.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = string_quote.cpp; sourceTree = ""; };
+ 91B37544297C8ABC008B0324 /* vector2d.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = vector2d.cpp; sourceTree = ""; };
91B3E8A50F938FFE00BF5B67 /* boe.consts.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = boe.consts.hpp; sourceTree = ""; };
91B3EED90F969BA700BF5B67 /* BoEScenEd-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "BoEScenEd-Info.plist"; path = "../../pkg/mac/BoEScenEd-Info.plist"; sourceTree = SOURCE_ROOT; };
91B3EEDB0F969BA700BF5B67 /* BoEScenEd.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = BoEScenEd.icns; path = icons/mac/BoEScenEd.icns; sourceTree = ""; };
@@ -1472,6 +1478,7 @@
isa = PBXGroup;
children = (
91CC17391B421CA0003D9A69 /* catch.cpp */,
+ 91B3753F297C8ABB008B0324 /* dialogs.cpp */,
91C763D81B4C4BB30086D879 /* enums.cpp */,
91E128E51BC19DA400C8BE1D /* init.cpp */,
919B13A31BBD8849009905A4 /* item_legacy.cpp */,
@@ -1490,7 +1497,8 @@
91CC173A1B421CA0003D9A69 /* scen_read.cpp */,
91CC173B1B421CA0003D9A69 /* scen_write.cpp */,
919B13A51BBDE985009905A4 /* spec_legacy.cpp */,
- 91B375392969F57B008B0324 /* tagfile.cpp */,
+ 91B37543297C8ABC008B0324 /* string_quote.cpp */,
+ 91B375392969F57B008B0324 /* tagfiles.cpp */,
9176FEC41D550EFD006EF694 /* talk_legacy.cpp */,
91C2A6EE1B8FAA8E00346948 /* talk_read.cpp */,
91E381471B97675900F69B81 /* talk_write.cpp */,
@@ -1500,6 +1508,7 @@
9176FEC51D550EFE006EF694 /* town_legacy.cpp */,
91C2A6EC1B8FA91400346948 /* town_read.cpp */,
91E381451B97671E00F69B81 /* town_write.cpp */,
+ 91B37544297C8ABC008B0324 /* vector2d.cpp */,
);
name = src;
sourceTree = "";
@@ -2086,7 +2095,10 @@
91C548F81D8B2FE400FE6A7B /* pc_read.cpp in Sources */,
91C548F91D8B338700FE6A7B /* pc.cpp in Sources */,
91B375372969F548008B0324 /* tagfile.cpp in Sources */,
- 91B3753A2969F57B008B0324 /* tagfile.cpp in Sources */,
+ 91B3753A2969F57B008B0324 /* tagfiles.cpp in Sources */,
+ 91B37545297C8ABC008B0324 /* dialogs.cpp in Sources */,
+ 91B37549297C8ABC008B0324 /* string_quote.cpp in Sources */,
+ 91B3754A297C8ABC008B0324 /* vector2d.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/rsrc/dialogs/edit-townperson.xml b/rsrc/dialogs/edit-townperson.xml
index 21afc0ea9..1ec9a5b67 100644
--- a/rsrc/dialogs/edit-townperson.xml
+++ b/rsrc/dialogs/edit-townperson.xml
@@ -21,8 +21,8 @@
Hostile, Type B
- No
- Yes
+ No
+ Yes
diff --git a/rsrc/dialogs/locked-door-action.xml b/rsrc/dialogs/locked-door-action.xml
index 81226a66d..a4d77d318 100644
--- a/rsrc/dialogs/locked-door-action.xml
+++ b/rsrc/dialogs/locked-door-action.xml
@@ -2,8 +2,8 @@
diff --git a/rsrc/saves/readme.md b/rsrc/saves/readme.md
new file mode 100644
index 000000000..824cdf112
--- /dev/null
+++ b/rsrc/saves/readme.md
@@ -0,0 +1,84 @@
+
+Saved Game Format
+=================
+
+The Blades of Exile saved game format is a gzipped tarball with a .exg extension
+and the following structure:
+
+* save/
+ * party.txt - Contains general info on the party.
+ * pc*N*.txt - Contains info on active PC _N_, which is 1-6.
+ * stored_pcs.txt - Contains a list of unique IDs for stored PCs. Optional.
+ * pc~*N*.txt - Contains info on stored PC _N_, which must be found in _stored_pcs.txt_.
+ * export.png - Contains graphics referenced from other files in this folder. Optional.
+ * scenario.txt - Contains some persistent information about towns in the scenario.
+ * setup.dat - Contains saved information about fields in recent towns you've visited.
+ * town.txt - Contains information about the current town, if the party is in down.
+ * townmaps.dat - Contains information about what areas of towns have been explored.
+ * out.txt - Contains information about the current outdoor region (a 2x2 grid of sectors).
+ * outmaps.dat - Contains information about what areas of the outdoors have been explored.
+
+A party that is not in a scenario omits all the files from _scenario.txt_ down.
+The _stored_pcs.txt_ file is only included if there actually are stored PCs.
+The _town.txt_ file is omitted if the party is outdoors, but _townmaps.dat_ is not.
+
+If you have a _save_ directory with the proper structure, it can be turned into a
+valid saved game with the following shell command:
+
+ tar -zcf save.exg save
+
+(This should work on the Windows command-line too, assuming you have `tar.exe` installed
+and in the `%PATH%` or current directory.)
+
+Most of the files in the saved game use a "tag file" format, which is described below. There are four exceptions (plus export.png):
+
+* The _stored_pcs.txt_ file is simply a list of numbers, one per line. It's essentially an index of the stored PCs – for every number in this file, there will be a corresponding _pc~N.txt_.
+* The _townmaps.dat_ file is simply a list of bitfields, one per line, addressing all towns in the scenario in order of definition from top to bottom. Each bitfield covers one row of one town.
+* The _out.txt_ file is a straight dump of the active outdoor terrain, two consecutive 96x96 grids of numbers separated by spaces and newlines. The first set covers the terrain while the second set covers the explored flag.
+* The _outmaps.dat_ file is simply a list of bitfields, several per line, addressing all outdoor sectors in order of definition from top to bottom. Each line covers one row of every sector in a single row of the outdoors grid, so for example if the outdoors is 3x3, then each row will contain 3 bitfields addressing a row of sectors (_N_,0), (_N_,1), and (_N_,2).
+
+Tag Files
+=========
+
+The "tag file" format is very simple. A "tag file" consists of a series of "pages", separated by formfeed characters. Each page consists of a series of "tags", one per line. Each tag consists of an "identifier" followed by zero or more "values", separated by whitespace. Values can be quoted if they contain spaces or tabs; this can also convey a blank value. The order of tags is preserved and can be significant. Sometimes the mere presence of a tag conveys a meaning – tags without values are often used for this purpose. There are no restrictions on what characters can appear in an identifier, other than whitespace (quotes are not parsed in the identifier).
+
+When parsing tag values, quotes (" and ') only have a special meaning if they appear as the first character. So, for example, the string "don't" would not need to be quoted, as it doesn't start with '. The following backslash escape sequences are supported in quoted strings:
+
+* `\\` - Literal backslash
+* `\'` - Literal single quote (only required in single-quoted strings)
+* `\"` - Literal double quote (only required in double-quoted strings)
+* `\n` - A newline
+* `\t` - A horizontal tab (not required, but parsed for consistency)
+* `\f` - A formfeed
+
+Note that no escape sequences will be expanded in unquoted strings.
+For tag values that are interpreted as booleans, the strings "true" and "false" are used.
+Most tag values interpreted as numbers use the decimal format, but a hexadecimal format
+is also supported. Which format to use is decided by the code that loads the file.
+
+For example, a very simple two-page tag file might look like this:
+
+ NAME "It's Me!"
+ LEVEL 5
+ HEALTH 12 34
+ MANA 1 45
+
+ ITEM 0
+ NAME "Broken Sword"
+ DAMAGE 2 7
+ EQUIPPED
+
+ ITEM 1
+ NAME "Healing Potion"
+ ABILITY heals
+
+An actual tag file would not add a newline between the formfeed and the following tag.
+
+For the tag files actually used in the saved game, pages are usually identified based on
+the first tag that appears in them. However, the very first page is usually treated
+specially without checking what its first tag is.
+
+The exact list of pages and tags that are used in the saved game files are not yet
+finalized, so they won't be documented here. However, it is not hard to figure it out
+by looking at the code – look for functions called `writeTo` or `readFrom` that take
+either a `cTagFile` or a `cTagFile_Page` as a parameter.
diff --git a/src/dialogxml/dialogs/dialog.cpp b/src/dialogxml/dialogs/dialog.cpp
index 970748512..6b590a25c 100644
--- a/src/dialogxml/dialogs/dialog.cpp
+++ b/src/dialogxml/dialogs/dialog.cpp
@@ -740,7 +740,7 @@ void cDialog::setBg(short n){
bg = n;
}
-short cDialog::getBg() {
+short cDialog::getBg() const {
return bg;
}
@@ -748,7 +748,7 @@ void cDialog::setDefTextClr(sf::Color clr){
defTextClr = clr;
}
-sf::Color cDialog::getDefTextClr() {
+sf::Color cDialog::getDefTextClr() const {
return defTextClr;
}
@@ -767,7 +767,7 @@ void cDialog::untoast() {
this->getControl(currentFocus).triggerFocusHandler(*this, currentFocus, false);
}
-bool cDialog::accepted() {
+bool cDialog::accepted() const {
return didAccept;
}
@@ -1057,6 +1057,10 @@ cControl& cDialog::operator[](std::string id){
return getControl(id);
}
+const cControl& cDialog::operator[](std::string id) const {
+ return const_cast(*this).getControl(id);
+}
+
cControl& cDialog::getControl(std::string id) {
ctrlIter iter = controls.find(id);
if(iter != controls.end()) return *(iter->second);
@@ -1073,8 +1077,8 @@ cControl& cDialog::getControl(std::string id) {
throw std::invalid_argument(id + " does not exist in dialog " + fname);
}
-bool cDialog::hasControl(std::string id) {
- ctrlIter iter = controls.find(id);
+bool cDialog::hasControl(std::string id) const {
+ auto iter = controls.find(id);
if(iter != controls.end()) return true;
iter = controls.begin();
diff --git a/src/dialogxml/dialogs/dialog.hpp b/src/dialogxml/dialogs/dialog.hpp
index 88a8451ad..7404dce44 100644
--- a/src/dialogxml/dialogs/dialog.hpp
+++ b/src/dialogxml/dialogs/dialog.hpp
@@ -111,7 +111,7 @@ public:
/// @tparam type The result type.
/// @throw boost::bad_any_cast if the provided result type is different from the type set by getResult().
/// @return The dialog's result.
- template type getResult(){
+ template type getResult() const {
return boost::any_cast(result);
}
/// Set the result of the dialog.
@@ -134,13 +134,13 @@ public:
void setBg(short n);
/// Get the background pattern of the dialog.
/// @return The numeric index of the background pattern.
- short getBg();
+ short getBg() const;
/// Set the default text colour applied to new dialogs when loading from a file.
/// @param clr The text colour.
void setDefTextClr(sf::Color clr);
/// Get the default text colour applied to new dialogs when loading from a file.
/// @return The text colour.
- sf::Color getDefTextClr();
+ sf::Color getDefTextClr() const;
/// Set the focused text field.
/// @param newFocus A pointer to the text field to receive focus.
/// @param force If true, the change will be forced.
@@ -168,11 +168,11 @@ public:
void untoast();
/// Determine how the dialog exited.
/// @return the argument passed to toast() when the dialog was closed
- bool accepted();
+ bool accepted() const;
/// Check if a control exists with a given ID.
/// @param id The unique key of the control.
/// @return true if it exists.
- bool hasControl(std::string id);
+ bool hasControl(std::string id) const;
/// Get a reference to a control.
/// @param id The unique key of the control.
/// @throw std::invalid_argument if the control does not exist.
@@ -180,6 +180,8 @@ public:
cControl& getControl(std::string id);
/// @copydoc getControl()
cControl& operator[](std::string id);
+ /// @copydoc getControl()
+ const cControl& operator[](std::string id) const;
/// Recalculate the dialog's bounding rect.
/// Call this after adding controls to the dialog to ensure that the control is within the bounding rect.
void recalcRect();
@@ -208,7 +210,7 @@ public:
void attachFocusHandlers(std::function handler, std::vector controls);
/// Get the bounding rect of the dialog.
/// @return The dialog's bounding rect.
- rectangle getBounds() {return winRect;}
+ rectangle getBounds() const {return winRect;}
/// Send keyboard input to the frontmost dialog.
/// Currently, only text edit fields will respond to this.
/// @return true if there was a dialog opened to send to.
diff --git a/src/dialogxml/dialogs/pictchoice.cpp b/src/dialogxml/dialogs/pictchoice.cpp
index 19775a41d..ef590529c 100644
--- a/src/dialogxml/dialogs/pictchoice.cpp
+++ b/src/dialogxml/dialogs/pictchoice.cpp
@@ -146,14 +146,14 @@ bool cPictChoice::onSelect(bool losing) {
return true;
}
-pic_num_t cPictChoice::getPicChosen() {
+pic_num_t cPictChoice::getPicChosen() const {
return dlg.getResult>().first;
}
-ePicType cPictChoice::getPicChosenType() {
+ePicType cPictChoice::getPicChosenType() const {
return dlg.getResult>().second;
}
-size_t cPictChoice::getSelected() {
+size_t cPictChoice::getSelected() const {
return cur;
}
diff --git a/src/dialogxml/dialogs/pictchoice.hpp b/src/dialogxml/dialogs/pictchoice.hpp
index 81b3ef19f..503f10496 100644
--- a/src/dialogxml/dialogs/pictchoice.hpp
+++ b/src/dialogxml/dialogs/pictchoice.hpp
@@ -68,13 +68,13 @@ public:
bool show(size_t cur_sel);
/// Get the chosen icon.
/// @return The number of the chosen icon.
- pic_num_t getPicChosen();
+ pic_num_t getPicChosen() const;
/// Get the chosen icon.
/// @return The type of the chosen icon.
- ePicType getPicChosenType();
+ ePicType getPicChosenType() const;
/// Get the index of the selected icon in the original list.
/// @return The index
- size_t getSelected();
+ size_t getSelected() const;
};
#endif
diff --git a/src/dialogxml/dialogs/strdlog.cpp b/src/dialogxml/dialogs/strdlog.cpp
index 9ec346461..dc8203ff4 100644
--- a/src/dialogxml/dialogs/strdlog.cpp
+++ b/src/dialogxml/dialogs/strdlog.cpp
@@ -12,10 +12,11 @@
#include "tools/winutil.hpp"
#include "dialogxml/widgets/pict.hpp"
#include "fileio/resmgr/res_dialog.hpp"
+#include "mathutil.hpp"
DialogDefn& cStrDlog::getDefn(short n_strs, ePicType type, bool hasTitle){
std::ostringstream sout;
- sout << n_strs << "str";
+ sout << minmax(1, 2, n_strs) << "str";
if(hasTitle) sout << "-title";
if(type == PIC_DLOG_LG || type == PIC_CUSTOM_DLOG_LG || type == PIC_SCEN_LG)
sout << "-lg";
diff --git a/src/dialogxml/widgets/button.cpp b/src/dialogxml/widgets/button.cpp
index 7d02562b1..f709c35e5 100644
--- a/src/dialogxml/widgets/button.cpp
+++ b/src/dialogxml/widgets/button.cpp
@@ -36,15 +36,15 @@ cButton::cButton(cDialog& parent,eControlType t) :
fromList("none"),
wrapLabel(false) {/* This constructor is only called for LEDs. */}
-bool cButton::isClickable(){
+bool cButton::isClickable() const {
return true;
}
-bool cButton::isFocusable(){
+bool cButton::isFocusable() const {
return false;
}
-bool cButton::isScrollable(){
+bool cButton::isScrollable() const {
return false;
}
@@ -169,7 +169,7 @@ void cButton::validatePostParse(ticpp::Element& elem, std::string fname, const s
}
}
-location cButton::getPreferredSize() {
+location cButton::getPreferredSize() const {
return {btnRects[type][0].width(), btnRects[type][0].height()};
}
@@ -285,6 +285,6 @@ void cButton::setBtnType(eBtnType newType){
}
}
-eBtnType cButton::getBtnType(){
+eBtnType cButton::getBtnType() const {
return type;
}
diff --git a/src/dialogxml/widgets/button.hpp b/src/dialogxml/widgets/button.hpp
index 5804ee695..91be9a766 100644
--- a/src/dialogxml/widgets/button.hpp
+++ b/src/dialogxml/widgets/button.hpp
@@ -38,29 +38,29 @@ public:
bool parseAttribute(ticpp::Attribute& attr, std::string tagName, std::string fname) override;
bool parseContent(ticpp::Node& content, int n, std::string tagName, std::string fname, std::string& text) override;
void validatePostParse(ticpp::Element& elem, std::string fname, const std::set& attrs, const std::multiset& elems) override;
- location getPreferredSize() override;
+ location getPreferredSize() const override;
void recalcRect() override;
/// Set the type of this button.
/// @param newType The desired button type.
void setBtnType(eBtnType newType);
/// Get the type of this button.
/// @return The button type.
- eBtnType getBtnType();
+ eBtnType getBtnType() const;
/// Create a new button.
/// @param parent The parent dialog.
explicit cButton(cDialog& parent);
/// Create a button outside of a dialog
/// @param parent The parent window
explicit cButton(sf::RenderWindow& parent);
- bool isClickable() override;
- bool isFocusable() override;
- bool isScrollable() override;
+ bool isClickable() const override;
+ bool isFocusable() const override;
+ bool isScrollable() const override;
virtual ~cButton();
void draw() override;
/// @copydoc cControl::getSupportedHandlers
///
/// @todo Document possible handlers
- const std::set getSupportedHandlers() const override {
+ std::set getSupportedHandlers() const override {
return {EVT_CLICK};
}
cButton& operator=(cButton& other) = delete;
diff --git a/src/dialogxml/widgets/container.hpp b/src/dialogxml/widgets/container.hpp
index 9b5bc358c..11d16538f 100644
--- a/src/dialogxml/widgets/container.hpp
+++ b/src/dialogxml/widgets/container.hpp
@@ -34,7 +34,7 @@ public:
/// Check if a control exists with a given ID.
/// @param id The unique key of the control.
/// @return true if it exists.
- virtual bool hasChild(std::string id) = 0;
+ virtual bool hasChild(std::string id) const = 0;
/// Get a reference to a child control.
/// @param id The unique key of the control.
/// @throw std::invalid_argument if the control does not exist.
@@ -46,7 +46,8 @@ public:
virtual void forEach(std::function callback) = 0;
/// @copydoc getChild()
cControl& operator[](std::string id) {return getChild(id);}
- bool isContainer() override {return true;}
+ const cControl& operator[](std::string id) const {return const_cast(*this).getChild(id);}
+ bool isContainer() const override {return true;}
bool handleClick(location where) override;
};
diff --git a/src/dialogxml/widgets/control.cpp b/src/dialogxml/widgets/control.cpp
index a0ebf551b..f9d553db3 100644
--- a/src/dialogxml/widgets/control.cpp
+++ b/src/dialogxml/widgets/control.cpp
@@ -23,11 +23,11 @@ void cControl::setText(std::string l){
lbl = l;
}
-std::string cControl::getText(){
+std::string cControl::getText() const {
return lbl;
}
-rectangle cControl::getBounds() {
+rectangle cControl::getBounds() const {
return frame;
}
@@ -120,7 +120,7 @@ void cControl::hide(){
if(labelCtrl) labelCtrl->hide();
}
-bool cControl::isVisible(){
+bool cControl::isVisible() const {
if(!parent || parent->dialogNotToast)
return visible;
else return false;
@@ -130,7 +130,11 @@ void cControl::setLabelCtrl(cControl* label) {
labelCtrl = label;
}
-cKey cControl::getAttachedKey() {
+cControl* cControl::getLabelCtrl() {
+ return labelCtrl;
+}
+
+cKey cControl::getAttachedKey() const {
return key;
}
@@ -161,9 +165,9 @@ void cControl::setFormat(eFormat prop, short val) {
throw xUnsupportedProp(prop);
}
-short cControl::getFormat(eFormat prop) {
+short cControl::getFormat(eFormat prop) const {
boost::any curVal;
- if(!manageFormat(prop, false, &curVal))
+ if(!const_cast(*this).manageFormat(prop, false, &curVal))
throw xUnsupportedProp(prop);
switch(prop) {
case TXT_WRAP:
@@ -180,8 +184,8 @@ short cControl::getFormat(eFormat prop) {
return 0;
}
-bool cControl::canFormat(eFormat prop) {
- return manageFormat(prop, false, nullptr);
+bool cControl::canFormat(eFormat prop) const {
+ return const_cast(*this).manageFormat(prop, false, nullptr);
}
void cControl::setColour(sf::Color clr) {
@@ -190,9 +194,9 @@ void cControl::setColour(sf::Color clr) {
throw xUnsupportedProp(TXT_COLOUR);
}
-sf::Color cControl::getColour() {
+sf::Color cControl::getColour() const {
boost::any curVal;
- if(!manageFormat(TXT_COLOUR, false, &curVal))
+ if(!const_cast(*this).manageFormat(TXT_COLOUR, false, &curVal))
throw xUnsupportedProp(TXT_COLOUR);
return boost::any_cast(curVal);
}
@@ -238,7 +242,7 @@ bool cControl::handleClick(location){
return clicked;
}
-std::string cControl::getAttachedKeyDescription() {
+std::string cControl::getAttachedKeyDescription() const {
std::string s;
if(key.spec) {
auto mod = key.mod;
@@ -331,6 +335,12 @@ void cControl::attachFocusHandler(std::function
attachEventHandler(std::bind(f, _1, _2, true));
}
+bool cControl::haveHandler(eDlogEvt t) const {
+ auto iter = event_handlers.find(t);
+ if(iter == event_handlers.end()) return false;
+ return !iter->second.empty();
+}
+
bool cControl::triggerClickHandler(cDialog& dlg, std::string id, eKeyMod mods){
triggerEvent(dlg, id, mods);
return true;
@@ -548,29 +558,29 @@ void cControl::validatePostParse(ticpp::Element& elem, std::string fname, const
cControl::~cControl() {}
-eControlType cControl::getType(){
+eControlType cControl::getType() const {
return type;
}
-void cControl::setTextToNum(long long what){
+void cControl::setTextToNum(long long what, const std::string& label){
std::ostringstream sout;
- sout << what;
+ sout << label << what;
setText(sout.str());
}
-long long cControl::getTextAsNum(){
+long long cControl::getTextAsNum() const {
std::istringstream sin(getText());
long long n;
sin >> n;
return n;
}
-bool cControl::hasKey(){
+bool cControl::hasKey() const {
if(key.spec) return true;
return key.c != 0;
}
-cControl::storage_t cControl::store() {
+cControl::storage_t cControl::store() const {
storage_t storage;
storage["text"] = lbl;
storage["visible"] = visible;
diff --git a/src/dialogxml/widgets/control.hpp b/src/dialogxml/widgets/control.hpp
index 74d3c0caa..a77424512 100644
--- a/src/dialogxml/widgets/control.hpp
+++ b/src/dialogxml/widgets/control.hpp
@@ -155,14 +155,14 @@ public:
void detachKey();
/// Check if the control has an assigned keyboard shortcut.
/// @return true if a keyboard shortcut is assigned.
- bool hasKey();
+ bool hasKey() const;
/// Retrieve the control's current keyboard shortcut.
/// @return the currently-assigned keyboard shortcut.
/// @note You should first check that a shortcut is assigned using hasKey().
- cKey getAttachedKey();
+ cKey getAttachedKey() const;
/// Retrieve the control's current keyboard shortcut as a human-readable string.
/// @return the currently-assigned keyboard shortcut, or an empty string if none is assigned.
- std::string getAttachedKeyDescription();
+ std::string getAttachedKeyDescription() const;
/// Attach an event handler to this control.
/// @tparam t The type of event to attach.
/// @param handler The event handler function or functor. Its signature depends on the event type.
@@ -214,48 +214,46 @@ public:
/// Check if a handler is assigned for a given event.
/// @param t The type of event to check for.
/// @return True if one is assigned, false otherwise.
- bool haveHandler(eDlogEvt t) {
- return !event_handlers[t].empty();
- }
+ bool haveHandler(eDlogEvt t) const;
/// Trigger the click handler for this control.
/// @param me A reference to the current dialog.
/// @param id The unique key of this control.
/// @param mods The currently-held keyboard modifiers.
/// @return true if the event should continue, false if it should be cancelled.
- virtual bool triggerClickHandler(cDialog& me, std::string id, eKeyMod mods) final;
+ bool triggerClickHandler(cDialog& me, std::string id, eKeyMod mods);
/// Trigger the focus handler for this control.
/// @param me A reference to the current dialog.
/// @param id The unique key of this control.
/// @param losingFocus true if this control is losing focus, false if it is gaining focus.
/// @return true if the event should continue, false if it should be cancelled.
- virtual bool triggerFocusHandler(cDialog& me, std::string id, bool losingFocus) final;
+ bool triggerFocusHandler(cDialog& me, std::string id, bool losingFocus);
/// Make this control visible.
virtual void show(); // cd_activate_item true
/// Make this control invisible.
virtual void hide(); // cd_activate_item false
/// Check if this control is visible.
/// @return true if it's visible
- bool isVisible(); // cd_get_active
+ bool isVisible() const; // cd_get_active
/// Check if this control is a container which contains other controls.
/// @return true if it's a container
/// @note Generally you shouldn't override this. If you need a container, then
/// extend @ref cContainer instead of cControl.
- virtual bool isContainer() {return false;}
+ virtual bool isContainer() const {return false;}
/// Set if this control is active. A control is normally active when the mouse button is held down within its bounding rect.
/// @param active true if it should be active, false if not
void setActive(bool active); // "active" here means "selected", so if it's a button, draw it pressed
/// Get the type of this control
/// @return The type of control
- eControlType getType();
+ eControlType getType() const;
/// Set the control's text.
/// @param l The new text.
virtual void setText(std::string l);
/// Fetch the control's text.
/// @return The control's current text.
- virtual std::string getText();
+ virtual std::string getText() const;
/// Get the bounding rect of this control.
/// @return The control's bounding rect.
- rectangle getBounds();
+ rectangle getBounds() const;
/// Set the bounding rect of this control.
/// @param newBounds The new bounding rect.
void setBounds(rectangle newBounds);
@@ -263,7 +261,7 @@ public:
/// This can specify an exact preferred size or just a preferred width or height.
/// The preferred size is only used if the size is not specified in the XML.
/// @return The preferred size, or (0,0) if there is no preferred size.
- virtual location getPreferredSize() {return {0,0};}
+ virtual location getPreferredSize() const {return {0,0};}
/// Set the position of this control.
/// @param to The new position.
void relocate(location to);
@@ -276,10 +274,12 @@ public:
void relocateRelative(location to, cControl* anchor, ePosition horz, ePosition vert);
/// Get the control's text as an integer.
/// @return The control's text, coerced to an integer.
- long long getTextAsNum();
+ long long getTextAsNum() const;
/// Set the control's text to an integer value.
/// @param what The desired value.
- void setTextToNum(long long what);
+ /// @param label This label will be prefixed to the value.
+ /// @note If a label is used, then @a getTextAsNum will not work to retrieve the value.
+ void setTextToNum(long long what, const std::string& label = "");
/// Set one of the control's formatting parameters.
/// @param prop The parameter to set.
/// @param val The desired value of the parameter.
@@ -289,11 +289,11 @@ public:
/// @param prop The parameter to retrieve.
/// @return The value of the parameter.
/// @throw xUnsupportedProp if this control doesn't support the given parameter.
- short getFormat(eFormat prop);
+ short getFormat(eFormat prop) const;
/// Test if the control supports a given formatting parameter
/// @param prop The parameter to check.
/// @return true if supported, false if not.
- bool canFormat(eFormat prop);
+ bool canFormat(eFormat prop) const;
/// Set the control's colour (usually text colour).
/// @param clr The desired colour.
/// @throw xUnsupportedProp if this control does not support colour.
@@ -301,24 +301,24 @@ public:
/// Get the control's colour.
/// @return The current colour.
/// @throw xUnsupportedProp if this control does not support colour.
- sf::Color getColour();
+ sf::Color getColour() const;
/// Test if the control supports colour
/// @return true if supported, false if not.
- bool canColour();
+ bool canColour() const;
/// Check if the control is clickable.
/// @return true if it's clickable.
/// @note This does not indicate whether the control supports click handlers.
/// In fact, some controls return true only if a click handler is assigned.
/// Others, like editable text fields, are clickable but do not support click handlers.
- virtual bool isClickable() = 0;
+ virtual bool isClickable() const = 0;
/// Check if the control is focusable.
/// @return true if it's focusable.
/// @note This does not indicate whether the control supports focus and defocus handlers.
- virtual bool isFocusable() = 0;
+ virtual bool isFocusable() const = 0;
/// Check if the control is scrollable.
/// @return true if it's scrollable.
/// @note This does not indicate whether the control supports scroll handlers.
- virtual bool isScrollable() = 0;
+ virtual bool isScrollable() const = 0;
/// Handles the action of clicking this control.
/// @param where The exact location at which the mouse was pressed, relative to the dialog.
/// @return true if the click was successful; false if it was cancelled.
@@ -333,9 +333,11 @@ public:
/// The practical effect of this is that hiding or showing this control automatically hides or shows the label as well.
/// @param label A pointer to the control that acts as a label.
void setLabelCtrl(cControl* label);
+ /// Get the control that serves as a label for this one, if any.
+ cControl* getLabelCtrl();
/// Get a view of the control's current state.
/// @return A map of string keys to boost::any values, representing the control's state.
- virtual storage_t store();
+ virtual storage_t store() const;
/// Restore the control to a previous state.
/// @param to A state previously returned from store()
virtual void restore(storage_t to);
@@ -362,7 +364,7 @@ protected:
///
/// See the documentation of this method in subclasses for explanations of what handlers
/// each control supports and how those handlers work for that control.
- virtual const std::set getSupportedHandlers() const = 0;
+ virtual std::set getSupportedHandlers() const = 0;
/// Called when a click event is triggered on this control. Override this to
/// customize the behaviour of clicks on the control. Note that, if you override it, you are
/// responsible for calling the passed handler, if it exists. (Test for existance with operator!.)
diff --git a/src/dialogxml/widgets/field.cpp b/src/dialogxml/widgets/field.cpp
index d8f38e3d3..b5a672f1b 100644
--- a/src/dialogxml/widgets/field.cpp
+++ b/src/dialogxml/widgets/field.cpp
@@ -187,19 +187,19 @@ void cTextField::setInputType(eFldType type) {
field_type = type;
}
-bool cTextField::isClickable(){
+bool cTextField::isClickable() const {
return true;
}
-bool cTextField::isFocusable(){
+bool cTextField::isFocusable() const {
return true;
}
-bool cTextField::isScrollable(){
+bool cTextField::isScrollable() const {
return false;
}
-bool cTextField::hasFocus() {
+bool cTextField::hasFocus() const {
return haveFocus;
}
@@ -326,6 +326,7 @@ static cKey divineFunction(cKey key) {
This is done to more closely emulate native Mac behaviour.
The Insert and Shift-Delete combos are included to more closely emulate
native Windows behaviour.
+ For Linux, we provide the same behaviour as Windows.
*/
if(!key.spec) {
if(mod_contains(key.mod, mod_ctrl)) {
@@ -722,7 +723,7 @@ void aTextDelete::append_back(char c) {
end++;
}
-cControl::storage_t cTextField::store() {
+cControl::storage_t cTextField::store() const {
storage_t storage = cControl::store();
storage["fld-ip"] = insertionPoint;
storage["fld-sp"] = selectionPoint;
diff --git a/src/dialogxml/widgets/field.hpp b/src/dialogxml/widgets/field.hpp
index 01194a0b4..447c3d8e3 100644
--- a/src/dialogxml/widgets/field.hpp
+++ b/src/dialogxml/widgets/field.hpp
@@ -39,12 +39,12 @@ public:
/// @copydoc cControl::getSupportedHandlers
///
/// @todo Document possible handlers
- const std::set getSupportedHandlers() const override {
+ std::set getSupportedHandlers() const override {
return {EVT_FOCUS, EVT_DEFOCUS};
}
bool handleClick(location where) override;
void setText(std::string to) override;
- storage_t store() override;
+ storage_t store() const override;
void restore(storage_t to) override;
/// Get the current input type of the field.
/// @return The input type.
@@ -55,14 +55,14 @@ public:
/// Create a new editable text field.
/// @param parent The parent dialog.
explicit cTextField(cDialog& parent);
- bool isClickable() override;
- bool isFocusable() override;
- bool isScrollable() override;
+ bool isClickable() const override;
+ bool isFocusable() const override;
+ bool isScrollable() const override;
virtual ~cTextField();
void draw() override;
/// Check if this text field currently has input focus.
/// @return true if it it is currently focused.
- bool hasFocus();
+ bool hasFocus() const;
/// Handle keyboard input.
/// @param key The keypress to handle.
void handleInput(cKey key);
diff --git a/src/dialogxml/widgets/led.cpp b/src/dialogxml/widgets/led.cpp
index e435d999d..6c1210f0f 100644
--- a/src/dialogxml/widgets/led.cpp
+++ b/src/dialogxml/widgets/led.cpp
@@ -110,7 +110,7 @@ void cLed::draw(){
inWindow->setActive();
}
-cControl::storage_t cLed::store() {
+cControl::storage_t cLed::store() const {
storage_t storage = cButton::store();
storage["led-state"] = getState();
return storage;
@@ -129,7 +129,7 @@ void cLed::setState(eLedState to){
state = to;
}
-eLedState cLed::getState(){
+eLedState cLed::getState() const {
return state;
}
@@ -151,6 +151,6 @@ bool cLed::parseContent(ticpp::Node& content, int n, std::string tagName, std::s
return cButton::parseContent(content, n, tagName, fname, text);
}
-location cLed::getPreferredSize() {
+location cLed::getPreferredSize() const {
return {ledRects[0][0].width(), ledRects[0][0].height()};
}
diff --git a/src/dialogxml/widgets/led.hpp b/src/dialogxml/widgets/led.hpp
index 738a41f34..7223f6c36 100644
--- a/src/dialogxml/widgets/led.hpp
+++ b/src/dialogxml/widgets/led.hpp
@@ -32,8 +32,8 @@ public:
static bool noAction(cDialog&,std::string,eKeyMod) {return true;}
bool parseAttribute(ticpp::Attribute& attr, std::string tagName, std::string fname) override;
bool parseContent(ticpp::Node& content, int n, std::string tagName, std::string fname, std::string& text) override;
- location getPreferredSize() override;
- storage_t store() override;
+ location getPreferredSize() const override;
+ storage_t store() const override;
void restore(storage_t to) override;
/// Create a new LED button.
/// @param parent The parent dialog.
@@ -44,12 +44,12 @@ public:
void setState(eLedState to);
/// Get the LED's current state.
/// @return The current state.
- eLedState getState();
+ eLedState getState() const;
void draw() override;
/// @copydoc cControl::getSupportedHandlers
///
/// @todo Document possible handlers
- const std::set getSupportedHandlers() const override {
+ std::set getSupportedHandlers() const override {
return {EVT_CLICK, EVT_FOCUS, EVT_DEFOCUS};
}
cLed& operator=(cLed& other) = delete;
diff --git a/src/dialogxml/widgets/ledgroup.cpp b/src/dialogxml/widgets/ledgroup.cpp
index 02579686a..6860bcb13 100644
--- a/src/dialogxml/widgets/ledgroup.cpp
+++ b/src/dialogxml/widgets/ledgroup.cpp
@@ -131,19 +131,19 @@ void cLedGroup::hide(std::string id){
choices[id]->hide();
}
-bool cLedGroup::isClickable(){
+bool cLedGroup::isClickable() const {
return true;
}
-bool cLedGroup::isScrollable(){
+bool cLedGroup::isScrollable() const {
return false;
}
-bool cLedGroup::isFocusable(){
+bool cLedGroup::isFocusable() const {
return false;
}
-bool cLedGroup::hasChild(std::string id) {
+bool cLedGroup::hasChild(std::string id) const {
return choices.find(id) != choices.end();
}
@@ -193,11 +193,11 @@ void cLedGroup::setSelected(std::string id){
}
}
-std::string cLedGroup::getSelected(){
+std::string cLedGroup::getSelected() const {
return curSelect;
}
-std::string cLedGroup::getPrevSelection(){
+std::string cLedGroup::getPrevSelection() const {
return prevSelect;
}
@@ -211,7 +211,7 @@ void cLedGroup::draw(){
drawFrame(2, frameStyle);
}
-cControl::storage_t cLedGroup::store() {
+cControl::storage_t cLedGroup::store() const {
storage_t storage = cControl::store();
storage["led-select"] = getSelected();
return storage;
diff --git a/src/dialogxml/widgets/ledgroup.hpp b/src/dialogxml/widgets/ledgroup.hpp
index 3d8b40471..4914b56c1 100644
--- a/src/dialogxml/widgets/ledgroup.hpp
+++ b/src/dialogxml/widgets/ledgroup.hpp
@@ -53,10 +53,10 @@ public:
/// The third parameter is always false for an LED group's focus handler.
/// You can determine what changed using getPrevSelection() and getSelected(), and can do whatever post-processing
/// you want, including selecting a completely different option.
- const std::set getSupportedHandlers() const override {
+ std::set getSupportedHandlers() const override {
return {EVT_CLICK, EVT_FOCUS};
}
- storage_t store() override;
+ storage_t store() const override;
void restore(storage_t to) override;
/// Add a new LED to this group.
/// @param ctrl A pointer to the LED, which should already be constructed.
@@ -80,9 +80,9 @@ public:
/// Create a new LED group.
/// @param parent The parent dialog.
explicit cLedGroup(cDialog& parent);
- bool isClickable() override;
- bool isFocusable() override;
- bool isScrollable() override;
+ bool isClickable() const override;
+ bool isFocusable() const override;
+ bool isScrollable() const override;
bool handleClick(location where) override;
virtual ~cLedGroup();
/// Get one of the LEDs in this group.
@@ -90,20 +90,20 @@ public:
/// @return A reference to the LED object.
/// @throw std::invalid_argument if the choice does not exist in the group.
cLed& getChild(std::string id) override;
- bool hasChild(std::string id) override;
+ bool hasChild(std::string id) const override;
/// Set the currently selected LED in this group.
/// @param id The unique key of the choice.
/// @throw std::invalid_argument if the choice does not exist in the group.
void setSelected(std::string id);
/// Get the currently selected choice.
/// @return id The unique key of the choice.
- std::string getSelected();
+ std::string getSelected() const;
/// Get the previously selected choice.
/// @return id The unique key of the choice.
/// @note This is intended for use by focus handlers.
///
/// This refers to the element that was last selected before the selection changed to the current selection.
- std::string getPrevSelection();
+ std::string getPrevSelection() const;
/// Recalculate the LED group's bounding rect.
/// Call this after adding choices to the group to ensure that the choice is within the bounding rect.
/// If a choice is not within the bounding rect, it will not respond to clicks.
diff --git a/src/dialogxml/widgets/message.cpp b/src/dialogxml/widgets/message.cpp
index 39bee37d1..5a70c1599 100644
--- a/src/dialogxml/widgets/message.cpp
+++ b/src/dialogxml/widgets/message.cpp
@@ -171,15 +171,15 @@ cTextMsg::cTextMsg(sf::RenderWindow& parent) :
setFormat(TXT_FRAME, FRM_NONE);
}
-bool cTextMsg::isClickable(){
+bool cTextMsg::isClickable() const {
return haveHandler(EVT_CLICK);
}
-bool cTextMsg::isFocusable(){
+bool cTextMsg::isFocusable() const {
return false;
}
-bool cTextMsg::isScrollable(){
+bool cTextMsg::isScrollable() const {
return false;
}
diff --git a/src/dialogxml/widgets/message.hpp b/src/dialogxml/widgets/message.hpp
index 44a59751e..0efd30af4 100644
--- a/src/dialogxml/widgets/message.hpp
+++ b/src/dialogxml/widgets/message.hpp
@@ -33,9 +33,9 @@ public:
/// Create a new text message without a parent dialog.
/// @param parent The parent window.
explicit cTextMsg(sf::RenderWindow& parent);
- bool isClickable() override;
- bool isFocusable() override;
- bool isScrollable() override;
+ bool isClickable() const override;
+ bool isFocusable() const override;
+ bool isScrollable() const override;
void setFixed(bool w, bool h);
virtual ~cTextMsg();
void draw() override;
@@ -43,7 +43,7 @@ public:
/// @copydoc cControl::getSupportedHandlers
///
/// @todo Document possible handlers
- const std::set getSupportedHandlers() const override {
+ std::set getSupportedHandlers() const override {
return {EVT_CLICK};
}
cTextMsg& operator=(cTextMsg& other) = delete;
diff --git a/src/dialogxml/widgets/pict.cpp b/src/dialogxml/widgets/pict.cpp
index 6353eaaa3..f1bd9dad1 100644
--- a/src/dialogxml/widgets/pict.cpp
+++ b/src/dialogxml/widgets/pict.cpp
@@ -18,6 +18,7 @@
#include "gfx/tiling.hpp"
#include "location.hpp"
#include "dialogxml/dialogs/dialog.hpp"
+#include "dialogxml/dialogs/strdlog.hpp"
#include "fileio/resmgr/res_image.hpp"
extern sf::Texture bg_gworld;
@@ -96,6 +97,8 @@ bool cPict::manageFormat(eFormat prop, bool set, boost::any* val) {
}
void cPict::setPict(pic_num_t num, ePicType type){
+ sheetCached.reset();
+ sheetCachedType = NUM_SHEET_TYPES;
picNum = num;
picType = type;
if(picType == PIC_MONST && picNum < 1000) {
@@ -108,6 +111,8 @@ void cPict::setPict(pic_num_t num, ePicType type){
picType += PIC_PARTY;
} else {
picType += PIC_CUSTOM;
+ if(picNum >= 2000 && picType == PIC_CUSTOM_TER)
+ picType = PIC_CUSTOM_TER_ANIM;
if(picType != PIC_CUSTOM_TER_MAP)
picNum %= 1000;
}
@@ -121,11 +126,11 @@ void cPict::setPict(pic_num_t num) {
else setPict(num, picType - PIC_CUSTOM);
}
-pic_num_t cPict::getPicNum(){
+pic_num_t cPict::getPicNum() const {
return picNum;
}
-ePicType cPict::getPicType(){
+ePicType cPict::getPicType() const {
return picType;
}
@@ -139,15 +144,15 @@ cPict::cPict(sf::RenderWindow& parent) :
setFormat(TXT_FRAME, FRM_SOLID);
}
-bool cPict::isClickable(){
+bool cPict::isClickable() const {
return haveHandler(EVT_CLICK);
}
-bool cPict::isFocusable(){
+bool cPict::isFocusable() const {
return false;
}
-bool cPict::isScrollable(){
+bool cPict::isScrollable() const {
return false;
}
@@ -586,6 +591,16 @@ void cPict::recalcRect() {
}
std::shared_ptr cPict::getSheet(eSheetType type, size_t n) {
+ if(type == sheetCachedType && n == sheetCachedNum) {
+ return sheetCached;
+ }
+ sheetCachedType = type;
+ sheetCachedNum = n;
+ sheetCached = getSheetInternal(type, n);
+ return sheetCached;
+}
+
+std::shared_ptr cPict::getSheetInternal(eSheetType type, size_t n) {
std::ostringstream sout;
bool purgeable = false;
switch(type) {
@@ -672,7 +687,13 @@ std::shared_ptr cPict::getSheet(eSheetType type, size_t n) {
sout << "sheet" << n;
}
}
- return &ResMgr::graphics.get(sout.str(), purgeable);
+ auto name = sout.str();
+ try {
+ return &ResMgr::graphics.get(name, purgeable);
+ } catch(ResMgr::xError& e) {
+ showError(e.what());
+ return nullptr;
+ }
}
void cPict::draw(){
@@ -690,6 +711,10 @@ void cPict::draw(){
}
void cPict::drawPresetTer(short num, rectangle to_rect){
+ if(num >= 960) {
+ drawPresetTerAnim(num - 960, to_rect);
+ return;
+ }
auto from_gw = getSheet(SHEET_TER, num / 50);
if(!from_gw) return;
num = num % 50;
@@ -702,6 +727,7 @@ void cPict::drawPresetTer(short num, rectangle to_rect){
void cPict::drawPresetTerAnim(short num, rectangle to_rect){
rectangle from_rect = calc_rect(4 * (num / 5) + animFrame % 4, num % 5);
auto from_gw = getSheet(SHEET_TER_ANIM);
+ if(!from_gw) return;
if(to_rect.right - to_rect.left > 28) {
to_rect.inset(4,0);
to_rect.right = to_rect.left + 28;
@@ -1282,7 +1308,7 @@ void cPict::drawAt(sf::RenderWindow& win, rectangle dest, pic_num_t which_g, ePi
pic.draw();
}
-cControl::storage_t cPict::store() {
+cControl::storage_t cPict::store() const {
storage_t storage = cControl::store();
storage["pic-num"] = picNum;
storage["pic-type"] = picType;
diff --git a/src/dialogxml/widgets/pict.hpp b/src/dialogxml/widgets/pict.hpp
index 5b27b2f60..2e173937e 100644
--- a/src/dialogxml/widgets/pict.hpp
+++ b/src/dialogxml/widgets/pict.hpp
@@ -29,7 +29,7 @@ public:
bool parseAttribute(ticpp::Attribute& attr, std::string tagName, std::string fname) override;
void validatePostParse(ticpp::Element& who, std::string fname, const std::set& attrs, const std::multiset& nodes) override;
bool manageFormat(eFormat prop, bool set, boost::any* val) override;
- storage_t store() override;
+ storage_t store() const override;
void restore(storage_t to) override;
/// @copydoc setPict(pic_num_t)
/// @param type The type of the new icon
@@ -51,19 +51,19 @@ public:
void recalcRect() override;
/// Get the current icon.
/// @return The number of the current icon.
- pic_num_t getPicNum();
+ pic_num_t getPicNum() const;
/// Get the current icon's type.
/// @return The type of the current icon.
- ePicType getPicType();
+ ePicType getPicType() const;
/// Create a new icon.
/// @param parent The parent dialog.
explicit cPict(cDialog& parent);
/// Create a new icon without a parent dialog.
/// @param parent The parent window.
explicit cPict(sf::RenderWindow& parent);
- bool isClickable() override;
- bool isFocusable() override;
- bool isScrollable() override;
+ bool isClickable() const override;
+ bool isFocusable() const override;
+ bool isScrollable() const override;
/// Advance the current animation frame.
/// Should be called at predictable intervals if the dialog might contain an animated graphic.
static void advanceAnim();
@@ -82,13 +82,17 @@ public:
/// @copydoc cControl::getSupportedHandlers
///
/// @todo Document possible handlers
- const std::set getSupportedHandlers() const override {
+ std::set getSupportedHandlers() const override {
return {EVT_CLICK};
}
cPict& operator=(cPict& other) = delete;
cPict(cPict& other) = delete;
private:
- static std::shared_ptr getSheet(eSheetType type, size_t n = 0);
+ static std::shared_ptr getSheetInternal(eSheetType type, size_t n);
+ std::shared_ptr getSheet(eSheetType type, size_t n = 0);
+ std::shared_ptr sheetCached;
+ eSheetType sheetCachedType;
+ size_t sheetCachedNum;
static short animFrame;
pic_num_t picNum;
ePicType picType;
diff --git a/src/dialogxml/widgets/scrollbar.cpp b/src/dialogxml/widgets/scrollbar.cpp
index f5c60b138..bd4b311b7 100644
--- a/src/dialogxml/widgets/scrollbar.cpp
+++ b/src/dialogxml/widgets/scrollbar.cpp
@@ -26,15 +26,15 @@ cScrollbar::cScrollbar(sf::RenderWindow& parent) : cControl(CTRL_SCROLL, parent)
void cScrollbar::init() {
}
-bool cScrollbar::isClickable(){
+bool cScrollbar::isClickable() const {
return true;
}
-bool cScrollbar::isFocusable(){
+bool cScrollbar::isFocusable() const {
return false;
}
-bool cScrollbar::isScrollable(){
+bool cScrollbar::isScrollable() const {
return true;
}
@@ -67,27 +67,27 @@ void cScrollbar::set_wheel_event_rect(rectangle rect) {
this->wheel_event_rect = rect;
}
-long cScrollbar::getPosition() {
+long cScrollbar::getPosition() const {
return pos;
}
-long cScrollbar::getMaximum() {
+long cScrollbar::getMaximum() const {
return max;
}
-long cScrollbar::getPageSize() {
+long cScrollbar::getPageSize() const {
return pgsz;
}
-bool cScrollbar::isVertical() {
+bool cScrollbar::isVertical() const {
return vert;
}
-std::string cScrollbar::getLink() {
+std::string cScrollbar::getLink() const {
return link;
}
-eScrollStyle cScrollbar::getStyle() {
+eScrollStyle cScrollbar::getStyle() const {
return style;
}
@@ -354,23 +354,6 @@ bool cScrollbar::handleClick(location where) {
return clicked;
}
-void cScrollbar::setFormat(eFormat prop, short) {
- throw xUnsupportedProp(prop);
-}
-
-short cScrollbar::getFormat(eFormat prop) {
- throw xUnsupportedProp(prop);
-}
-
-void cScrollbar::setColour(sf::Color) {
- // TODO: Colour is unsupported
-}
-
-sf::Color cScrollbar::getColour() {
- // TODO: Colour is unsupported
- return sf::Color();
-}
-
const rectangle cScrollbar::up_rect[NUM_STYLES][4] = {
{{0,0,16,16}, {16,0,32,16}, {32,0,48,16}, {48,0,64,16}},
{{0,0,10,14}, {10,0,20,14}, {20,0,34,10}, {34,0,48,10}},
@@ -583,12 +566,12 @@ void cScrollbar::validatePostParse(ticpp::Element& who, std::string fname, const
parent->getControl(link).setTextToNum(pos);
}
-location cScrollbar::getPreferredSize() {
+location cScrollbar::getPreferredSize() const {
if(vert) return {up_rect[style][VERT].width(), 0};
else return {0, up_rect[style][HORZ].height()};
}
-cControl::storage_t cScrollbar::store() {
+cControl::storage_t cScrollbar::store() const {
storage_t storage = cControl::store();
storage["scroll-pos"] = pos;
storage["scroll-max"] = max;
diff --git a/src/dialogxml/widgets/scrollbar.hpp b/src/dialogxml/widgets/scrollbar.hpp
index 7a45c3d75..adad279ad 100644
--- a/src/dialogxml/widgets/scrollbar.hpp
+++ b/src/dialogxml/widgets/scrollbar.hpp
@@ -66,7 +66,7 @@ public:
static void init();
bool parseAttribute(ticpp::Attribute& attr, std::string tagName, std::string fname) override;
void validatePostParse(ticpp::Element& who, std::string fname, const std::set& attrs, const std::multiset& nodes) override;
- location getPreferredSize() override;
+ location getPreferredSize() const override;
/// Create a new scrollbar without a parent dialog.
/// @param parent The parent window.
explicit cScrollbar(sf::RenderWindow& parent);
@@ -74,39 +74,35 @@ public:
/// @param parent The parent dialog.
explicit cScrollbar(cDialog& parent);
bool handleClick(location where) override;
- void setFormat(eFormat prop, short val);
- short getFormat(eFormat prop);
- void setColour(sf::Color clr);
- sf::Color getColour();
- storage_t store() override;
+ storage_t store() const override;
void restore(storage_t to) override;
- bool isClickable() override;
- bool isFocusable() override;
- bool isScrollable() override;
+ bool isClickable() const override;
+ bool isFocusable() const override;
+ bool isScrollable() const override;
/// Get the scrollbar thumb's current position.
/// @return The current position.
- long getPosition();
+ long getPosition() const;
/// Get the scrollbar thumb's maximum value.
/// @return The maximum value.
- long getMaximum();
+ long getMaximum() const;
/// Get the scrollbar thumb's page size.
/// @return The page size.
///
/// The page size is the number of steps scrolled when a click is received
/// in the area between the arrow buttons and the scrollbar thumb.
- long getPageSize();
+ long getPageSize() const;
/// Check whether the scrollbar is vertical.
/// @return True if it is vertical, false if it is horizontal.
- bool isVertical();
+ bool isVertical() const;
/// Get the linked control.
///
/// A linked control is one that always reflect's the scrollbar's current
/// value as its text.
/// @return The ID of the linked control, or an empty string if none.
- std::string getLink();
+ std::string getLink() const;
/// Get the scrollbar style.
/// @return The style
- eScrollStyle getStyle();
+ eScrollStyle getStyle() const;
/// Set the scrollbar thumb's current position.
/// @param to The new position.
void setPosition(long to);
@@ -137,7 +133,7 @@ public:
/// @copydoc cControl::getSupportedHandlers
///
/// @todo Document possible handlers
- const std::set getSupportedHandlers() const override {
+ std::set getSupportedHandlers() const override {
return {EVT_CLICK, EVT_SCROLL};
}
cScrollbar& operator=(cScrollbar& other) = delete;
diff --git a/src/dialogxml/widgets/scrollpane.cpp b/src/dialogxml/widgets/scrollpane.cpp
index e3fe50a21..29b7b0407 100644
--- a/src/dialogxml/widgets/scrollpane.cpp
+++ b/src/dialogxml/widgets/scrollpane.cpp
@@ -71,7 +71,7 @@ bool cScrollPane::manageFormat(eFormat prop, bool set, boost::any* val) {
return true;
}
-cControl::storage_t cScrollPane::store() {
+cControl::storage_t cScrollPane::store() const {
// We don't call the superclass store() here like other controls do
storage_t storage;
storage[""] = scroll.store();
@@ -90,23 +90,23 @@ void cScrollPane::restore(storage_t to) {
}
}
-bool cScrollPane::isClickable() {
+bool cScrollPane::isClickable() const {
return true;
}
-bool cScrollPane::isFocusable() {
+bool cScrollPane::isFocusable() const {
return false;
}
-bool cScrollPane::isScrollable() {
+bool cScrollPane::isScrollable() const {
return true;
}
-long cScrollPane::getPosition() {
+long cScrollPane::getPosition() const {
return scroll.getPosition();
}
-long cScrollPane::getMaximum() {
+long cScrollPane::getMaximum() const {
return scroll.getMaximum();
}
@@ -114,7 +114,7 @@ void cScrollPane::setPosition(long to) {
scroll.setPosition(to);
}
-eScrollStyle cScrollPane::getStyle() {
+eScrollStyle cScrollPane::getStyle() const {
return scroll.getStyle();
}
@@ -122,7 +122,7 @@ void cScrollPane::setStyle(eScrollStyle style) {
scroll.setStyle(style);
}
-bool cScrollPane::hasChild(std::string id) {
+bool cScrollPane::hasChild(std::string id) const {
return contents.find(id) != contents.end();
}
diff --git a/src/dialogxml/widgets/scrollpane.hpp b/src/dialogxml/widgets/scrollpane.hpp
index 57fe834e2..1508190fa 100644
--- a/src/dialogxml/widgets/scrollpane.hpp
+++ b/src/dialogxml/widgets/scrollpane.hpp
@@ -29,13 +29,13 @@ public:
bool parseContent(ticpp::Node& content, int n, std::string tagName, std::string fname, std::string& text) override;
void validatePostParse(ticpp::Element& who, std::string fname, const std::set& attrs, const std::multiset& nodes) override;
bool handleClick(location where) override;
- bool hasChild(std::string id) override;
+ bool hasChild(std::string id) const override;
cControl& getChild(std::string id) override;
- storage_t store() override;
+ storage_t store() const override;
void restore(storage_t to) override;
- bool isClickable() override;
- bool isFocusable() override;
- bool isScrollable() override;
+ bool isClickable() const override;
+ bool isFocusable() const override;
+ bool isScrollable() const override;
/// Add a new control to this pane.
/// @param ctrl A pointer to the control, which should already be constructed.
/// @param key A key to be used to look up the control later.
@@ -45,16 +45,16 @@ public:
void recalcRect() override;
/// Get the pane's current scroll position.
/// @return The current position.
- long getPosition();
+ long getPosition() const;
/// Get the pane's maximum scroll position.
/// @return The maximum value.
- long getMaximum();
+ long getMaximum() const;
/// Set the pane's current scroll position.
/// @param to The new position.
void setPosition(long to);
/// Get the scrollbar style.
/// @return The style
- eScrollStyle getStyle();
+ eScrollStyle getStyle() const;
/// Set the scrollbar style.
/// @param newStyle The new style.
void setStyle(eScrollStyle newStyle);
@@ -62,7 +62,7 @@ public:
/// @copydoc cControl::getSupportedHandlers
///
/// @todo Document possible handlers
- const std::set getSupportedHandlers() const override {
+ std::set getSupportedHandlers() const override {
return {EVT_CLICK, EVT_SCROLL, EVT_FOCUS, EVT_DEFOCUS};
}
void forEach(std::function callback) override;
diff --git a/src/dialogxml/widgets/stack.cpp b/src/dialogxml/widgets/stack.cpp
index c9f213680..6a51c47eb 100644
--- a/src/dialogxml/widgets/stack.cpp
+++ b/src/dialogxml/widgets/stack.cpp
@@ -15,7 +15,7 @@
#include "scrollbar.hpp"
#include
-bool cStack::hasChild(std::string id) {
+bool cStack::hasChild(std::string id) const {
return controls.find(id) != controls.end();
}
@@ -38,15 +38,15 @@ bool cStack::manageFormat(eFormat prop, bool set, boost::any* val) {
return true;
}
-bool cStack::isClickable() {
+bool cStack::isClickable() const {
return true;
}
-bool cStack::isFocusable() {
+bool cStack::isFocusable() const {
return false;
}
-bool cStack::isScrollable() {
+bool cStack::isScrollable() const {
return false;
}
@@ -84,7 +84,7 @@ bool cStack::setPage(size_t n) {
return !failed;
}
-size_t cStack::getPage() {
+size_t cStack::getPage() const {
return curPage;
}
@@ -109,7 +109,7 @@ void cStack::addPage() {
setPageCount(getPageCount() + 1);
}
-size_t cStack::getPageCount() {
+size_t cStack::getPageCount() const {
return nPages;
}
diff --git a/src/dialogxml/widgets/stack.hpp b/src/dialogxml/widgets/stack.hpp
index 2aded01b2..6da6394ef 100644
--- a/src/dialogxml/widgets/stack.hpp
+++ b/src/dialogxml/widgets/stack.hpp
@@ -47,11 +47,11 @@ public:
bool parseAttribute(ticpp::Attribute& attr, std::string tagName, std::string fname) override;
bool parseContent(ticpp::Node& content, int n, std::string tagName, std::string fname, std::string& text) override;
void validatePostParse(ticpp::Element& who, std::string fname, const std::set& attrs, const std::multiset& nodes) override;
- bool isClickable() override;
- bool isFocusable() override;
- bool isScrollable() override;
+ bool isClickable() const override;
+ bool isFocusable() const override;
+ bool isScrollable() const override;
void draw() override;
- bool hasChild(std::string id) override;
+ bool hasChild(std::string id) const override;
cControl& getChild(std::string id) override;
/// Switch the stack to a particular page.
/// You need to do this before retrieving data from that page.
@@ -60,7 +60,7 @@ public:
bool setPage(size_t n);
/// Get the current page the stack is displaying.
/// @return The current page number
- size_t getPage();
+ size_t getPage() const;
/// Set the number of pages in the stack.
/// @param n The new number of pages
/// @note If you reduce the number of pages, some data will be destroyed.
@@ -74,7 +74,7 @@ public:
void applyTemplate(const std::string& name);
// Get the number of pages in the stack.
/// @return The number of pages
- size_t getPageCount();
+ size_t getPageCount() const;
/// Recalculate the stack's bounding rect based on its contained controls.
void recalcRect() override;
/// Adds any fields in this stack to the tab order building arrays.
@@ -86,7 +86,7 @@ public:
/// @copydoc cControl::getSupportedHandlers
///
/// @todo Document possible handlers
- const std::set getSupportedHandlers() const override {
+ std::set getSupportedHandlers() const override {
return {EVT_CLICK, EVT_FOCUS, EVT_DEFOCUS};
}
void forEach(std::function callback) override;
diff --git a/src/fileio/fileio.cpp b/src/fileio/fileio.cpp
index 3bc024334..ebf85f99e 100644
--- a/src/fileio/fileio.cpp
+++ b/src/fileio/fileio.cpp
@@ -128,37 +128,49 @@ std::string read_maybe_quoted_string(std::istream& from) {
from >> std::ws;
if(from.peek() == '"' || from.peek() == '\'') {
char delim = from.get();
- getline(from, result, delim);
- if(result.empty()) return result;
- while(result[result.length() - 1] == '\\') {
- result[result.length() - 1] = delim;
+ bool reached_end = true;
+ do {
std::string nextPart;
getline(from, nextPart, delim);
+ if(!nextPart.empty() && nextPart.back() == '\\') {
+ nextPart.back() = delim;
+ reached_end = false;
+ } else {
+ reached_end = true;
+ }
// Collapse any double backslashes; remove any single backslashes
for(std::string::iterator iter = nextPart.begin(); iter != nextPart.end(); iter++) {
- if(iter[0] == '\\' && iter + 1 != nextPart.end() && iter[1] != '\\') {
+ if(iter[0] == '\\' && iter + 1 != nextPart.end()) {
iter = nextPart.erase(iter);
// After this, iter points to the second of the two backslashes, so
// when incremented by the loop, it'll point to the character after the backslashes.
+ // However! It might also be pointing at an n, t, or f, so substitute that if so.
+ switch(*iter) {
+ case 'n': *iter = '\n'; break;
+ case 't': *iter = '\t'; break;
+ case 'f': *iter = '\f'; break;
+ }
}
}
// Note that this does not support escaping the single quotes in strings delimited by double quotes, and vice versa.
result += nextPart;
- }
+ } while(!reached_end);
} else from >> result;
return result;
}
std::string maybe_quote_string(std::string which) {
if(which.empty()) return "''";
- if(which.find_first_of(' ') != std::string::npos || which[0] == '"' || which[0] == '\'') {
+ if(which.find_first_of(" \t\n\f") != std::string::npos || which[0] == '"' || which[0] == '\'') {
// The string contains spaces or starts with a quote, so quote it.
// We may have to escape quotes or backslashes.
- int apos = 0, quot = 0, bslash = 0;
- std::for_each(which.begin(), which.end(), [&apos,",&bslash](char c) {
+ int apos = 0, quot = 0, bslash = 0, newline = 0, formfeed = 0;
+ std::for_each(which.begin(), which.end(), [&apos,",&bslash,&newline,&formfeed](char c) {
if(c == '\'') apos++;
if(c == '"') quot++;
if(c == '\\') bslash++;
+ if(c == '\n') newline++;
+ if(c == '\f') formfeed++;
});
char quote_c;
// Surround it in whichever quote character appears fewer times.
@@ -166,15 +178,20 @@ std::string maybe_quote_string(std::string which) {
else quote_c = '\'';
// Let's create this string to initially have the required size.
std::string temp;
- size_t quoted_len = which.length() + std::min(quot,apos) + bslash + 2;
+ size_t quoted_len = which.length() + std::min(quot,apos) + bslash + newline + formfeed + 2;
temp.reserve(quoted_len);
temp += quote_c;
for(size_t i = 0; i < which.length(); i++) {
if(which[i] == quote_c) {
temp += '\\';
temp += quote_c;
- } else if(which[i] == '\\')
+ } else if(which[i] == '\\') {
temp += R"(\\)";
+ } else if(which[i] == '\n') {
+ temp += R"(\n)";
+ } else if(which[i] == '\f') {
+ temp += R"(\f)";
+ }
else temp += which[i];
}
temp += quote_c;
diff --git a/src/fileio/fileio.hpp b/src/fileio/fileio.hpp
index 766b235d9..1e587a143 100644
--- a/src/fileio/fileio.hpp
+++ b/src/fileio/fileio.hpp
@@ -40,6 +40,11 @@ struct array_value_type {
using type = T;
};
+template
+struct array_value_type, D1>> {
+ using type = T;
+};
+
template
void writeArray(std::ostream& to, const T& array, int width, int height) {
using int_type = decltype(typename array_value_type::type() + 1);
diff --git a/src/fileio/fileio_scen.cpp b/src/fileio/fileio_scen.cpp
index 99fe6f173..b7ce37dfb 100644
--- a/src/fileio/fileio_scen.cpp
+++ b/src/fileio/fileio_scen.cpp
@@ -9,6 +9,7 @@
#include "fileio.hpp"
#include
+#include
#include
#include
@@ -317,7 +318,7 @@ bool load_scenario_v1(fs::path file_to_load, cScenario& scenario, bool only_head
if(info.type == eShopItemType::ITEM) {
int end = info.first + info.count;
end = min(end, scenario.scen_items.size());
- shop.addItems(info.first, scenario.scen_items.begin() + info.first, scenario.scen_items.begin() + end, cShop::INFINITE);
+ shop.addItems(info.first, scenario.scen_items.begin() + info.first, scenario.scen_items.begin() + end, cShop::INFINITE_AMOUNT);
} else {
int max = 62;
if(info.type == eShopItemType::ALCHEMY)
@@ -476,14 +477,14 @@ static void readQuestFromXml(ticpp::Element& data, cQuest& quest) {
std::string type, name, val, fname;
data.GetDocument()->GetValue(&fname);
data.GetValue(&type);
- quest.flags = 0;
+ quest.deadline_is_relative = quest.auto_start = false;
Iterator attr;
for(attr = attr.begin(&data); attr != attr.end(); attr++) {
attr->GetName(&name);
if(name == "start-with") {
attr->GetValue(&val);
if(val == "true")
- quest.flags += 10;
+ quest.auto_start = true;
} else throw xBadAttr(type, name, attr->Row(), attr->Column(), fname);
}
std::set reqs = {"name", "description"};
@@ -498,7 +499,7 @@ static void readQuestFromXml(ticpp::Element& data, cQuest& quest) {
if(name == "relative") {
attr->GetValue(&val);
if(val == "true")
- quest.flags += 1;
+ quest.deadline_is_relative = true;
} else if(name == "waive-if")
attr->GetValue(&quest.event);
else throw xBadAttr(type, name, attr->Row(), attr->Column(), fname);
@@ -698,6 +699,7 @@ void readScenarioFromXml(ticpp::Document&& data, cScenario& scenario) {
"language", "author", "text", "ratings",
"flags", "creator", "game", "editor"
};
+ TiXmlBase::SetCondenseWhiteSpace(true);
for(elem = elem.begin(data.FirstChildElement()); elem != elem.end(); elem++) {
elem->GetValue(&type);
reqs.erase(type);
@@ -1939,6 +1941,7 @@ void loadOutMapData(map_data&& data, location which, cScenario& scen) {
break;
case eMapFeature::BOAT:
is_boat = true;
+ BOOST_FALLTHROUGH;
case eMapFeature::HORSE:
(is_boat ? scen.boats : scen.horses).resize(abs(feat.second));
what = &(is_boat ? scen.boats : scen.horses)[abs(feat.second) - 1];
@@ -1988,6 +1991,7 @@ void loadTownMapData(map_data&& data, int which, cScenario& scen) {
break;
case eMapFeature::BOAT:
is_boat = true;
+ BOOST_FALLTHROUGH;
case eMapFeature::HORSE:
(is_boat ? scen.boats : scen.horses).resize(abs(feat.second));
what = &(is_boat ? scen.boats : scen.horses)[abs(feat.second) - 1];
diff --git a/src/fileio/resmgr/resmgr.hpp b/src/fileio/resmgr/resmgr.hpp
index 69f10898b..4bb88f5e2 100644
--- a/src/fileio/resmgr/resmgr.hpp
+++ b/src/fileio/resmgr/resmgr.hpp
@@ -15,6 +15,7 @@
#include
#include
#include
+#include
namespace ResMgr {
namespace fs = boost::filesystem;
diff --git a/src/fileio/xml-parser/.gitattributes b/src/fileio/xml-parser/.gitattributes
new file mode 100644
index 000000000..8e948c534
--- /dev/null
+++ b/src/fileio/xml-parser/.gitattributes
@@ -0,0 +1 @@
+* text=auto !eol
diff --git a/src/fileio/xml-parser/.gitignore b/src/fileio/xml-parser/.gitignore
new file mode 100644
index 000000000..1df20ed23
--- /dev/null
+++ b/src/fileio/xml-parser/.gitignore
@@ -0,0 +1,2 @@
+/*build*
+*.user
diff --git a/src/fileio/xml-parser/CMakeLists.txt b/src/fileio/xml-parser/CMakeLists.txt
new file mode 100644
index 000000000..ccded1e29
--- /dev/null
+++ b/src/fileio/xml-parser/CMakeLists.txt
@@ -0,0 +1,99 @@
+cmake_minimum_required(VERSION 3.21)
+
+project(ticpp VERSION 2.5.3 LANGUAGES CXX)
+
+get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(PROJECT_IS_TOP_LEVEL)
+ set(buildTypes "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
+ set(defaultBuildType "Debug")
+ if(NOT isMultiConfig)
+ if(NOT CMAKE_BUILD_TYPE)
+ message(STATUS "Setting build type to '${defaultBuildType}' as none was specified.")
+ set(CMAKE_BUILD_TYPE "${defaultBuildType}" CACHE STRING "Choose the type of build." FORCE)
+ set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "${buildTypes}")
+ elseif(NOT CMAKE_BUILD_TYPE IN_LIST buildTypes)
+ message(FATAL_ERROR "Unknown build type: '${CMAKE_BUILD_TYPE}'")
+ endif()
+ endif()
+ unset(defaultBuildType)
+ unset(buildTypes)
+
+ # TODO: This is not the ideal solution to apply these warning flags.
+ # Toolchain files are not really intended for this purpose.
+ # Presets would be a viable solution, but currently, at least on VSCode, this
+ # has the side effect that pretty much everything from generator to build type
+ # to binary directory needs to be specified. The usual control ability of especially
+ # the build type gets lost in preset mode.
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+ string(APPEND CMAKE_CXX_FLAGS " /W4")
+ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ # This assumes the default Clang frontend and not the MSVC compatible one
+ string(APPEND CMAKE_CXX_FLAGS " -Wall -Wextra -Wpedantic")
+ else()
+ # This assumes GCC
+ string(APPEND CMAKE_CXX_FLAGS " -Wall -Wextra -Wpedantic")
+ endif()
+endif()
+
+if(NOT DEFINED CMAKE_CXX_STANDARD)
+ set(CMAKE_CXX_STANDARD 17)
+elseif(CMAKE_CXX_STANDARD LESS 17 OR CMAKE_CXX_STANDARD GREATER_EQUAL 98)
+ message(FATAL_ERROR "The CMAKE_CXX_STANDARD value needs to be at least 17, current value: ${CMAKE_CXX_STANDARD}")
+endif()
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+if (NOT DEFINED CMAKE_CXX_EXTENSIONS)
+ set(CMAKE_CXX_EXTENSIONS OFF)
+endif()
+
+if(MSVC)
+ # Disable warnings about standard conformant code that is not conform to Microsoft standards
+ add_compile_definitions(_CRT_SECURE_NO_WARNINGS _SCL_SECURE_NO_WARNINGS)
+ # Without BOM the UTF-8 encoding doesn't get detected so enforce it
+ add_compile_options(/source-charset:utf-8)
+endif()
+
+add_library(ticpp_ticpp)
+add_library(ticpp::ticpp ALIAS ticpp_ticpp)
+set_target_properties(ticpp_ticpp PROPERTIES
+ OUTPUT_NAME ticpp
+)
+
+target_sources(ticpp_ticpp
+ PRIVATE
+ ticpp.cpp
+ ticpp.h
+ ticppapi.h
+ ticpprc.h
+ tinystr.cpp
+ tinystr.h
+ tinyxml.cpp
+ tinyxml.h
+ tinyxmlparser.cpp
+ tinyxmlerror.cpp
+)
+
+target_compile_definitions(ticpp_ticpp
+ PUBLIC
+ TIXML_USE_TICPP
+ $<$:BUILD_TICPP_DLL>
+)
+target_include_directories(ticpp_ticpp
+ INTERFACE
+ "$"
+)
+
+if(PROJECT_IS_TOP_LEVEL)
+ set(excludeFromAllTag "")
+else()
+ set(excludeFromAllTag EXCLUDE_FROM_ALL)
+endif()
+install(TARGETS ticpp_ticpp
+ RUNTIME
+ DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ${excludeFromAllTag}
+)
+unset(excludeFromAllTag)
diff --git a/src/fileio/xml-parser/LICENSE b/src/fileio/xml-parser/LICENSE
new file mode 100644
index 000000000..2888fbe93
--- /dev/null
+++ b/src/fileio/xml-parser/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2006 Ryan Pusztai, Ryan Mulder
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/fileio/xml-parser/README.md b/src/fileio/xml-parser/README.md
new file mode 100644
index 000000000..8d204606b
--- /dev/null
+++ b/src/fileio/xml-parser/README.md
@@ -0,0 +1,11 @@
+# TiCPP
+
+**TiCPP** is short for the official name TinyXML++. It is a completely new interface to [TinyXML](http://www.grinninglizard.com/tinyxml/) that uses MANY of the C++ strengths.
+Templates, exceptions, and much better error handling. It is also fully documented in Doxygen. It is really cool because this version lets you interface tiny
+the exact same way as before or you can choose to use the new `ticpp` classes. All you need to do is define `TIXML_USE_TICPP`.
+It has been tested in VC 6.0, VC 7.0, VC 7.1, VC 8.0, MinGW gcc 3.4.5, and in Linux GNU gcc 3+.
+
+Documentation:
+
+* [Online](http://rawgit.com/wxFormBuilder/ticpp/docs/ticpp.html)
+* [Download](http://rawgit.com/wxFormBuilder/ticpp/docs/TinyXMLHelp_v2.5.3.chm)
diff --git a/src/fileio/xml-parser/build_instructions.txt b/src/fileio/xml-parser/build_instructions.txt
index dd48de0f5..7cc5c40c9 100644
--- a/src/fileio/xml-parser/build_instructions.txt
+++ b/src/fileio/xml-parser/build_instructions.txt
@@ -22,7 +22,7 @@ Introduction:
Build Steps:
1) Download Premake from http://premake.sf.net/download
2) Checkout the source for TinyXML++ using Subversion.
- - svn checkout https://ticpp.googlecode.com/svn/trunk/ ticpp
+ - svn checkout https://github.com/rjpcomputing/ticpp ticpp
3) Place the Premake executable in the root directory of TiCPP or somewhere in your
path.
4) To create the needed build files navigate to the TinyXML++ directory (ticpp)
@@ -53,7 +53,8 @@ Build Steps:
with gcc or MinGW)
* Release:
- make CONFIG=Release
+ make CONFIG=Release (if generated with premake)
+ make config=release (if generated with premake4)
* Debug:
make
diff --git a/src/fileio/xml-parser/changes.txt b/src/fileio/xml-parser/changes.txt
index 1ecc03ac1..4075fd620 100644
--- a/src/fileio/xml-parser/changes.txt
+++ b/src/fileio/xml-parser/changes.txt
@@ -267,5 +267,3 @@ Changes in version 2.1.5
Comments should not, in fact, parse entities. Fixed the code path and added tests.
- We were not catching all the returns from ftell. Thanks to Bernard for catching that.
-2.5.4
-- Added dll-interface declarations to support using DLLs built via VS200X.
diff --git a/src/fileio/xml-parser/premake.lua b/src/fileio/xml-parser/premake.lua
new file mode 100644
index 000000000..7f8835055
--- /dev/null
+++ b/src/fileio/xml-parser/premake.lua
@@ -0,0 +1,36 @@
+--*****************************************************************************
+--* Author: RJP Computing
+--* Copyright (C) 2007 RJP Computing
+--*
+--* Permission is hereby granted, free of charge, to any person obtaining a copy of
+--* this software and associated documentation files (the "Software"), to deal in
+--* the Software without restriction, including without limitation the rights to
+--* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+--* the Software, and to permit persons to whom the Software is furnished to do so,
+--* subject to the following conditions:
+--*
+--* The above copyright notice and this permission notice shall be included in all
+--* copies or substantial portions of the Software.
+--*
+--* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+--* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+--* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+--* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+--* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+--* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+--*
+--* NOTES:
+--* - use the '/' slash for all paths.
+--*****************************************************************************
+project.name = "TinyXML++"
+
+project.bindir = "lib"
+project.libdir = "lib"
+
+-- This is for including other Premake scripts.
+dopackage( "ticpp.lua" )
+
+-- Add options here.
+addoption( "dynamic-runtime", "Use the dynamicly loadable version of the runtime." )
+addoption( "unicode", "Use the Unicode character set" )
+
diff --git a/src/fileio/xml-parser/premake4.lua b/src/fileio/xml-parser/premake4.lua
new file mode 100644
index 000000000..212b12d16
--- /dev/null
+++ b/src/fileio/xml-parser/premake4.lua
@@ -0,0 +1,46 @@
+--*****************************************************************************
+--* Author: RJP Computing
+--* Copyright (C) 2009 RJP Computing
+--*
+--* Permission is hereby granted, free of charge, to any person obtaining a copy of
+--* this software and associated documentation files (the "Software"), to deal in
+--* the Software without restriction, including without limitation the rights to
+--* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+--* the Software, and to permit persons to whom the Software is furnished to do so,
+--* subject to the following conditions:
+--*
+--* The above copyright notice and this permission notice shall be included in all
+--* copies or substantial portions of the Software.
+--*
+--* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+--* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+--* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+--* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+--* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+--* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+--*
+--* NOTES:
+--* - use the '/' slash for all paths.
+--*****************************************************************************
+solution "TinyXML++"
+ targetdir "lib"
+ implibdir "lib"
+ configurations { "Debug", "Release" }
+ buildoptions { "-std=c++14" }
+
+-- This is for including other Premake scripts.
+dofile( "ticpp4.lua" )
+
+-- Add options here.
+newoption
+{
+ trigger = "dynamic-runtime",
+ description = "Use the dynamicly loadable version of the runtime."
+}
+
+newoption
+{
+ trigger = "unicode",
+ description = "Use the Unicode character set"
+}
+
diff --git a/src/fileio/xml-parser/readme.txt b/src/fileio/xml-parser/readme.txt
deleted file mode 100644
index aad3648b5..000000000
--- a/src/fileio/xml-parser/readme.txt
+++ /dev/null
@@ -1,531 +0,0 @@
-/** @mainpage
-
-
TinyXML
-
-TinyXML is a simple, small, C++ XML parser that can be easily
-integrated into other programs.
-
-
What it does.
-
-In brief, TinyXML parses an XML document, and builds from that a
-Document Object Model (DOM) that can be read, modified, and saved.
-
-XML stands for "eXtensible Markup Language." It allows you to create
-your own document markups. Where HTML does a very good job of marking
-documents for browsers, XML allows you to define any kind of document
-markup, for example a document that describes a "to do" list for an
-organizer application. XML is a very structured and convenient format.
-All those random file formats created to store application data can
-all be replaced with XML. One parser for everything.
-
-The best place for the complete, correct, and quite frankly hard to
-read spec is at
-http://www.w3.org/TR/2004/REC-xml-20040204/. An intro to XML
-(that I really like) can be found at
-http://skew.org/xml/tutorial.
-
-There are different ways to access and interact with XML data.
-TinyXML uses a Document Object Model (DOM), meaning the XML data is parsed
-into a C++ objects that can be browsed and manipulated, and then
-written to disk or another output stream. You can also construct an XML document
-from scratch with C++ objects and write this to disk or another output
-stream.
-
-TinyXML is designed to be easy and fast to learn. It is two headers
-and four cpp files. Simply add these to your project and off you go.
-There is an example file - xmltest.cpp - to get you started.
-
-TinyXML is released under the ZLib license,
-so you can use it in open source or commercial code. The details
-of the license are at the top of every source file.
-
-TinyXML attempts to be a flexible parser, but with truly correct and
-compliant XML output. TinyXML should compile on any reasonably C++
-compliant system. It does not rely on exceptions or RTTI. It can be
-compiled with or without STL support. TinyXML fully supports
-the UTF-8 encoding, and the first 64k character entities.
-
-
-
What it doesn't do.
-
-TinyXML doesn't parse or use DTDs (Document Type Definitions) or XSLs
-(eXtensible Stylesheet Language.) There are other parsers out there
-(check out www.sourceforge.org, search for XML) that are much more fully
-featured. But they are also much bigger, take longer to set up in
-your project, have a higher learning curve, and often have a more
-restrictive license. If you are working with browsers or have more
-complete XML needs, TinyXML is not the parser for you.
-
-The following DTD syntax will not parse at this time in TinyXML:
-
-@verbatim
-
- ]>
-@endverbatim
-
-because TinyXML sees this as a !DOCTYPE node with an illegally
-embedded !ELEMENT node. This may be addressed in the future.
-
-
Tutorials.
-
-For the impatient, here are some tutorials to get you going. A great way to get started,
-but it is worth your time to read this (very short) manual completely.
-
-- @subpage ticppTutorial
-- @subpage tutorial0
-
-
Code Status.
-
-TinyXML is mature, tested code. It is very stable. If you find
-bugs, please file a bug report on the sourceforge web site
-(www.sourceforge.net/projects/tinyxml). We'll get them straightened
-out as soon as possible.
-
-There are some areas of improvement; please check sourceforge if you are
-interested in working on TinyXML.
-
-
Related Projects
-
-TinyXML projects you may find useful! (Descriptions provided by the projects.)
-
-
-
TinyXPath (http://tinyxpath.sourceforge.net). TinyXPath is a small footprint
- XPath syntax decoder, written in C++.
-
@subpage ticpp (http://code.google.com/p/ticpp/). TinyXML++ is a completely new
- interface to TinyXML that uses MANY of the C++ strengths. Templates,
- exceptions, and much better error handling.
-
-
-
Features
-
-
Using STL
-
-TinyXML can be compiled to use or not use STL. When using STL, TinyXML
-uses the std::string class, and fully supports std::istream, std::ostream,
-operator<<, and operator>>. Many API methods have both 'const char*' and
-'const std::string&' forms.
-
-When STL support is compiled out, no STL files are included whatsoever. All
-the string classes are implemented by TinyXML itself. API methods
-all use the 'const char*' form for input.
-
-Use the compile time #define:
-
- TIXML_USE_STL
-
-to compile one version or the other. This can be passed by the compiler,
-or set as the first line of "tinyxml.h".
-
-Note: If compiling the test code in Linux, setting the environment
-variable TINYXML_USE_STL=YES/NO will control STL compilation. In the
-Windows project file, STL and non STL targets are provided. In your project,
-It's probably easiest to add the line "#define TIXML_USE_STL" as the first
-line of tinyxml.h.
-
-
UTF-8
-
-TinyXML supports UTF-8 allowing to manipulate XML files in any language. TinyXML
-also supports "legacy mode" - the encoding used before UTF-8 support and
-probably best described as "extended ascii".
-
-Normally, TinyXML will try to detect the correct encoding and use it. However,
-by setting the value of TIXML_DEFAULT_ENCODING in the header file, TinyXML
-can be forced to always use one encoding.
-
-TinyXML will assume Legacy Mode until one of the following occurs:
-
-
If the non-standard but common "UTF-8 lead bytes" (0xef 0xbb 0xbf)
- begin the file or data stream, TinyXML will read it as UTF-8.
-
If the declaration tag is read, and it has an encoding="UTF-8", then
- TinyXML will read it as UTF-8.
-
If the declaration tag is read, and it has no encoding specified, then TinyXML will
- read it as UTF-8.
-
If the declaration tag is read, and it has an encoding="something else", then TinyXML
- will read it as Legacy Mode. In legacy mode, TinyXML will work as it did before. It's
- not clear what that mode does exactly, but old content should keep working.
-
Until one of the above criteria is met, TinyXML runs in Legacy Mode.
-
-
-What happens if the encoding is incorrectly set or detected? TinyXML will try
-to read and pass through text seen as improperly encoded. You may get some strange results or
-mangled characters. You may want to force TinyXML to the correct mode.
-
-You may force TinyXML to Legacy Mode by using LoadFile( TIXML_ENCODING_LEGACY ) or
-LoadFile( filename, TIXML_ENCODING_LEGACY ). You may force it to use legacy mode all
-the time by setting TIXML_DEFAULT_ENCODING = TIXML_ENCODING_LEGACY. Likewise, you may
-force it to TIXML_ENCODING_UTF8 with the same technique.
-
-For English users, using English XML, UTF-8 is the same as low-ASCII. You
-don't need to be aware of UTF-8 or change your code in any way. You can think
-of UTF-8 as a "superset" of ASCII.
-
-UTF-8 is not a double byte format - but it is a standard encoding of Unicode!
-TinyXML does not use or directly support wchar, TCHAR, or Microsoft's _UNICODE at this time.
-It is common to see the term "Unicode" improperly refer to UTF-16, a wide byte encoding
-of unicode. This is a source of confusion.
-
-For "high-ascii" languages - everything not English, pretty much - TinyXML can
-handle all languages, at the same time, as long as the XML is encoded
-in UTF-8. That can be a little tricky, older programs and operating systems
-tend to use the "default" or "traditional" code page. Many apps (and almost all
-modern ones) can output UTF-8, but older or stubborn (or just broken) ones
-still output text in the default code page.
-
-For example, Japanese systems traditionally use SHIFT-JIS encoding.
-Text encoded as SHIFT-JIS can not be read by TinyXML.
-A good text editor can import SHIFT-JIS and then save as UTF-8.
-
-The Skew.org link does a great
-job covering the encoding issue.
-
-The test file "utf8test.xml" is an XML containing English, Spanish, Russian,
-and Simplified Chinese. (Hopefully they are translated correctly). The file
-"utf8test.gif" is a screen capture of the XML file, rendered in IE. Note that
-if you don't have the correct fonts (Simplified Chinese or Russian) on your
-system, you won't see output that matches the GIF file even if you can parse
-it correctly. Also note that (at least on my Windows machine) console output
-is in a Western code page, so that Print() or printf() cannot correctly display
-the file. This is not a bug in TinyXML - just an OS issue. No data is lost or
-destroyed by TinyXML. The console just doesn't render UTF-8.
-
-
-
Entities
-TinyXML recognizes the pre-defined "character entities", meaning special
-characters. Namely:
-
-@verbatim
- & &
- < <
- > >
- " "
- ' '
-@endverbatim
-
-These are recognized when the XML document is read, and translated to there
-UTF-8 equivalents. For instance, text with the XML of:
-
-@verbatim
- Far & Away
-@endverbatim
-
-will have the Value() of "Far & Away" when queried from the TiXmlText object,
-and will be written back to the XML stream/file as an ampersand. Older versions
-of TinyXML "preserved" character entities, but the newer versions will translate
-them into characters.
-
-Additionally, any character can be specified by its Unicode code point:
-The syntax " " or " " are both to the non-breaking space characher.
-
-
Printing
-TinyXML can print output in several different ways that all have strengths and limitations.
-
-- Print( FILE* ). Output to a std-C stream, which includes all C files as well as stdout.
- - "Pretty prints", but you don't have control over printing options.
- - The output is streamed directly to the FILE object, so there is no memory overhead
- in the TinyXML code.
- - used by Print() and SaveFile()
-
-- operator<<. Output to a c++ stream.
- - Integrates with standart C++ iostreams.
- - Outputs in "network printing" mode without line breaks. Good for network transmission
- and moving XML between C++ objects, but hard for a human to read.
-
-- TiXmlPrinter. Output to a std::string or memory buffer.
- - API is less concise
- - Future printing options will be put here.
- - Printing may change slightly in future versions as it is refined and expanded.
-
-
Streams
-With TIXML_USE_STL on TinyXML supports C++ streams (operator <<,>>) streams as well
-as C (FILE*) streams. There are some differences that you may need to be aware of.
-
-C style output:
- - based on FILE*
- - the Print() and SaveFile() methods
-
- Generates formatted output, with plenty of white space, intended to be as
- human-readable as possible. They are very fast, and tolerant of ill formed
- XML documents. For example, an XML document that contains 2 root elements
- and 2 declarations, will still print.
-
-C style input:
- - based on FILE*
- - the Parse() and LoadFile() methods
-
- A fast, tolerant read. Use whenever you don't need the C++ streams.
-
-C++ style output:
- - based on std::ostream
- - operator<<
-
- Generates condensed output, intended for network transmission rather than
- readability. Depending on your system's implementation of the ostream class,
- these may be somewhat slower. (Or may not.) Not tolerant of ill formed XML:
- a document should contain the correct one root element. Additional root level
- elements will not be streamed out.
-
-C++ style input:
- - based on std::istream
- - operator>>
-
- Reads XML from a stream, making it useful for network transmission. The tricky
- part is knowing when the XML document is complete, since there will almost
- certainly be other data in the stream. TinyXML will assume the XML data is
- complete after it reads the root element. Put another way, documents that
- are ill-constructed with more than one root element will not read correctly.
- Also note that operator>> is somewhat slower than Parse, due to both
- implementation of the STL and limitations of TinyXML.
-
-
White space
-The world simply does not agree on whether white space should be kept, or condensed.
-For example, pretend the '_' is a space, and look at "Hello____world". HTML, and
-at least some XML parsers, will interpret this as "Hello_world". They condense white
-space. Some XML parsers do not, and will leave it as "Hello____world". (Remember
-to keep pretending the _ is a space.) Others suggest that __Hello___world__ should become
-Hello___world.
-
-It's an issue that hasn't been resolved to my satisfaction. TinyXML supports the
-first 2 approaches. Call TiXmlBase::SetCondenseWhiteSpace( bool ) to set the desired behavior.
-The default is to condense white space.
-
-If you change the default, you should call TiXmlBase::SetCondenseWhiteSpace( bool )
-before making any calls to Parse XML data, and I don't recommend changing it after
-it has been set.
-
-
-
Handles
-
-Where browsing an XML document in a robust way, it is important to check
-for null returns from method calls. An error safe implementation can
-generate a lot of code like:
-
-@verbatim
-TiXmlElement* root = document.FirstChildElement( "Document" );
-if ( root )
-{
- TiXmlElement* element = root->FirstChildElement( "Element" );
- if ( element )
- {
- TiXmlElement* child = element->FirstChildElement( "Child" );
- if ( child )
- {
- TiXmlElement* child2 = child->NextSiblingElement( "Child" );
- if ( child2 )
- {
- // Finally do something useful.
-@endverbatim
-
-Handles have been introduced to clean this up. Using the TiXmlHandle class,
-the previous code reduces to:
-
-@verbatim
-TiXmlHandle docHandle( &document );
-TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement();
-if ( child2 )
-{
- // do something useful
-@endverbatim
-
-Which is much easier to deal with. See TiXmlHandle for more information.
-
-
-
Row and Column tracking
-Being able to track nodes and attributes back to their origin location
-in source files can be very important for some applications. Additionally,
-knowing where parsing errors occured in the original source can be very
-time saving.
-
-TinyXML can tracks the row and column origin of all nodes and attributes
-in a text file. The TiXmlBase::Row() and TiXmlBase::Column() methods return
-the origin of the node in the source text. The correct tabs can be
-configured in TiXmlDocument::SetTabSize().
-
-
-
Using and Installing
-
-To Compile and Run xmltest:
-
-A Linux Makefile and a Windows Visual C++ .dsw file is provided.
-Simply compile and run. It will write the file demotest.xml to your
-disk and generate output on the screen. It also tests walking the
-DOM by printing out the number of nodes found using different
-techniques.
-
-The Linux makefile is very generic and runs on many systems - it
-is currently tested on mingw and
-MacOSX. You do not need to run 'make depend'. The dependecies have been
-hard coded.
-
-
Windows project file for VC6
-
-
tinyxml: tinyxml library, non-STL
-
tinyxmlSTL: tinyxml library, STL
-
tinyXmlTest: test app, non-STL
-
tinyXmlTestSTL: test app, STL
-
-
-
Makefile
-At the top of the makefile you can set:
-
-PROFILE, DEBUG, and TINYXML_USE_STL. Details (such that they are) are in
-the makefile.
-
-In the tinyxml directory, type "make clean" then "make". The executable
-file 'xmltest' will be created.
-
-
-
-
To Use in an Application:
-
-Add tinyxml.cpp, tinyxml.h, tinyxmlerror.cpp, tinyxmlparser.cpp, tinystr.cpp, and tinystr.h to your
-project or make file. That's it! It should compile on any reasonably
-compliant C++ system. You do not need to enable exceptions or
-RTTI for TinyXML.
-
-
-
How TinyXML works.
-
-An example is probably the best way to go. Take:
-@verbatim
-
-
-
- Go to the Toy store!
- Do bills
-
-@endverbatim
-
-Its not much of a To Do list, but it will do. To read this file
-(say "demo.xml") you would create a document, and parse it in:
-@verbatim
- TiXmlDocument doc( "demo.xml" );
- doc.LoadFile();
-@endverbatim
-
-And its ready to go. Now lets look at some lines and how they
-relate to the DOM.
-
-@verbatim
-
-@endverbatim
-
- The first line is a declaration, and gets turned into the
- TiXmlDeclaration class. It will be the first child of the
- document node.
-
- This is the only directive/special tag parsed by by TinyXML.
- Generally directive tags are stored in TiXmlUnknown so the
- commands wont be lost when it is saved back to disk.
-
-@verbatim
-
-@endverbatim
-
- A comment. Will become a TiXmlComment object.
-
-@verbatim
-
-@endverbatim
-
- The "ToDo" tag defines a TiXmlElement object. This one does not have
- any attributes, but does contain 2 other elements.
-
-@verbatim
-
-@endverbatim
-
- Creates another TiXmlElement which is a child of the "ToDo" element.
- This element has 1 attribute, with the name "priority" and the value
- "1".
-
-@verbatim
-Go to the
-@endverbatim
-
- A TiXmlText. This is a leaf node and cannot contain other nodes.
- It is a child of the "Item" TiXmlElement.
-
-@verbatim
-
-@endverbatim
-
-
- Another TiXmlElement, this one a child of the "Item" element.
-
-Etc.
-
-Looking at the entire object tree, you end up with:
-@verbatim
-TiXmlDocument "demo.xml"
- TiXmlDeclaration "version='1.0'" "standalone=no"
- TiXmlComment " Our to do list data"
- TiXmlElement "ToDo"
- TiXmlElement "Item" Attribtutes: priority = 1
- TiXmlText "Go to the "
- TiXmlElement "bold"
- TiXmlText "Toy store!"
- TiXmlElement "Item" Attributes: priority=2
- TiXmlText "Do bills"
-@endverbatim
-
-
Documentation
-
-The documentation is build with Doxygen, using the 'dox'
-configuration file.
-
-
License
-
-TinyXML is released under the zlib license:
-
-This software is provided 'as-is', without any express or implied
-warranty. In no event will the authors be held liable for any
-damages arising from the use of this software.
-
-Permission is granted to anyone to use this software for any
-purpose, including commercial applications, and to alter it and
-redistribute it freely, subject to the following restrictions:
-
-1. The origin of this software must not be misrepresented; you must
-not claim that you wrote the original software. If you use this
-software in a product, an acknowledgment in the product documentation
-would be appreciated but is not required.
-
-2. Altered source versions must be plainly marked as such, and
-must not be misrepresented as being the original software.
-
-3. This notice may not be removed or altered from any source
-distribution.
-
-
References
-
-The World Wide Web Consortium is the definitive standard body for
-XML, and there web pages contain huge amounts of information.
-
-The definitive spec:
-http://www.w3.org/TR/2004/REC-xml-20040204/
-
-I also recommend "XML Pocket Reference" by Robert Eckstein and published by
-OReilly...the book that got the whole thing started.
-
-